kathy
kathy

Reputation: 339

Find the center line between object's edges

enter image description here

Today I am trying to identify the edge of an object.

I got a great result by doing this.

import cv2
img = cv2.imread("0.png")
img2 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img2 = cv2.equalizeHist(img2)
img2 = cv2.GaussianBlur(img2, (7, 7), 0)
edges = cv2.Canny(img2, 180, 300)
im2, contours, hierarchy = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(img, contours, -1, (0, 255, 0), 1)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

and the image looks like: (it's a welding's x-ray) image with edges

My ultimate goal is to find the center line between the edges, (the collection of (MaxY+MinY)/2 on each X) the ideal result should look like this: (sorry for the bad hand drawing)

image with center line

Could anyone let me know how should I do this? Thank you very much.

Upvotes: 3

Views: 5413

Answers (1)

kavko
kavko

Reputation: 2831

First of all you should prepare your image so that you can found your one contour (threshold, histogram equalization etc.). The contour returns you a set of (x,y) coordinates that represent the contour so for the first step you should seperate the upper edge from the bottom (split it on half). In my example I made it complementary to momements of the contour but note that this will not work for curved lines! You will have to make an algorithm to divide upper side and down side. Once you have done this you can make two list, containing one element per x coordinate. Then simply calculate the midle and make a point on the image.

Example code:

import cv2
import numpy as np

img = cv2.imread('centerline.png')
mask = np.zeros((img.shape[:2]), np.uint8)
h2, w2 = img.shape[:2]

gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
equ = cv2.equalizeHist(gray)

_, thresh = cv2.threshold(equ,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
kernel = np.ones((5,5),np.uint8)
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)

_, contours, hierarchy = cv2.findContours(opening,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
for cnt in contours:
    x,y,w,h = cv2.boundingRect(cnt)
    print(h, w)
    if h < 30 and w > 270:
        cv2.drawContours(mask, [cnt], 0, (255,255,255), -1)

res = cv2.bitwise_and(img, img, mask=mask)
gray = cv2.cvtColor(res,cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
blur = cv2.GaussianBlur(thresh,(5,5),0)
_, contours, hierarchy = cv2.findContours(blur,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cnt = max(contours, key=cv2.contourArea)

M = cv2.moments(cnt)
cy = int(M['m01']/M['m00'])

mask = np.zeros((img.shape[:2]), np.uint8)
cv2.drawContours(mask, [cnt], 0, (255,255,255), -1)

up = []
down = []

for i in cnt:
    x = i[0][0]
    y = i[0][1]
    if x == 0:
        pass
    elif x == w2:
        pass
    else:
        if y > cy:
            down.append(tuple([x,y]))
        elif y < cy:
            up.append(tuple([x,y]))
        else:
            pass


up.sort(key = lambda x: x[0])
down.sort(key = lambda x: x[0])

up_1 = []
down_1 = []

for i in range(0, len(up)-1):
    if up[i][0] != up[i+1][0]:
        up_1.append(up[i])
    else:
        pass

for i in range(0, len(down)-1):
    if down[i][0] != down[i+1][0]:
        down_1.append(down[i])
    else:
        pass

lines = zip(up_1, down_1)

for i in lines:
    x1 = i[0][0]
    y1 = i[0][1]
    x2 = i[1][0]
    y2 = i[1][1]
    middle = np.sqrt(((x2-x1)**2)+((y2-y1)**2))
    cv2.circle(img, (x1, y1+int(middle/2)), 1, (0,0,255), -1)    

cv2.imshow('img', img)

Result:

enter image description here

Upvotes: 7

Related Questions