Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get a contour (x,y) coordinates of a shape in an image with python

I need to get a matrix with the coordinates (x,y) of the contour of the following image with python.

enter image description here

I try it with opencv canny detector and find contours but I get a lot of contours and I don't know how to get the one I want.

import numpy as np
from matplotlib import pyplot as plt
import cv2
#from skimage import measure, feature, io
#from skimage import img_as_ubyte

x1 = 330
xf = 690
y1 = 0
yf = 400

img = cv2.imread('test.tif')
img = img[y1:yf, x1:xf]
edge = cv2.Canny(img, 100, 200)

image, contours, hierarchy = cv2.findContours(edge, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

enter image description here

I just need an array with the (x,y) coordinates of the contour. I think it is in the contours output of cv2.findContours() but I don't find the contour that I want…

I also tried with the matplotlib.pyplot.contour function :

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('test.tif', 0) # read image
img = cv2.threshold(img, 0, 255, cv2.THRESH_OTSU)[1] # threshold image
img = cv2.medianBlur(img, 15)  # remove noise

# skeletonize 
size = np.size(img)  # get number of pixels
skel = np.zeros(img.shape, np.uint8) # create an array of zeros with the same shape as the image and 256 gray levels

element = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3)) # create a structurant element (cross)
done = False

while(not done):
    eroded = cv2.erode(img, element)
    temp = cv2.dilate(eroded, element)
    temp = cv2.subtract(img, temp)
    skel = cv2.bitwise_or(skel, temp)
    img = eroded.copy()
    zeros = size - cv2.countNonZero(img)
    if zeros == size:
        done = True

cs = plt.contour(skel, 1)
p = cs.collections[0].get_paths()[0]
v = p.vertices
x = v[:, 0]
y = v[:, 1]

enter image description here

But I just have closed contours and not the open contour which is going from the left to the right of the image.

Thanks a lot for your answers.

like image 725
razoool Avatar asked Oct 31 '22 16:10

razoool


1 Answers

You almost found the answer to your question. First of all, there is a difference between edge detection and contour detection. Fundamentally, edge detection results in what you call (improperly) "open contour" (i.e. edge) and contour detection results in what you call "closed contour" (i.e. contour).

The Canny edge detection is a popular edge detection algorithm. Since you want to detect the edge in the form of an array with the (x,y) coordinates going from the left to the right of the image, the Canny edge detection is a good idea.

The answer is edge which is not in the wanted format.

import numpy as np
import matplotlib.pyplot as plt
import cv2

img = cv2.imread('test.tif')
edge = cv2.Canny(img, 100, 200)

ans = []
for y in range(0, edge.shape[0]):
    for x in range(0, edge.shape[1]):
        if edge[y, x] != 0:
            ans = ans + [[x, y]]
ans = np.array(ans)

print(ans.shape)
print(ans[0:10, :])

The array ans (shape equal to (n, 2)) stores the (x, y)-coordinate of the n pixels which compose the detected edge. This is the result you are looking for.

Here is an image where I have plotted in white these n pixels:

enter image description here

I hope this will help you.

like image 171
Flabetvibes Avatar answered Nov 10 '22 15:11

Flabetvibes