简体   繁体   中英

Find contour and boundary to obtain points inside image OpenCV Python

I have a code to draw contour of object in a image and then draw a rectangle around them. i need to find widest diameter in my shape (two point) witch is straight horizontal line Now I need to find the points(coordinates of the pixels) that are inside the boundary of the object.

heres my code:

图片供参考

class App:
    def __init__(self, window, window_title, image_path="ex.jpg"):
        self.window = window
        self.window.title(window_title)

        # Load an image using OpenCV
        self.cv_img = cv2.cvtColor(cv2.imread(image_path), cv2.COLOR_BGR2RGB)

        # Get the image dimensions (OpenCV stores image data as NumPy ndarray)
        self.height, self.width, no_channels = self.cv_img.shape

        # Create a canvas that can fit the above image
        self.canvas = tkinter.Canvas(window, width = self.width, height = self.height)
        self.canvas.pack()

        # Use PIL (Pillow) to convert the NumPy ndarray to a PhotoImage
        self.photo = PIL.ImageTk.PhotoImage(image = PIL.Image.fromarray(self.cv_img))

        # Add a PhotoImage to the Canvas
        self.canvas.create_image(0, 0, image=self.photo, anchor=tkinter.NW)

        # Button that lets the user blur the image
        self.btn_blur=tkinter.Button(window, text="Blur", width=25, command=self.blur_image)
        self.btn_blur.pack(anchor=tkinter.CENTER, expand=True)

        # Button that lets the user edeged the image
        self.btn_blur=tkinter.Button(window, text="edged", width=25, command=self.edged_image)
        self.btn_blur.pack(anchor=tkinter.CENTER, expand=True)

        # Button that lets the user edeged the image
        self.btn_blur=tkinter.Button(window, text="draw box", width=25, command=self.draw_box)
        self.btn_blur.pack(anchor=tkinter.CENTER, expand=True)

        self.window.mainloop()

    # Callback for the "Blur" button
    def blur_image(self):
        self.cv_img = cv2.blur(self.cv_img, (3, 3))
        self.photo = PIL.ImageTk.PhotoImage(image = PIL.Image.fromarray(self.cv_img))
        self.canvas.create_image(0, 0, image=self.photo, anchor=tkinter.NW)

    # Callback for the "edged" button
    def edged_image(self):
        #edeged image
        self.cv_img=cv2.Canny(self.cv_img,50,180)
        self.cv_img = cv2.dilate(self.cv_img, None, iterations=1)
        self.cv_img = cv2.erode(self.cv_img, None, iterations=1)
        self.photo = PIL.ImageTk.PhotoImage(image = PIL.Image.fromarray(self.cv_img))
        self.canvas.create_image(0, 0, image=self.photo, anchor=tkinter.NW)

    # Callback for the "draw contours" button
    def draw_box(self):        
        #draw contour
        cnts = cv2.findContours(self.cv_img.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
        cnts = cnts[0] if imutils.is_cv2() else cnts[1]
        #draw box
        for c in cnts:
            self.cv_img = cv2.drawContours(self.cv_img, [c], 0, (0,255,0), 3)
            x,y,w,h = cv2.boundingRect(c)
            self.cv_img = cv2.rectangle(self.cv_img,(x,y),(x+w,y+h),(0,255,0),2)

#Create a window and pass it to the Application object
App(tkinter.Tk(), "morteza app")

You can try to find extreme points (left, right, and top in your case). You can then calculate the distance from extreme left to extreme right with the formula for calculating distance between two points d=sqrt((x2-x1)^2 + (y2-y1)^2). You can even find the center of the line and calculate the distance between the center of the line and extreme top point if you would like with the same principle. Here is an example code:

import numpy as np
import cv2
import imutils

img = cv2.imread('bulb.png')


gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 240, 255, cv2.THRESH_BINARY)
cv2.bitwise_not(thresh, thresh)

cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL,
                cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0]
c = max(cnts, key=cv2.contourArea)

left = tuple(c[c[:, :, 0].argmin()][0])
right = tuple(c[c[:, :, 0].argmax()][0])

distance = np.sqrt( (right[0] - left[0])**2 + (right[1] - left[1])**2 )

x,y,w,h = cv2.boundingRect(c)

centx = np.sqrt( ((right[0] + left[0])**2)/4)
centy = np.sqrt( ((right[1] + left[1])**2)/4 )
print(centx, centy)

font = cv2.FONT_HERSHEY_SIMPLEX
cv2.circle(img, left, 5, (0, 0, 255), -1)
cv2.circle(img, right, 5, (0, 0, 255), -1)
cv2.circle(img, (int(centx), int(centy)), 5, (0, 0, 255), -1)
cv2.line(img, left, right, (255,0,0), 2)
cv2.drawContours(img, [c], -1, (0,255,0), 2)
cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
cv2.putText(img,'Distance: '+str(distance),(10,30), font, 1, (0,0,0),2, cv2.LINE_AA)
cv2.imshow('img', img)
cv2.imwrite('bulbresult.png', img)

Result:

在此处输入图片说明

You can find the four extreme points in a contour the following way:

First, finding contours for a given image. I considered the following image for this illustration:

在此处输入图片说明

(Skipping the contour finding section)

cnt = contours[0]    #--- since there is only one contour in the image
leftmost = tuple(cnt[cnt[:,:,0].argmin()][0])
rightmost = tuple(cnt[cnt[:,:,0].argmax()][0])
topmost = tuple(cnt[cnt[:,:,1].argmin()][0])
bottommost = tuple(cnt[cnt[:,:,1].argmax()][0])

#--- drawing these points on the image ----
cv2.circle(im2, leftmost, 6, (0, 0, 255), -1)
cv2.circle(im2, rightmost, 6, (0, 0, 255), -1)
cv2.circle(im2, topmost, 6, (0, 255, 0), -1)
cv2.circle(im2, bottommost, 6, (0, 255, 0), -1)
cv2.imshow('final', im2)

在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM