Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions src/PRo3D.ImageMapping/App.fs
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,17 @@ module App =
| SetPitch r -> { m with boresightAdjustment = { m.boresightAdjustment with pitch = Numeric.update m.boresightAdjustment.pitch r } }
| SetYaw r -> { m with boresightAdjustment = { m.boresightAdjustment with yaw = Numeric.update m.boresightAdjustment.yaw r } }
| LoadImagesDir directory ->
let imageExts = [".tif";".tiff";".jpg";".exr"]
let mbiExt = ".mbi.json"
let images' =
Directory.EnumerateFiles(directory)
|> Seq.filter (fun p ->
let e = Path.GetExtension p
List.contains e imageExts
p.EndsWith(mbiExt)
)
|> Seq.map (fun path ->
Image.loadFile(path)
) |> IndexList.ofSeq
Image.mbiFileToImageObjs(path)
)
|> Seq.collect id
|> IndexList.ofSeq
let firstIndex =
if IndexList.isEmpty images' then
None
Expand Down
79 changes: 38 additions & 41 deletions src/PRo3D.ImageMapping/Image.fs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ open PRo3D.InstrumentVisualization
open PRo3D.Core
open PRo3D.SPICE

open PRo3D.Core.InstrumentMetadata


module Shaders =
open FShade
Expand Down Expand Up @@ -99,13 +101,11 @@ module Image =
texture = initialPath;
distance = 0;
time = new DateTime();
instrument = "";
mbi = "";
}

let loadFile (texturePath : string) =
// this could be a fallback
let ifUsefulThisIsHowToExtractInfos = MultiBandReader.tryGetChannels texturePath

let (tiffMbiJson, tiffJson) = InstrumentMetadata.tryParseMetadataForImagePath texturePath
let loadFile (texturePath, ((tiffMbiJson : Option<Tiff_Mbi_Json.Mbi>), (tiffJson : Option<Tiff_Json.ImageMetadata>)), mbiPath : string) =

let channels =
match tiffJson with
Expand Down Expand Up @@ -156,6 +156,11 @@ module Image =
| Some mbi -> mbi.obs_date
| None -> System.DateTime.MinValue // which default time?

let instrument =
match tiffMbiJson with
| Some mbi -> mbi.instrument
| None -> ""

{ initial with
texture = Path.GetFullPath(texturePath);
defaultMinValues = defaultMinValues;
Expand All @@ -167,8 +172,21 @@ module Image =
dataType = dataType;
distance = distance;
time = time;
instrument = instrument;
mbi = mbiPath;
}


let mbiFileToImageObjs (mbiPath : string) =
// this could be a fallback
//let ifUsefulThisIsHowToExtractInfos = MultiBandReader.tryGetChannels mbiPath
let parsed_files = InstrumentMetadata.parseDataForMbiPath mbiPath
parsed_files
|> Array.map (fun (texturePath, (tiffMbiJson, tiffJson)) ->
loadFile (texturePath, (tiffMbiJson, tiffJson), mbiPath)
)


let update (m : Image) (msg : ImageMessage) =
match msg with
| SetDataTypeAndRange (dataType, min, max) ->
Expand Down Expand Up @@ -338,15 +356,6 @@ module Image =
let referenceFrame = cval "ECLIPJ2000"
let referenceFrame = cval "IAU_MARS"

let currentProjectedImage =
m.texture
|> AVal.map (fun path ->
if File.Exists path then
Some (path, InstrumentMetadata.tryParseMetadataForImagePath path)
else
None
)

let imageSettings =
{
VisualizationProperties.empty with
Expand All @@ -365,40 +374,28 @@ module Image =
time = DateTime.Now
boresightAdjustment = None
}
(currentProjectedImage, boresightAdjustment) ||> AVal.map2 (fun currentProjectedImage boresight ->
match currentProjectedImage with
| Some (f, (Some mbi,_)) ->
let p =
{ p with
time = mbi.obs_date
instrumentName =
match InstrumentProjection.instrument2SpiceName mbi.instrument with
| None -> failwith "no spice name for the given instrument."
| Some i -> i
instrumentReferenceFrame = "J2000"
boresightAdjustment = boresight
}
p, mbi.obs_date
| _ ->
let defaultTime = "2025-03-12 11:50:30.000Z"
p, DateTime.Parse(defaultTime)
boresightAdjustment |> AVal.map (fun boresight ->
let p =
{ p with
time = m.time |> AVal.force
instrumentName =
match InstrumentProjection.instrument2SpiceName (m.instrument |> AVal.force) with
| None -> failwith "no spice name for the given instrument."
| Some i -> i
instrumentReferenceFrame = "J2000"
boresightAdjustment = boresight
}
p, p.time
)

let projection = projectionSetup |> AVal.map fst
let time = projectionSetup |> AVal.map snd

let projectImage = Visualization.creatProjectionFunction observer time referenceFrame currentProjectedImage projection
let projectedTexture = Visualization.createProjectedTexture currentProjectedImage m.selectedChannel

let projectionEnabled =
currentProjectedImage
|> AVal.map (function
| Some (_, (Some _, _)) -> true
| _ -> false
)
let projectImage = Visualization.creatProjectionFunction observer time referenceFrame projection
let projectedTexture = Visualization.createProjectedTexture (m.texture |> AVal.force) m.selectedChannel

let scene =
Visualization.createSceneGraph imageSettings referenceFrame supportBody observer time projectImage projectedTexture projectionEnabled
Visualization.createSceneGraph imageSettings referenceFrame supportBody observer time projectImage projectedTexture (AVal.constant true)
|> Sg.noEvents

scene
Expand Down
2 changes: 2 additions & 0 deletions src/PRo3D.ImageMapping/Model.fs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ type Image =
texture : string
distance: float
time: System.DateTime
instrument: string
mbi : string
}

