Skip to content

Commit

Permalink
Update to v1.0.0 (#13)
Browse files Browse the repository at this point in the history
* Breaking change to NLLSOptions
* Generalize lens distortion conversion function
* Several bug fixes and stability improvements
  • Loading branch information
ojwoodford authored Mar 23, 2023
1 parent 38b2d51 commit 41501f2
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 19 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "NLLSsolver"
uuid = "50b5cf9e-bf7a-4e29-8981-4280cbba70cb"
authors = ["Oliver Woodford"]
version = "0.1.1"
version = "1.0.0"

This comment has been minimized.

Copy link
@ojwoodford

ojwoodford Mar 23, 2023

Author Owner

[deps]
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
Expand Down
8 changes: 6 additions & 2 deletions src/iterators.jl
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
using LDLFactorizations
export iterate!, NewtonData, DoglegData, LevMarData

function symmetricsolve(A::AbstractMatrix, b::AbstractVector, options)
function symmetricsolve(A::SparseMatrixCSC, b::AbstractVector, options)
return ldl(A) \ b
end

function symmetricsolve(A::AbstractMatrix, b::AbstractVector, options)
return Symmetric(A) \ b
end

function linearsolve(A::AbstractMatrix, b::AbstractVector, options)
return solve(LinearProblem(A, b)).u
end
Expand Down Expand Up @@ -141,7 +145,7 @@ function iterate!(levmardata::LevMarData, data::NLLSInternal, problem::NLLSProbl
# Success (or convergence) - update lambda
uniformscaling!(hessian, -lastlambda)
step_quality = (cost_ - data.bestcost) / (((data.step' * hessian) * 0.5 + gradient') * data.step)
levmardata.lambda *= max(0.1, 1 - (step_quality - 1) ^ 3)
levmardata.lambda *= step_quality < 1.966 ? 1 - (step_quality - 1) ^ 3 : 0.1
# Return the cost
return cost_
end
Expand Down
2 changes: 1 addition & 1 deletion src/optimize.jl
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ function optimize!(problem::NLLSProblem{VarTypes}, options::NLLSOptions, data::N
push!(trajectory, copy(data.step))
end
# Check for convergence
if options.callback(problem, data, cost) || !(dcost >= data.bestcost * options.dcost) || (maximum(abs, data.step) < options.dstep) || (fails > options.maxfails) || data.iternum >= options.maxiters
if options.callback(problem, data, cost) || !(dcost >= data.bestcost * options.reldcost) || !(dcost >= options.absdcost) || (maximum(abs, data.step) < options.dstep) || (fails > options.maxfails) || data.iternum >= options.maxiters
break
end
# Update the variables
Expand Down
9 changes: 5 additions & 4 deletions src/structs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ function Base.String(iterator::NLLSIterator)
end

struct NLLSOptions
dcost::Float64 # Minimum relative reduction in cost required to avoid termination
reldcost::Float64 # Minimum relative reduction in cost required to avoid termination
absdcost::Float64 # Minimum relative reduction in cost required to avoid termination
dstep::Float64 # Minimum L-infinity norm of the update vector required to avoid termination
maxfails::Int # Maximum number of consecutive iterations that have a higher cost than the current best before termination
maxiters::Int # Maximum number of outer iterations
Expand All @@ -26,8 +27,8 @@ struct NLLSOptions
storecosts::Bool # Indicates whether the cost per outer iteration should be stored
storetrajectory::Bool # Indicates whether the step per outer iteration should be stored
end
function NLLSOptions(; maxiters=100, dcost=1.e-6, dstep=1.e-6, maxfails=3, iterator=gaussnewton, callback=(args...)->false, storecosts=false, storetrajectory=false)
NLLSOptions(dcost, dstep, maxfails, maxiters, iterator, callback, storecosts, storetrajectory)
function NLLSOptions(; maxiters=100, reldcost=1.e-6, absdcost=1.e-15, dstep=1.e-6, maxfails=3, iterator=levenbergmarquardt, callback=(args...)->false, storecosts=false, storetrajectory=false)
NLLSOptions(reldcost, absdcost, dstep, maxfails, maxiters, iterator, callback, storecosts, storetrajectory)
end

struct NLLSResult
Expand Down Expand Up @@ -100,7 +101,7 @@ mutable struct NLLSInternal{VarTypes}
end
varlen = UInt(nvars(problem.variables[unfixed]))
linsystem = UniVariateLS(unfixed, varlen, computehessian ? varlen : UInt(lengthresiduals(problem.residuals)))
return new(copy(problem.variables), copy(problem.variables), linsystem, Vector{Float64}(undef, varlen), 0., 0., 0., 0., 0, 0, 0, starttimens)
return new(copy(problem.variables), copy(problem.variables), linsystem, Vector{Float64}(undef, varlen), 0., 0., 0., 0., 0, 0, 0, 0, starttimens)
end

# Multiple variables. Use a block sparse matrix
Expand Down
21 changes: 10 additions & 11 deletions src/visualgeometry/camera.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export SimpleCamera, NoDistortionCamera, ExtendedUnifiedCamera, BarrelDistortion
export ideal2image, image2ideal, pixel2image, image2pixel, update, nvars, nres, varindices, getvars, computeresidual, barrel2eulens
export SimpleCamera, NoDistortionCamera, ExtendedUnifiedCamera, BarrelDistortion, EULensDistortion
export ideal2image, image2ideal, pixel2image, image2pixel, ideal2distorted, distorted2ideal, update, nvars, nres, varindices, getvars, computeresidual, convertlens
using StaticArrays, LinearAlgebra


Expand Down Expand Up @@ -135,24 +135,23 @@ struct LensDistortResidual{T} <: AbstractResidual
end
nvars(@objtype(LensDistortResidual)) = 1 # The residual depends on one variable
nres(@objtype(LensDistortResidual)) = 1 # The residual vector has length one
varindices(::LensDistortResidual) = [1]
varindices(::LensDistortResidual) = SVector(1)
function computeresidual(residual::LensDistortResidual, lens::EULensDistortion)
return SVector(residual.rdistort - ideal2distorted(lens, residual.rlinear))
end
function getvars(::LensDistortResidual{T}, vars::Vector) where T
return (vars[1]::EULensDistortion{T},)
end

function barrel2eulens(k1, k2, halfimsz)
function convertlens(tolens, fromlens, halfimsz)
# Create an optimization problem to convert the lens distortion
problem = NLLSsolver.NLLSProblem{EULensDistortion}()
NLLSsolver.addvariable!(problem, EULensDistortion(0.001, 1.))
for x in range(0, halfimsz, 100)
x2 = x ^ 2
NLLSsolver.addresidual!(problem, LensDistortResidual(x, x * (1 + x2 * (k1 + x2 * k2))))
problem = NLLSsolver.NLLSProblem{typeof(tolens)}()
NLLSsolver.addvariable!(problem, tolens)
for x in LinRange(0., convert(Float64, halfimsz), 100)
NLLSsolver.addresidual!(problem, LensDistortResidual(x, ideal2distorted(fromlens, x)))
end
# Optimize
NLLSsolver.optimize!(problem, NLLSsolver.NLLSOptions(dcost=1.e-6, iterator=NLLSsolver.levenbergmarquardt))
NLLSsolver.optimize!(problem, NLLSsolver.NLLSOptions(iterator=NLLSsolver.dogleg))
# Return the lens
return problem.variables[1]
end
end
10 changes: 10 additions & 0 deletions test/camera.jl
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,14 @@ end
testcamera(NoDistortionCamera(f, c), x)
testcamera(ExtendedUnifiedCamera(f, c, 0.1, 0.1), x)
testcamera(ExtendedUnifiedCamera(f, c, 0.5, 0.2), x)

# Test lens distortion model conversion
halfimsz = 1.
fromlens = BarrelDistortion(-1.e-5, -1.e-7)
tolens = convertlens(EULensDistortion(0.1, 0.1), fromlens, halfimsz)
maxerror = 0.
for x in LinRange(0., halfimsz, 100)
maxerror = max(maxerror, abs(ideal2distorted(tolens, x) - ideal2distorted(fromlens, x)))
end
@test maxerror < 1.e-6
end

1 comment on commit 41501f2

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/80170

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v1.0.0 -m "<description of version>" 41501f2446510f4adf3b962ff5ff708fd61143c5
git push origin v1.0.0

Please sign in to comment.