Introducing a new primitive shape

API under development

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.defaultshapeparametersFunction

Return the default parameters as a NamedTuple for the passed FittedShape.

Implementation

Example definition for MyShape<:FittedShape: defaultshapeparameters(::Type{MyShape})=(myshape=(ϵ=1, α=deg2rad(5),),).

source
RANSAC.fitFunction

Fit 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.

source
RANSAC.scorecandidateFunction

Compute 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.

source
RANSAC.estimatescoreFunction
estimatescore(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.
source
RANSAC.refitFunction

Refit 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.

source
RANSAC.strtFunction

Return a string that tells the "human-readable" type (plane, spehere, etc.) of a FittedShape.

Implementation

strt(s::MyShape) = "myshape"

source

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