How can I use OpenCV to find the center of mass. [closed]
I am working on an inspection process that requires me to precisely locate features in the field of view. Specifically I am finding features on a circuit board which could include finding tooling holes and solder pads. Our vision setup gives us a per-pixel size of ~100 microns.
At that resolution there is a great deal of material clutter as solder pads leak beyond their intended circumference, and tooling holes have microscopic burrs which can distort.
The question is about a tooling hole where a couple of burrs are causing my centroid calculation to result in a center point that does not correspond with the center of mass of the object. I have attached the raw image and a processed image that shows the detected contour, the calculated centroid and the circle based on the area of the contour centered at the centroid.
Looking at the output I would expect the circle to be shifted much further to the left as the omitted pieces of the contour look much larger than the extra pieces to right.
Raw Capture
Processed Image
static void Process( string filename ) {
Mat raw;
raw = Cv2.ImRead( filename, ImreadModes.GrayScale );
Mat threshold = new Mat();
Cv2.Threshold( raw, threshold, 190, 255, ThresholdTypes.Otsu );
Point[][] contours;
HierarchyIndex[] hierarchyIndexes;
Cv2.FindContours( threshold, out contours, out hierarchyIndexes, RetrievalModes.List, ContourApproximationModes.ApproxSimple );
Mat rawColor = new Mat();
Cv2.CvtColor( raw, rawColor, ColorConversionCodes.GRAY2RGB );
if ( contours.Length != 0 ) {
var contourIndex = 0;
while ( contourIndex >= 0 ) {
var area = Cv2.ContourArea( contours[ contourIndex ] );
Debug.Print( $"{contourIndex} points: {contours[ contourIndex ].Length}, area: {area}" );
//only look for features that have a given area
if ( area < 1100000 && area > 400000.0 ) {
//if ( area < 1100000 && area > 60000.0 ) {
Cv2.DrawContours( rawColor, contours, contourIndex, new Scalar( 255, 0, 0 ), 10, LineTypes.Link8, hierarchyIndexes, int.MaxValue );
Point centroid = Centroid( contours[ contourIndex ] );
Cv2.Circle( rawColor, centroid, 20, new Scalar( 0, 0, 255 ), 3 );
var radius = Math.Sqrt( area / Math.PI );
Cv2.Circle( rawColor, centroid, (int)radius, new Scalar( 0, 0, 255 ), thickness: 3 );
}
contourIndex = hierarchyIndexes[ contourIndex ].Next;
}
}
}
static Point Centroid ( Point[] knots ) {
Point center = new Point();
int sumofx = 0, sumofy = 0;
for ( int i = 0; i < knots.Length; i++ ) {
sumofx = sumofx + knots[ i ].X;
sumofy = sumofy + knots[ i ].Y;
}
center.X = sumofx / knots.Length;
center.Y = sumofy / knots.Length;
return center;
}
please add the code, you're trying with
OP updated with code.
Take a look at the moments function. m10/m00 is x, and m01/m00 is y, unless they're backwards. You should test that before you believe me.
"unless they're backwards" -- you're also using an unsupported 3rdparty wrapper, and we have no idea, what they're doing !
Is that not Java? That looks like the normal OpenCV Java to me.
@Tetragramm, no. opencv's java bindings do not have a Cv2 prefix
i rather guess: some (unsupported) c# binding
@webatxcent , -- do you realize, what kind of trouble you're in ?