Reputation: 603
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")
Upvotes: 3
Views: 11692
Reputation: 2841
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:
Upvotes: 7
Reputation: 21243
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)
Upvotes: 2