Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Automatic pyramids levels fit] #13

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
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
93 changes: 89 additions & 4 deletions web-elm/src/Main.elm
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ type alias ParametersForm =
, maxIterations : NumberInput.Field Int NumberInput.IntError
, convergenceThreshold : NumberInput.Field Float NumberInput.FloatError
, levels : NumberInput.Field Int NumberInput.IntError
, defaultLevels : Int
, sparse : NumberInput.Field Float NumberInput.FloatError
, lambda : NumberInput.Field Float NumberInput.FloatError
, rho : NumberInput.Field Float NumberInput.FloatError
Expand Down Expand Up @@ -265,7 +266,7 @@ defaultParams : Parameters
defaultParams =
{ crop = Nothing
, equalize = True
, levels = 4
, levels = 1
, sparse = 0.5
, lambda = 1.5
, rho = 0.1
Expand Down Expand Up @@ -300,6 +301,7 @@ defaultParamsForm =
, levels =
{ anyInt | min = Just 1, max = Just 10 }
|> NumberInput.setDefaultIntValue defaultParams.levels
, defaultLevels = 0
, sparse =
{ anyFloat | min = Just 0.0, max = Just 1.0 }
|> NumberInput.setDefaultFloatValue defaultParams.sparse
Expand Down Expand Up @@ -544,10 +546,26 @@ update msg model =
, loaded = newLoaded
}

finished =
Set.size names == Dict.size newLoaded

oldParamsForm =
model.paramsForm

oldParams =
model.params

optiLevels =
if finished then
getOptimumPyramids newLoaded

else
model.params.levels

anyInt =
NumberInput.intDefault
in
if Set.size names == Dict.size newLoaded then
if finished then
case Dict.values newLoaded of
[] ->
-- This should be impossible, there must be at least 1 image
Expand All @@ -557,7 +575,18 @@ update msg model =
( { model
| state = ViewImgs { images = Pivot.fromCons firstImage otherImages }
, viewer = Viewer.fitImage 1.0 ( toFloat firstImage.width, toFloat firstImage.height ) model.viewer
, paramsForm = { oldParamsForm | crop = CropForm.withSize firstImage.width firstImage.height }
, params = { oldParams | levels = optiLevels }
, paramsForm =
{ oldParamsForm
| crop = CropForm.withSize firstImage.width firstImage.height
, levels =
{ anyInt
| min = Just 1
, max = Just 10
}
|> NumberInput.setDefaultIntValue optiLevels
, defaultLevels = optiLevels
}
, imagesCount = Set.size names
}
, Cmd.none
Expand Down Expand Up @@ -979,6 +1008,62 @@ update msg model =
( model, Cmd.none )


{-|

We search the number n of level of the pyramid.
We know that h/(2^n)>100 and w/(2^n)>100
with w the width and h the height of the image
So as x -> log_2(x) is monotonous, we have :
n < log_2(min{h, w}/100)
We choose to use n=floor(...) to get a nice integer result.

getOptimumPyramids(imgsList) = floor[log_2(min{h, w}/100)]

-}
getOptimumPyramids : Dict String Image -> Int
getOptimumPyramids imgs =
imgs
-- (Dict String/Image)
|> Dict.values
-- (List Image)
|> minWidthHeight
-- (Int)
|> toFloat
-- (Float)
|> (*) 0.01
-- ~ Divide by 100, the min length -- (Float)
|> logBase 2
-- (Float)
|> floor



-- (Int) The approximate number of pyramids levels
-- Just a function to get the minimum side dimension of a list of images.
-- /!\ It might be useless if all of the images have the same dimension...
-- But whatever, we can just use the dimensions of the last image.


minWidthHeight : List Image -> Int
minWidthHeight imgs =
let
maybeMinimum =
imgs
-- -> (List Image)
|> List.map (\img -> min img.width img.height)
-- -> (List Int)
|> List.minimum

-- -> (Int)
in
case maybeMinimum of
Nothing ->
defaultParams.levels

Just trueMinimum ->
trueMinimum


runAndSwitchToLogsPage : { images : Pivot Image } -> Model -> Model
runAndSwitchToLogsPage imgs model =
goTo GoToPageLogs imgs { model | registeredImages = Nothing, runStep = StepNotStarted }
Expand Down Expand Up @@ -2034,7 +2119,7 @@ viewConfig ({ params, paramsForm, paramsInfo, notSeenLogs, registeredImages } as
}
]
, moreInfo paramsInfo.levels "The number of levels for the multi-resolution approach. Each level halves/doubles the resolution of the previous one. The algorithm starts at the lowest resolution and transfers the converged parameters at one resolution to the initialization of the next. Increasing the number of levels enables better convergence for bigger movements but too many levels might make it definitively drift away. Targetting a lowest resolution of about 100x100 is generally good enough. The number of levels also has a joint interaction with the sparse threshold parameter so keep that in mind while changing this parameter."
, Element.text ("(default to " ++ String.fromInt defaultParams.levels ++ ")")
, Element.text ("(default to " ++ String.fromInt model.paramsForm.defaultLevels ++ ")")
, intInput paramsForm.levels (ParamsMsg << ChangeLevels) "Number of pyramid levels"
, displayIntErrors paramsForm.levels.decodedInput
]
Expand Down