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 MyShape
s 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
- myshape
you 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