CloudCompare / CloudComPy

Python wrapper for CloudCompare
Other
265 stars 38 forks source link

check overlap / cc.DistanceComputationTools.computeApproxCloud2CloudDistance(cloud1,cloud2) #141

Closed antoinebio closed 4 months ago

antoinebio commented 8 months ago

Hello again, before running C2C in batch all thousand of scan stations, I would like to check if there are overlaps between tested pointclouds to skip the unecessary pairs .

if i input 2 scans in cc GUI

image

I can see there is no overlap

but if I run a test using

cc.DistanceComputationTools.computeApproxCloud2CloudDistance(cloud1,cloud2)

I still have value returns

image

Is there any boolean function to check any overlaps between 2 clouds ? ; otherwise any alternative way such as with bounding box of E57 inputs ? (boolean intersection) thanks antoine

prascle commented 8 months ago

Hello, I don't think there's a dedicated Boolean function for checking overlap between clouds. Working with bounding boxes is of course a quick first step, to get a sufficient condition to eliminate non-overlapping pairs. Then, computeApproxCloud2CloudDistance is probably a quick second step to eliminate more non-overlapping pairs... Depending on your specific use case and the number and size of clouds, there are probably different strategies... Perhaps Label Connected Components can give you some ideas (see LabelConnectedComponents in CloudComPy. Best, Paul

antoinebio commented 8 months ago

Paul, to speed up do you recommend to use OCTREE info after cloud loading ?

nbCells = octree.getCellNumber(level)

and works with the first OCTREE (level 0) ? then ask to get BBox of that OCTREE LEVEL ?

image

to get bounding box we must use that function ?

https://www.simulation.openfields.fr/documentation/CloudComPy/html/ccOctree.html#cloudComPy.DgmOctree.getBoundingBox

(found in test013.py exemple dataset code)

what about the coordinates returned ? is it location from the internal ref frame or the absolute ref frame ?

image

which ones of them ?

other wise I can rely on header info of E57 or LAZ but providing the info is consistent (it could be wrong header info but good pts position after parsing the entire file).

prascle commented 8 months ago

I suggest to use the getOwnBB method of the cloud. You don't need to deal with octree at that step. When you work with CloudComPy, you manipulate the internal coordinates of CloudCompare (the shifted coordinates). If you want to retreive the original coordinates, you have to use the getGlobalShift method.

antoinebio commented 8 months ago

ok will try if a comparison of what is returned by [getOwnBB] satisfies our need. If I load recursively 2 clouds (ref and test) are the internal coordinates of CloudCompare the same CRS ? same origin ? we do not care about absolute coordinate at this step, if internal coordinates are in the same "word"

prascle commented 8 months ago

If you want to be sure to have the same shift, use an explicit shift : see Load with explicit shift parameters.

antoinebio commented 8 months ago

shift is the same when you load recursively 2 clouds in the same script

cloud1 = cc.loadPointCloud(cloud_reference) # read the first point cloud1 from a file print("\nfirst cloud name: %s"%cloud1.getName()) if not cloud1.isShifted(): raise RuntimeError shift = cloud1.getGlobalShift() print(shift)

elapsed_time1 = time.process_time() - t print('->->-> temps de chargement : ' , '{:.1f}'.format(elapsed_time1) , '(sec)')

cloud2 = cc.loadPointCloud(cloud_compare) # read the first point cloud1 from a file print("\nsecond cloud name: %s"%cloud2.getName()) if not cloud2.isShifted(): raise RuntimeError shift = cloud2.getGlobalShift() print(shift)

image
prascle commented 8 months ago

Shift is not always the same, even in the same script! There is for instance the #29 issue about this problem.

antoinebio commented 8 months ago

ok thanks for the warning. will do a check therefore

antoinebio commented 8 months ago

Hi @prascle the first skip with the bounding box works well.

then comes the second step with computeApproxCloud2CloudDistance

How do you deal with returned value with cc.DistanceComputationTools.computeApproxCloud2CloudDistance(cloud1,cloud2)

How are those values computed by CC ?

[min, max, mean, variance, error max]

image

in order to eliminate more non-overlapping pairs...

you were also suggesting Label Connected Components

If I understand well that function returns (https://www.simulation.openfields.fr/documentation/CloudComPy/html/cloudComPy.html#cloudComPy.LabelConnectedComponents) in CloudComPy.

If we have a look to the function

image

can I get d from min or max values from computeApproxCloud2CloudDistance ?

I would like to work with first octree level . can I use level 0 ?

when computing individual octree level for each cloud we can see overlapping areas... but probably we should also combine that with computeApproxCloud2CloudDistance results... If we understand them.

image image image

Is there any equivalence between that computeApproxCloud2CloudDistance and what CC GUI offer in TOOL> DISTANCES > Compute closest point set

Capture d'écran 2023-10-27 095454

cloudcompare wiki gives that answer https://danielgm.net/cc/forum/viewtopic.php?p=7869&sid=fe28db4801179d505def3307b301563c#p7869

antoinebio commented 8 months ago

correction computeApproxCloud2CloudDistance IS NOT what CC GUI offer in TOOL> DISTANCES > Compute closest point set

computeApproxCloud2CloudDistance is given in C2C tool after having chosen your 2 clouds. in last tabs like below.

image

Is it possible to get that histogram with cloudcompy ? I only want that histogram to report and skip unwanted pairs...

prascle commented 8 months ago

Hello, Some answers, with an example (2 cloud from manitou sample in my tests).

image

On the left side: cloud sp25_2 (colored) On the right side: cloud sp26_2 (grey) on the center: the closet point set of sp26_2 relative to sp25_2 (big colored nodes)

Now, the octrees at level 5 (at each octree level, you subdivide the boxes by 2 in each direction: here the size of the boxes are 32 time smaller than the cloud bounding box) image On the left side: octree for sp25_2 (plain boxes colored) On the right side: octree for sp26_2 (wireframe)

As I understand it, in computeApproxCloud2CloudDistance, distances are calculated between boxes of the octree level you've chosen: with a higher octree level, it's more accurate, but it takes longer to calculate. Only the min value is of interest in your case, to decide if the clouds overlap or not (I am not sure if the histogram data is easily accessible from cloudComPy, I will check).

I therefore think that using 0 as the octree level in computeApproxCloud2CloudDistance should give the same result as the bounding box overlap test. Using higher levels may help you find more non-overlapping cloud pairs.

The strategy to adopt depends on your use case: how many clouds, of what size ? how many cloud can you load simultaneously on your computer... The idea behind LabelConnectedComponents was to combine a large number of clouds into one, and to find an answer to the question of which parts overlap in a single calculation, perhaps you can achieve this with a subsampling of the original clouds...

Best, Paul

antoinebio commented 8 months ago

hello @prascle the purpose of my task is to inspect TLS pointcloud given by station in 57 format (structured pointcloud also called grid scan or ordered pointcloud). I am chosing uniques pairs of a given set, N files, of about 100 Mo per file to 200 Mo per file (depending of the scan resolution)

image

skip unwanted pairs that do not overlaps themselve (DONE)

and also skip or prevent from doing C2C computation for small or bad layout of overlaping boxs (exemple below)

image

it would be good to skip also the below case

image

where there is a small relevant part to analyse the adjutement between the pairs of scans when using C2CDistance (a small amount of point in a given distance range / compare to the entire point count)

image

by the way how does [Cloud2CloudDistance(cloud1,cloud2)] behave if the process fails ? does it return an error , or should we use it like below example to avoid error in the console (if the C2C computation doesn't give any result ?)

if cc.DistanceComputationTools.computeApproxCloud2CloudDistance(cloud2ref, cloud3): raise RuntimeError

antoinebio commented 7 months ago

hi @prascle not sure what's going wrong but I noticed different results between CC GUI and CloudComPy

with that example (2 closed BBox with limited overlap)

image

I tested approximate distance , here is what CloudCompPy returns image

and here is what CC GUI returns after rough C2C selection image

image

prascle commented 7 months ago

Hello, Regarding your last message, note that the min, max and mean distances are the same, cloudComPy provides the variance which is the square of the standard deviation, and the maximum error depends on the level of the octree and the cloud (perhaps in your example, the reference cloud and the compared cloud are swapped between the script and the GUI). Regarding the previous post from 2 weeks ago, the "Top view" case can probably be solved with an octree level of 2 or 3 maximum in computeApproxCloud2CloudDistance. For the case of the slight overlap, I don't know, it's more complex... The main reason for errors in algorithms is lack of memory.

Paul