@@ -75,6 +75,21 @@ Base.@kwdef struct ObjectAffordanceSubcloud <: AbstractManifoldMinimize
7575 added to the same object variable later by the user. See [`IIF.rebuildFactorMetadata!`](@ref).
7676 FIXME: there is a hack, should not be using Serialization.deserialize on a PCLPointCloud2, see Caesar.jl#921 """
7777 p_PC_blobIds:: Vector{UUID} = Vector {UUID} ()
78+ """
79+ Object Affordance factor can be used to "close loops" if the user knows two object are the same.
80+ E.g. say two OAS factors already make two :OBJECT_AFFORDANCE variables of the same physical object,
81+ then creating a third and loop obj variable and third OAS factor with .loopObject=true against the
82+ existing two object variables should effectively "close the loop".
83+ """
84+ loopObject:: Bool = false
85+ """
86+ Alignment parameters
87+ """
88+ alignParams:: Dict{Symbol,Int} = Dict {Symbol,Int} (
89+ :max_iterations => 40 ,
90+ :correspondences => 500 ,
91+ :neighbors => 50
92+ )
7893end
7994
8095# function Base.getproperty(oas::ObjectAffordanceSubcloud, f::Symbol)
@@ -127,6 +142,18 @@ function _findObjPriors(dfg::AbstractDFG, fvars::AbstractVector{<:DFGVariable})
127142 return objpriors, op_PCs
128143end
129144
145+ function _findObjAffSubcFactor (dfg:: AbstractDFG , objl:: Symbol )
146+ # find oas factor label where objl is first variable
147+ fcts = ls (dfg, objl)
148+ # loop through all factors on this obj variable
149+ for fc in getFactor .(dfg, fcts)
150+ vo = getVariableOrder (fc)
151+ # check that it is the OAS factor defining this vo[1] obj Variable
152+ if 1 < length (vo) && vo[1 ] == objl
153+ return getLabel (fc)
154+ end
155+ end
156+ end
130157
131158function _defaultOASCache (
132159 dfg:: AbstractDFG ,
@@ -160,13 +187,26 @@ function _defaultOASCache(
160187
161188 # NOTE, obj variable first, pose variables are [2:end]
162189 for (i,vl) in enumerate (getLabel .(fvars)[2 : end ])
163- p_PC = _PCL. getDataPointCloud (dfg, vl, fct. p_PC_blobIds[i]; checkhash= false ) |> _PCL. PointCloud
164- p_SC = _PCL. getSubcloud (p_PC, fct. p_BBos[i]; minrange, maxrange)
190+ lhat_T_p_, p_SC = if ! fct. loopObject
191+ p_PC = _PCL. getDataPointCloud (dfg, vl, fct. p_PC_blobIds[i]; checkhash= false ) |> _PCL. PointCloud
192+ p_SC_ = _PCL. getSubcloud (p_PC, fct. p_BBos[i]; minrange, maxrange)
193+ fct. lhat_Ts_p[i], p_SC_
194+ else
195+ # use this when OAS is used to close loop on already existing ObjAff variables
196+ @assert :OBJECT_AFFORDANCE in getTags (fvars[i]) " ObjAffSubc factor with .loopObject = true must connect to variables with the tag :OBJECT_AFFORDANCE"
197+ foaslb = _findObjAffSubcFactor (dfg, vl)
198+ # get the obj aff point cloud
199+ o_SC_ = Caesar. assembleObjectCache (dfg, foaslb)
200+ # transform obj aff clouds to same reference frame
201+ w_T_o_ = fct. lhat_Ts_p[i] |> deepcopy # getBelief(dfg, vl) |> mean
202+ # return transform to common frame and object frame subcloud
203+ w_T_o_, o_SC_
204+ end
205+ # sanity check
165206 if 0 === length (p_SC)
166207 error (" ObjectAffordance factor cannot use empty subcloud on $(vl) " )
167208 end
168-
169- lhat_T_p_ = fct. lhat_Ts_p[i]
209+ # use mutable format
170210 lhat_T_p = ArrayPartition (
171211 MVector (lhat_T_p_. x[1 ]. .. ),
172212 MMatrix {size(lhat_T_p_.x[2])...} (lhat_T_p_. x[2 ])
@@ -229,6 +269,14 @@ function IncrementalInference.preambleCache(
229269 for i in 1 : length (cache. ohat_SCs)
230270 push! (cache. o_Ts_ohat, e0)
231271 end
272+ k_ = keys (fct. alignParams) |> collect
273+ v_ = values (fct. alignParams) |> collect
274+ arr = []
275+ for i in 1 : length (k_)
276+ push! (arr, (k_[i]=> v_[i]))
277+ end
278+ tup = (arr... ,)
279+ lookws = (;tup... )
232280
233281 # finalize object point clouds for cache
234282 # align if there if there is at least one LIE transform and cloud available.
@@ -237,7 +285,8 @@ function IncrementalInference.preambleCache(
237285 _PCL. alignPointCloudsLOOIters! (
238286 cache. o_Ts_ohat,
239287 cache. ohat_SCs,
240- true
288+ true ;
289+ lookws...
241290 )
242291 end
243292
@@ -361,8 +410,18 @@ function generateObjectAffordanceFromWorld!(
361410 w_BBobj:: _PCL.AbstractBoundingBox ;
362411 solveKey:: Symbol = :default ,
363412 pcBlobLabel = r" PCLPointCloud2" ,
364- modelprior:: Union{Nothing,<:_PCL.PointCloud} = nothing
413+ modelprior:: Union{Nothing,<:_PCL.PointCloud} = nothing ,
414+ loopObject:: Bool = false ,
415+ alignParams:: Dict{Symbol,Int} = Dict {Symbol,Int} (
416+ :max_iterations => 40 ,
417+ :correspondences => 500 ,
418+ :neighbors => 50
419+ )
365420)
421+ if 0 === length (vlbs)
422+ @error " No variables from which to build and object affordance."
423+ return nothing
424+ end
366425 M = SpecialEuclidean (3 ) # getManifold(Pose3)
367426 # add the object variable
368427 addVariable! (dfg, olb, Pose3; tags= [:OBJECT_AFFORDANCE ])
@@ -374,24 +433,34 @@ function generateObjectAffordanceFromWorld!(
374433 end
375434
376435 # add the object affordance subcloud factors
377- oas = ObjectAffordanceSubcloud ()
436+ oas = ObjectAffordanceSubcloud (;loopObject, alignParams )
378437
379438 for vlb in vlbs
380439 # make sure PPE is set on this solveKey
381440 setPPE! (dfg, vlb, solveKey)
382- # lhat frame is some local frame where object subclouds roughly fall together (could be host start from world frame)
383- p_BBo, p_T_lhat = _PCL. transformFromWorldToLocal (dfg, vlb, w_BBobj; solveKey)
384- lhat_T_p_ = inv (M, p_T_lhat)
385- # make immutable data type
386- lhat_T_p = ArrayPartition (SA[lhat_T_p_. x[1 ]. .. ], SMatrix {3,3} (lhat_T_p_. x[2 ]))
387- p_PC_blobId = getDataEntry (dfg, vlb, pcBlobLabel). id
388- push! (oas. p_BBos, p_BBo)
389- push! (oas. lhat_Ts_p, lhat_T_p)
390- push! (oas. p_PC_blobIds, p_PC_blobId)
441+ if ! loopObject
442+ # lhat frame is some local frame where object subclouds roughly fall together (could be host start from world frame)
443+ p_BBo, p_T_lhat = _PCL. transformFromWorldToLocal (dfg, vlb, w_BBobj; solveKey)
444+ lhat_T_p_ = inv (M, p_T_lhat)
445+ # make immutable data type
446+ lhat_T_p = ArrayPartition (SA[lhat_T_p_. x[1 ]. .. ], SMatrix {3,3} (lhat_T_p_. x[2 ]))
447+ p_PC_blobId = getDataEntry (dfg, vlb, pcBlobLabel). id
448+ push! (oas. p_BBos, p_BBo)
449+ push! (oas. lhat_Ts_p, lhat_T_p)
450+ push! (oas. p_PC_blobIds, p_PC_blobId)
451+ else
452+ w_T_o = getBelief (dfg, vlb, solveKey) |> mean
453+ push! (oas. lhat_Ts_p, w_T_o) # inv(M, w_T_o)) # do not understand the inverse?
454+ end
391455 end
392456
393- addFactor! (dfg, [olb; vlbs], oas)
394-
457+ try
458+ addFactor! (dfg, [olb; vlbs], oas)
459+ catch err
460+ deleteVariable! (dfg, olb)
461+ rethrow (err)
462+ end
463+
395464 oas
396465end
397466
@@ -517,7 +586,8 @@ function protoObjectCheck!(
517586 minrange = 0.75 ,
518587 varList:: AbstractVector{Symbol} = _PCL. findObjectVariablesFromWorld (dfg, w_BBo; solveKey, limit, minpoints, selection, minList, maxList),
519588 obl:: Symbol = :testobj ,
520- align:: Symbol = :fine
589+ align:: Symbol = :fine ,
590+ oaskw...
521591)
522592 #
523593 try
@@ -529,7 +599,8 @@ function protoObjectCheck!(
529599 obl,
530600 varList,
531601 w_BBo;
532- solveKey
602+ solveKey,
603+ oaskw...
533604 )
534605
535606 flb = intersect ((ls .(dfg, varList)). .. , ls (dfg, obl))[1 ]
0 commit comments