[<ModelType>]
Expand Down
129 changes: 64 additions & 65 deletions src/PRo3D.InstrumentData/InstrumentMetadata.fs
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,13 @@ module Tiff_Mbi_Json =
open System.Globalization

type Mbi = {
obs_date : DateTime; sunPos : V3d; earthPos : V3d;
sc_quat : QuaternionD; targetPos : V3d
obs_date : DateTime;
sunPos : V3d;
earthPos : V3d;
sc_quat : QuaternionD;
targetPos : V3d
instrument : string
imagePath : string
}

let tryGetFitsHeader (headerName : string) (mbi : JsonValue) (m : JsonValue -> Option<'a>): Option<'a> =
Expand All @@ -119,6 +123,17 @@ module Tiff_Mbi_Json =
| _ ->
None

let tryGetImagePaths (mbi : JsonValue) (rootDirectory : string) : string array =
match mbi?bands with
| JsonValue.Array arr ->
arr
|> Array.map (fun band ->
let filename = band?file_path.AsString()
Log.line "%s" (Path.Combine(rootDirectory, filename))
Path.Combine(rootDirectory, filename)
)
| _ ->
[] |> List.toArray

let parseDate (s : JsonValue) : Option<DateTime> =
match s with
Expand Down Expand Up @@ -154,28 +169,37 @@ module Tiff_Mbi_Json =
let tryExtractSC_quat (mbi : JsonValue) =
match tryGetFitsHeader "SC_QUAT0" mbi parseFloat, tryGetFitsHeader "SC_QUAT1" mbi parseFloat, tryGetFitsHeader "SC_QUAT2" mbi parseFloat, tryGetFitsHeader "SC_QUAT3" mbi parseFloat with
| Some q0, Some q1, Some q2, Some q3 ->
QuaternionD(q0, q1, q2, q3) |> Result.Ok
Some (QuaternionD(q0, q1, q2, q3))
| _ ->
Result.Error "could not extract SC_QUAT from mbi json"
None


let tryParseJson (content : string) =
let tryParseJson (content : string) (rootDirectory : string) =
match JsonValue.TryParse(content) with
| Some mbi ->
try
let sunPos = tryExtractXyz "SUN_POSX" "SUN_POSY" "SUN_POSZ" mbi
let earthPos = tryExtractXyz "EARTPOSX" "EARTPOSY" "EARTPOSZ" mbi
let targetPos = tryExtractXyz "TRG_POSX" "TRG_POSY" "TRG_POSZ" mbi
let instrument = tryGetFitsHeader "INSTRUME" mbi (function JsonValue.String s -> Some s | _ -> None)
match tryExtractDateObsFromMbi mbi, sunPos, earthPos, tryExtractSC_quat mbi, targetPos, instrument with
| Some d, Some sunPos, Some earthPos, Result.Ok quat, Some targetPos, Some instrument ->
{
obs_date = d; sunPos = sunPos;
earthPos = earthPos
sc_quat = quat
targetPos = targetPos
instrument = instrument
} |> Result.Ok
let (imagePaths : string array) = tryGetImagePaths mbi rootDirectory
let date = tryExtractDateObsFromMbi mbi
let quat = tryExtractSC_quat mbi
match date with
| Some d ->
imagePaths
|> Array.map (fun image ->
// TBD: default values!
{
obs_date = d;
sunPos = match sunPos with | Some sunPos -> sunPos | None -> V3d.Zero
earthPos = match earthPos with | Some earthPos -> earthPos | None -> V3d.Zero
sc_quat = match quat with | Some quat -> quat | None -> QuaternionD(0,0,0,0)
targetPos = match targetPos with | Some targetPos -> targetPos | None -> V3d.Zero
instrument = match instrument with | Some instrument -> instrument | None -> ""
imagePath = image
}
) |> Result.Ok
| _ -> Result.Error (System.Exception("could not find DATE-OBS in mbi json"))
with e ->
Result.Error e
Expand All @@ -184,57 +208,32 @@ module Tiff_Mbi_Json =

type ParsedMetadata = Option<Tiff_Mbi_Json.Mbi> * Option<Tiff_Json.ImageMetadata>

let tryParseMetadataForImagePath (imagePath : string) : ParsedMetadata =
let getJsonMbiInfoPath (imagePath : string) (suffix : string) : string =
let killPhrases = ["_Stacked"; "_AFC1"; "_AFC2"; "_HSH"]
let fi = Path.Combine(Path.GetDirectoryName(imagePath), Path.GetFileNameWithoutExtension(imagePath) + suffix)
// metadata file naming does not follow a strict pattern, therefore we cover some variations of naming conventions we observed:
if File.Exists fi then
fi
else
List.fold (fun (path : string) kill -> path.Replace(kill, "")) fi killPhrases

let getJsonInfoPath (imagePath : string) (suffix : string) : string =
let killPhrases = ["_Stacked"; "_AFC1"; "_AFC2"; "_HSH"]
let fi = Path.Combine(Path.GetDirectoryName(imagePath), Path.GetFileName(imagePath) + suffix)
// metadata file naming does not follow a strict pattern, therefore we cover some variations of naming conventions we observed:
if File.Exists fi then
fi
else
let fiv1 = List.fold (fun (path : string) kill -> path.Replace(kill, "")) fi killPhrases
if File.Exists fiv1 then
fiv1
else
let fiv2 = fiv1.Replace(".exr", ".tif")
let fiv3 = fi.Replace(".exr", ".tif")
if Path.Exists fiv2 then
fiv2
else
fiv3

let mbi_json = getJsonMbiInfoPath imagePath ".mbi.json"
let json = getJsonInfoPath imagePath ".json"
match File.Exists(mbi_json), File.Exists(json) with
| true, true ->
try
let mbi_json = File.ReadAllText(mbi_json)
let jimMetadata = File.ReadAllText(json)
match Tiff_Mbi_Json.tryParseJson mbi_json, Tiff_Json.tryParseJson jimMetadata with
| Result.Ok mbi_json, Result.Ok tif_json -> Some mbi_json, Some tif_json
| _, Result.Ok jimMetadata -> None, Some jimMetadata
| Result.Ok mbi_json, _ -> Some mbi_json, None
| _ -> None, None
with e ->
printfn $"could not parse json metadtata for {imagePath}: {e}"
None, None
| f, e ->
printfn "%s, %A" mbi_json (f,e)
None, None
let parseDataForMbiPath (mbiPath : string) : (string * ParsedMetadata) array =
try
let mbiData = File.ReadAllText(mbiPath)
match Tiff_Mbi_Json.tryParseJson mbiData (Path.GetDirectoryName(mbiPath)) with
| Result.Ok mbi_json_files ->
mbi_json_files
|> Array.map (fun mbi_json ->
let imagePath = mbi_json.imagePath
let jimPath = imagePath + ".json"
let jimData = File.ReadAllText(jimPath)
match Tiff_Json.tryParseJson jimData with
| Result.Ok jimData ->
imagePath, (Some mbi_json, Some jimData)
| _ ->
imagePath, (Some mbi_json, None)
)
| _ ->
[] |> List.toArray
with e ->
printfn $"could not parse json metadtata for {mbiPath}: {e}"
[] |> List.toArray

let discoverInstrumentFolder (dir : string) : seq<string * ParsedMetadata> =
let tifs = Directory.EnumerateFiles(dir, "*.tif", SearchOption.TopDirectoryOnly)
tifs
|> Seq.map (fun tifFilename ->
let metaData = tryParseMetadataForImagePath tifFilename
tifFilename, metaData
let mbiFiles = Directory.EnumerateFiles(dir, "*.mbi.json", SearchOption.TopDirectoryOnly)
mbiFiles
|> Seq.map (fun mbiPath ->
parseDataForMbiPath mbiPath
)
|> Seq.collect id
13 changes: 11 additions & 2 deletions src/PRo3D.InstrumentProjection/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,15 @@ module InstrumentProjectionViewer =
Range1d.Unit
)

let texture =
currentProjectedImage |> AVal.map (fun img ->
match img with
| Some (texture, (_, Some imgMeta) : ParsedMetadata) ->
texture
| _ ->
""
)

let projectionOpacity =
cval 1.0

Expand All @@ -190,8 +199,8 @@ module InstrumentProjectionViewer =
colorMapping = colorMap
}

let projectImage = Visualization.creatProjectionFunction observer time referenceFrame currentProjectedImage (AVal.constant projection)
let projectedTexture = Visualization.createProjectedTexture currentProjectedImage (AVal.constant { idx = 0; name = None})
let projectImage = Visualization.creatProjectionFunction observer time referenceFrame (AVal.constant projection)
let projectedTexture = Visualization.createProjectedTexture (texture |> AVal.force) (AVal.constant { idx = 0; name = None})

let opc =
let molaOpcs =
Expand Down
Loading