Mah
Mah

Reputation: 105

Getting a centre of an irregular shape

I have a irregular shape like below:

enter image description here

I need to get the centre of that white area, I just tried with contour in openCV like below

img=cv.imread('mypic',0)
ret,thresh = cv.threshold(img,127,255,cv.THRESH_BINARY_INV)
cnts = cv.findContours(thresh.copy(), cv.RETR_EXTERNAL,
    cv.CHAIN_APPROX_SIMPLE)
cnt = contours[0]
x,y,w,h = cv.boundingRect(cnt)
res_img = cv.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
cv.imwrite('output.png',res_img)

But those cnts doeesn't give me very good results, as you can see the original image and its two small black point below the picture. Can someone point me to a good solution to get a centre of an irregular shape like above?

enter image description here

Upvotes: 3

Views: 2115

Answers (3)

Carlos Melus
Carlos Melus

Reputation: 1552

One can think of the centroid calculated using the image moments as the "mass" center of the object in relation to the pixel intensity. Depending on the actual shape of the object it may not even be inside the object. An alternative would be calculating the center of the bounding circle:

thresh = cv2.morphologyEx(thresh, cv2.MORPH_DILATE, np.ones((3, 3)))
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = [c for c in contours if cv2.contourArea(c) > 100]
(x, y), r = cv2.minEnclosingCircle(contours[0])
output = thresh.copy()
cv2.circle(output, (int(x), int(y)), 3, (0, 0, 0), -1)
cv2.putText(output, f"{(int(x), int(y))}", (int(x-50), int(y-10)), cv2.FONT_HERSHEY_PLAIN, 1, (0, 0, 0), 1)
cv2.circle(output, (int(x), int(y)), int(r), (255, 0, 0), 2)

The output of that code looks like this: enter image description here

Upvotes: 4

stateMachine
stateMachine

Reputation: 5815

As I suggested, perform an erosion followed by dilation (an opening operation) on the binary image, then compute central moments and use this information to calculate the centroid. These are the steps:

  1. Get a binary image from the input via Otsu's Thresholding
  2. Compute central moments using cv2.moments
  3. Compute the blob's centroid using the previous information

Let's see the code:

import cv2
import numpy as np

# Set image path
path = "C:/opencvImages/"
fileName = "pn43H.png"

# Read Input image
inputImage = cv2.imread(path+fileName)

# Convert BGR to grayscale:
grayscaleImage = cv2.cvtColor(inputImage, cv2.COLOR_BGR2GRAY)

# Threshold via Otsu + bias adjustment:
threshValue, binaryImage = cv2.threshold(grayscaleImage, 0, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)

This is the binary image you get. Notice the small noise:

The opening operation will get rid of the smalls blobs. A rectangular structuring element will suffice, let's use 3 iterations:

# Apply an erosion + dilation to get rid of small noise:

# Set kernel (structuring element) size:
kernelSize = 3

# Set operation iterations:
opIterations = 3

# Get the structuring element:
maxKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (kernelSize, kernelSize))

# Perform closing:
openingImage = cv2.morphologyEx(binaryImage, cv2.MORPH_OPEN, maxKernel, None, None, opIterations, cv2.BORDER_REFLECT101)

This is the filtered image:

Now, compute the central moments and then the blob's centroid:

# Calculate the moments
imageMoments = cv2.moments(openingImage)

# Compute centroid
cx = int(imageMoments['m10']/imageMoments['m00'])
cy = int(imageMoments['m01']/imageMoments['m00'])

# Print the point:
print("Cx: "+str(cx))
print("Cy: "+str(cy))

Additionally, let's draw this point onto the binary image to check out the results:

# Draw centroid onto BGR image:
bgrImage = cv2.cvtColor(binaryImage, cv2.COLOR_GRAY2BGR)
bgrImage = cv2.line(bgrImage, (cx,cy), (cx,cy), (0,255,0), 10)

This is the result:

Upvotes: 4

JVod
JVod

Reputation: 151

You may want to try ConnectedComponentsWithStats function. This returns centroids, areas and bounding box parameters. Also blur and morphology(dilate/erode) helps a lot with noice, as noted above. If you're generous enough with erode, you`re gonna get almost no stray pixels after processing.

Upvotes: 2

Related Questions