Circle with cut off edges
SCooil
I am trying to figure out the diameter of a circle, the problem is that some of the edges of the circle have been cut by a rectangle (see attached wave "mask.ibw").
I have tried to use imageanalyzeparticle, with the "/E" flag but in this case the fitted circle must have the same area as the particle itself. Here however the circle needs to have a larger area than the particle as it needs to include the area of the cut off edges.
Any help would be greatly appreciated. Thanks in advance.
Depends on some assumptions you are willing to make. From your image, you could use Maximum X of particle - minimum X of particle as the diameter. Not a general solution, but it works on your test case. The requirement would be one particle with at least a diameter aligned to one axis in the field of view.
Andy
December 5, 2015 at 11:57 am - Permalink
Wouldn't this only work if the circle was centred in the rectangle?
Cheers
December 6, 2015 at 12:55 am - Permalink
Andy
December 6, 2015 at 11:38 am - Permalink
My solution is brute force and inelegant, but it appears to work. The idea is to compute the distance between all pairs of points on the boundary of the figure. If the figure includes a pair of points on a diameter, then the maximum of all the computed distances will be the diameter. If the figure doesn't include a diameter, this method will fail.
I include two variations: one where you have already used
ImageAnalyzeParticles
to get the pair of xy waves describing the figure boundary and a second where you begin with the binarized figure.This method gives a diameter of 1654.21. My testing shows that a circle with the calculated diameter provides a good fit to your input mask wave.
I look forward to seeing other replies with simple and beautiful solutions.
Hope this helps.
Jeff
Method 1 (starting with boundary waves)
//the boundary of the partial circle.
//If starting from and image, use ImageAnalyze particles to get the x and y boundary
//waves (W_BoundaryX and W_BoundaryY) for the object.
Function GetDistanceFromBoundary(wX, wY)
Wave wX
Wave wY
Variable vNumElements
Variable vIndex_i
Variable vIndex_j
Variable vIndex_d
Variable vX
Variable vY
Variable vDiameter
Variable vTest
vNumElements = DimSize(wX, 0 )
Make/FREE /N=(vNumElements^2) wDistance
Make/FREE /N=(vNumElements^2) wNumberOfMax
for( vIndex_i = 0; vIndex_i < vNumElements; vIndex_i += 1 )
vX = wX[vIndex_i]
vY = wY[vIndex_i]
for( vIndex_j = 0; vIndex_j < vNumElements; vIndex_j += 1 )
vIndex_d = vIndex_i * vNumElements + vIndex_j
wDistance[vIndex_d] = sqrt( (wX[vIndex_j] - vX) ^2 + (wY[vIndex_j] - vY) ^2 )
endfor
endfor
vDiameter = wavemax(wDistance)
vTest = floor(vDiameter)
print vDiameter, vTest
wNumberOfMax = wDistance > vTest ? 1 : 0
print sum(wNumberOfMax)
print "done"
End
Method 2 (starting with binarized figure)
//The source image wave must be binary, i.e., an unsigned char format where the
//particles are designated by 0 and the background by 255.
Function GetDistanceFromImage(wParticle)
Wave wParticle
imageanalyzeparticles/W stats wParticle
Wave wX = W_BoundaryX
Wave wY = W_BoundaryY
Variable vNumElements
Variable vIndex_i
Variable vIndex_j
Variable vIndex_d
Variable vX
Variable vY
Variable vDiameter
Variable vTest
vNumElements = DimSize(wX, 0 )
Make/FREE /N=(vNumElements^2) wDistance
Make/FREE /N=(vNumElements^2) wNumberOfMax
for( vIndex_i = 0; vIndex_i < vNumElements; vIndex_i += 1 )
vX = wX[vIndex_i]
vY = wY[vIndex_i]
for( vIndex_j = 0; vIndex_j < vNumElements; vIndex_j += 1 )
vIndex_d = vIndex_i * vNumElements + vIndex_j
wDistance[vIndex_d] = sqrt( (wX[vIndex_j] - vX) ^2 + (wY[vIndex_j] - vY) ^2 )
endfor
endfor
vDiameter = wavemax(wDistance)
vTest = floor(vDiameter)
print vDiameter, vTest
wNumberOfMax = wDistance > vTest ? 1 : 0
print sum(wNumberOfMax)
print "done"
End
December 7, 2015 at 06:37 am - Permalink
Jeff is correct, i miss read the image a bit. An alternative solution:
1. Find the edge points
2. Discard all the ones that are on the image boundary, 1st or last row and first or last column.
3. For each row with 2 points, then calculate the average which should lie on a diameter.
4. Repeat for the columns with 2 points also lying on a diameter.
You can fit the lines and find the intersection which will be the center.
From that point you can calculate the distance to any point on edge detected to get the radius. You can do it over all the found edge points and take an average to get the benefit of statistics.
Andy
December 7, 2015 at 09:46 am - Permalink