How to close a path along a path rather than an edge - OpenCV

Tl; DR: how to measure the area enclosed by a contour, not just the contour line itself

I want to find the outline of an object in the image below and have a code that works most of the time. Original image

Threshold and additive threshold do not work reliably as ligation changes. I use Canny's edge detection and check the area to make sure I found the correct path. However, at times, when there is a gap that cannot be closed by the morphological closure, the shape is correct, but the area is a contour line and not the entire object.

Canny contour output

I usually use convexHull as it returns an outline around the object. However, in this case, the object curves inward along the top and convex vertices are no longer a good approximation of area.

Contour after Convex Hull

I tried using approxPolyDP , but the area returned is a contour line, not an object.

How can I get approxPolyDP to return a similar closed path around the object as the convex function does?

Code to illustrate this using the above image:

import cv2
img = cv2.imread('Img_0.jpg',0)
cv2.imshow('Original', img)

edges = cv2.Canny(img,50,150) 
cv2.imshow('Canny', edges)

contours, hierarchy = cv2.findContours(edges,cv2.cv.CV_RETR_EXTERNAL,cv2.cv.CV_CHAIN_APPROX_NONE)

cnt = contours[1] #I have a function to do this but for simplicity here by hand

M = cv2.moments(cnt) 
print('Area = %f \t' %M['m00'], end="")

cntHull = cv2.convexHull(cnt, returnPoints=True)
cntPoly=cv2.approxPolyDP(cnt, epsilon=1, closed=True)
MHull = cv2.moments(cntHull)
MPoly = cv2.moments(cntPoly)
print('Area after Convec Hull = %f \t Area after apporxPoly = %f \n' %(MHull['m00'], MPoly['m00']), end="")

x, y =img.shape
size = (w, h, channels) = (x, y, 1)
canvas = np.zeros(size, np.uint8)
cv2.drawContours(canvas, cnt, -1, 255)
cv2.imshow('Contour', canvas)

canvas = np.zeros(size, np.uint8)
cv2.drawContours(canvas, cntHull, -1, 255)
cv2.imshow('Hull', canvas)

canvas = np.zeros(size, np.uint8)
cv2.drawContours(canvas, cntPoly, -1, 255)
cv2.imshow('Poly', canvas)

      

Exiting the code

Area = 24.500000    Area after Convec Hull = 3960.500000     Area after apporxPoly = 29.500000 

      

+3


source to share


1 answer


Here's a very promising ppt from geosensor.net where several algorithms are discussed. My recommendation would be to use the limited radius swing arm method.

Another completely untested wall idea I have is to scan through the image by row and column (more directions increase accuracy) and color in areas between line intersections:



          _______
         /-------\
        /---------\
--------+---------+------ (fill between 2 intersections)     
        |         |
        |
--------+---------------- (no fill between single intersection)
         \
          -------

      

the maximum error will decrease as the number of lines scanned increases (more than 90 and 45 degrees). Getting the final area will be as easy as counting the pixels.

+1


source







All Articles