diff --git a/web-elm/src/Main.elm b/web-elm/src/Main.elm index 7711a19..f972e1a 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 @@ -265,7 +266,7 @@ defaultParams : Parameters defaultParams = { crop = Nothing , equalize = True - , levels = 4 + , levels = 1 , sparse = 0.5 , lambda = 1.5 , rho = 0.1 @@ -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 @@ -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 @@ -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 @@ -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 } @@ -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 ]