Create masks that partition an image from a voronoi tesselation

Hello,

I am using Igor to process images of crystal lattices. The image contain projections of atomic columns of a given lattice. I identify the atomic columns using ImageAnalyzeParticles. Then, I pass the XY positions of the centers of the identified particles to ImageTransform voronoi to compute a voronoi tesselation of the image. I would like to use this tesselation to compute statistics for a region around each atomic column.

How can I link each polygon from the tesselation to the atomic columns it encompasses? I have not found anything in the documentation on this.

I've attached an example where I've overlaid the centers of the atomic columns (blue dots) and the voronoi tesselation (red vertices) on the original image.

Thank you for your help.
It seems to me that the only ingredient that you are missing is how to convert a polygon into a mask. One approach could be to use ImageBoundaryToMask. Here is an example:
make/n=(10,3) ddd=enoise(5)
•ddd[][2]=0ImageTransform voronoi ddd
•DisplayappendToGraph ddd[][1] vs ddd[][0]ModifyGraph mode=3,marker=19appendToGraph M_VoronoiEdges[][1] vs M_VoronoiEdges[][0]MatrixOP/o xxx=col(M_VoronoiEdges,0)MatrixOP/o yyy=col(M_VoronoiEdges,1)make/n=(500,500) scalingwave
•SetScale/I x -10,10,"", scalingWave
•SetScale/I y -10,10,"", scalingwave
// Now iterate over the "seeds" from the original triplet wave.  For example, picking up row 5:ImageBoundaryToMask xwave=xxx,ywave=yyy,scalingWave=scalingwave,seedx=ddd[5][0],seedy=ddd[5][1],height=500,width=500


I hope this helps,

A.G.
WaveMetrics, Inc.

This is great!

However it seems that in some occasion the "seed" may not be within the boundary so an error occurs

"error: Bad seed pixel specification."

Here is a minimal code that may reproduce the error if run multiple times

Function Test_Voronoi()
    variable Cr=10,np =100,size=1000,ii
    Make/o/n=(np,3) Vor
    vor= enoise(Cr)
    vor[][2]=0
 
    ImageTransform voronoi vor
    wave M_VoronoiEdges
    MatrixOP/o xxx=col(M_VoronoiEdges,0)
    MatrixOP/o yyy=col(M_VoronoiEdges,1)
    make/n=(size,size)/o/d scalingwave, MaskVor,Bounds
    SetScale/I x -Cr ,Cr ,"", scalingWave, MaskVor
    SetScale/I y -Cr ,Cr ,"", scalingwave, MaskVor
 
    ii=0
    do
        wavestats/q  MaskVor
 
        ImageBoundaryToMask xwave=xxx,ywave=yyy,scalingWave=scalingwave,seedx=vor[ii][0],seedy=vor[ii][1],height=1000,width=1000
 
        ii+=1
    while (  ii<np )
 
end

 

Is there a straightforward test should be implemented on seedx and seedy to avoid the error ?

 

1.  It is not obvious to me what is the purpose of executing WaveStats inside the loop.  You have 1e6 points so unless you have a good reason, I'd skip that.

2.  To figure out what is happening in any particular run you can execute:

display vor[][1] vs vor[][0]ModifyGraph mode=3,marker=19appendToGraph m_voronoiEdges[][1] vs m_voronoiEdges[][0]ModifyGraph rgb(M_VoronoiEdges)=(0,0,65535)

and then expand the display until you can inspect the details.

In a normal application the input is rarely a uniform noise so that points are unlikely to "overlap".  Here "overlap" is in quotes because in practice there is a minimum distance that is required between the seed and the boundary.  Also, the operation was originally designed to work with integer pixels.  When you apply wave scaling the code has to internally compute the corresponding pixels (some rounding is involved) which, as you can see here, leads to seeds falling on the boundary.

Depending on your goal in this calculation you may want to apply a completely different wave scaling; increasing the number of pixels in the mask improves the resolution and accuracy of the results.

AG