Introducing a new primitive shape
The primitive fitting API is still under development, so please be careful. If you have any issues, or questions, feel free to open issues/PR-s.
Fitting API
If you want to extend the package with a new primitive, this page will guide you what to define/extend. You can also check the "built-in" primitives (src/shapes/...), which follow the same API.
The primitive must be subtype of FittedShape (struct MyShape<:FittedShape), and you must define the following functions:
defaultshapeparameters()fit()scorecandidate()refit()strt()
Docs of the functions:
RANSAC.defaultshapeparameters — FunctionReturn the default parameters as a NamedTuple for the passed FittedShape.
Implementation
Example definition for MyShape<:FittedShape: defaultshapeparameters(::Type{MyShape})=(myshape=(ϵ=1, α=deg2rad(5),),).
RANSAC.fit — FunctionFit a primitive shape to point-normal pairs (passed as an array of points and an array of normals). The type of the primitive and a parameter named tuple is also passed. The RANSACCloud is also passed if needed for more advanced methods. Return nothing, if can't fit the shape to the points.
Implementation
Signature: fit(::Type{MyShape}, p, n, pc, params).
It should return nothing if the fit wasn't succesfull, MyShape otherwise. If the fit results multiple shapes, it can return an array of MyShapes as well.
RANSAC.scorecandidate — FunctionCompute the score of a candidate and return its score and the corresponding points.
Implementation
Signature: scorecandidate(pc, candidate::MyShape, subsetID, params).
subsetID is the index of the subset that is used to estimate the score. You must count the compatible points (that are enabled) in the given subset. You can get the points by: pc.vertices[pc.subsets[subsetID]] and normals similarly. Use the estimatescore function to estimate a score, then return a (score, inpoints), where inpoints is the indexes of the points, that are counted.
RANSAC.estimatescore — Functionestimatescore(S1length, Plength, σS1)Give an estimate score for the whole pointcloud.
Arguments
S1length: number of points that are searched for compatible points (size of a subset).Plength: size of the whole point cloud.σS1: number of compatible points.
RANSAC.refit — FunctionRefit a primitive to the whole point cloud, say search for all the compatible points in the point cloud.
Implementation
Signature: refit(s::T, pc, params) where {T<:MyShape}.
Search all the compatible (and enabled) points in the whole point cloud. After finding the indexes, return an ExtractedShape.
RANSAC.strt — FunctionReturn a string that tells the "human-readable" type (plane, spehere, etc.) of a FittedShape.
Implementation
strt(s::MyShape) = "myshape"
Reading parameters from YAML file
If you want to read the parameters from a YAML file, you need to pass a dictionary to the readconfig function, that contains all the types, that you wish to use. If you have MyShape<:FittedShape and the following YAML file
plane:
- ϵ: 0.1
- α: 0.01
myshape:
- ϵ: 0.1
- α: 0.01
- anotherpar: 42
iteration:
- prob_det: 0.999
- τ: 10000
- itermax: 100000
- shape_types:
- plane
- myshapeyou should use the following script to read the parameters:
julia> myd = Dict("plane"=>FittedPlane, "myshape"=>MyShape)
Dict{String,Type} with 2 entries:
"plane" => FittedPlane
"myshape" => MyShape
julia> p = readconfig("config.yml", shapedict=myd)
(iteration = (drawN = 3, minsubsetN = 15, prob_det = 0.999,
shape_types = Type[FittedPlane, MyShape], τ = 10000, itermax = 100000,
extract_s = :nofminset, terminate_s = :nofminset),
common = (collin_threshold = 0.2, parallelthrdeg = 1.0),
plane = (ϵ = 0.1, α = 0.01),
cone = (ϵ = 0.3, α = 0.08726646259971647, minconeopang = 0.03490658503988659),
cylinder = (ϵ = 0.3, α = 0.08726646259971647),
sphere = (ϵ = 0.3, α = 0.08726646259971647, sphere_par = 0.02),
myshape = (ϵ = 0.1, α = 0.01, anotherpar = 42))The parameters for MyShape can be accessed with p.myshape. In any functions you need, the @extract macro can help from the ExtractMacro.jl package.
An example:
function fit(::Type{MyShape}, p, n, params)
@extract params: params_myshape=myshape
@extract params_myshape : α, anotherpar
# you can use α, anotherpar as you wish
...
end