From 6a3ac9d062e28b20ff1f7ae89fe4e7bb5a366547 Mon Sep 17 00:00:00 2001 From: Vincent Florian Date: Tue, 15 Jun 2021 15:38:50 +0200 Subject: [PATCH 1/4] Automatic estimate of a good number of pyramid levels --- web-elm/src/Main.elm | 83 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 80 insertions(+), 3 deletions(-) diff --git a/web-elm/src/Main.elm b/web-elm/src/Main.elm index 7711a19..7b8d9ea 100644 --- a/web-elm/src/Main.elm +++ b/web-elm/src/Main.elm @@ -265,7 +265,7 @@ defaultParams : Parameters defaultParams = { crop = Nothing , equalize = True - , levels = 4 + , levels = 1 , sparse = 0.5 , lambda = 1.5 , rho = 0.1 @@ -546,6 +546,15 @@ update msg model = oldParamsForm = model.paramsForm + + oldParams = + model.params + + optiLevels = + getOptimumPyramids newLoaded + + anyInt = + NumberInput.intDefault in if Set.size names == Dict.size newLoaded then case Dict.values newLoaded of @@ -557,7 +566,17 @@ 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 + } , imagesCount = Set.size names } , Cmd.none @@ -979,6 +998,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 } @@ -2034,7 +2109,9 @@ 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 defaultParams.levels ++ ")") + -- /!\ Default number of pyramids removed in order to put a fitting number of pyramids , intInput paramsForm.levels (ParamsMsg << ChangeLevels) "Number of pyramid levels" , displayIntErrors paramsForm.levels.decodedInput ] From 1d6bf9b8c6a6353ceda4cebe2ff2c3b6a4cfcd61 Mon Sep 17 00:00:00 2001 From: Vincent Florian Date: Fri, 18 Jun 2021 12:35:33 +0200 Subject: [PATCH 2/4] [Auto-resolution for pyramids] The optimum number of pyramids is only computed once, when all images are loaded --- web-elm/src/Main.elm | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/web-elm/src/Main.elm b/web-elm/src/Main.elm index 7b8d9ea..56d48ea 100644 --- a/web-elm/src/Main.elm +++ b/web-elm/src/Main.elm @@ -544,19 +544,22 @@ update msg model = , loaded = newLoaded } + finished = (Set.size names == Dict.size newLoaded) + oldParamsForm = model.paramsForm oldParams = model.params - optiLevels = - getOptimumPyramids newLoaded + 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 From 681854cb7ebcb4b08583468c9546f57f5840dd01 Mon Sep 17 00:00:00 2001 From: Vincent Florian Date: Fri, 18 Jun 2021 12:45:21 +0200 Subject: [PATCH 3/4] [Auto-resolution for pyramids] The default number of pyramids is stored in the model directly. It is then displayed in the little text of the config tab : "(defaults to x)" --- web-elm/src/Main.elm | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/web-elm/src/Main.elm b/web-elm/src/Main.elm index 56d48ea..b0bb329 100644 --- a/web-elm/src/Main.elm +++ b/web-elm/src/Main.elm @@ -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 @@ -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 @@ -579,6 +581,7 @@ update msg model = , max = Just 10 } |> NumberInput.setDefaultIntValue optiLevels + , defaultLevels = optiLevels } , imagesCount = Set.size names } @@ -2113,8 +2116,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 ++ ")") - -- /!\ Default number of pyramids removed in order to put a fitting number of pyramids + , Element.text ("(default to " ++ String.fromInt model.paramsForm.defaultLevels ++ ")") , intInput paramsForm.levels (ParamsMsg << ChangeLevels) "Number of pyramid levels" , displayIntErrors paramsForm.levels.decodedInput ] From 491a6e7a2c57ce951a1e8a247c398b7aadab31bb Mon Sep 17 00:00:00 2001 From: Vincent Florian Date: Fri, 18 Jun 2021 12:47:08 +0200 Subject: [PATCH 4/4] [Formating] elm-format applied for the branch auto-res --- web-elm/src/Main.elm | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/web-elm/src/Main.elm b/web-elm/src/Main.elm index b0bb329..f972e1a 100644 --- a/web-elm/src/Main.elm +++ b/web-elm/src/Main.elm @@ -546,7 +546,8 @@ update msg model = , loaded = newLoaded } - finished = (Set.size names == Dict.size newLoaded) + finished = + Set.size names == Dict.size newLoaded oldParamsForm = model.paramsForm @@ -554,9 +555,12 @@ update msg model = oldParams = model.params - optiLevels = if finished - then getOptimumPyramids newLoaded - else model.params.levels + optiLevels = + if finished then + getOptimumPyramids newLoaded + + else + model.params.levels anyInt = NumberInput.intDefault @@ -2115,7 +2119,6 @@ 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 model.paramsForm.defaultLevels ++ ")") , intInput paramsForm.levels (ParamsMsg << ChangeLevels) "Number of pyramid levels" , displayIntErrors paramsForm.levels.decodedInput