How to get x,y position of contours in Python OpenCV - python

I'm trying to get x and y positions of contours from the following image, but I messed up.
the image
I just need to find x and y positions of contours or center of the contours.
The results will be something like the following as I manually look up their positions from GIMP.
290, 210
982, 190
570, 478
I believe it can be done with cv2.findContours method, but I'm really out of ideas right now.
-Offtopic-
I will use these values in setting cursor position usingwin32api.SetCursorPos((xposition,yposition))
Thanks

You can refer here
Find Co-ordinates of Contours using OpenCV | Python
# Python code to find the co-ordinates of
# the contours detected in an image.
import numpy as np
import cv2
# Reading image
font = cv2.FONT_HERSHEY_COMPLEX
img2 = cv2.imread('test.jpg', cv2.IMREAD_COLOR)
# Reading same image in another
# variable and converting to gray scale.
img = cv2.imread('test.jpg', cv2.IMREAD_GRAYSCALE)
# Converting image to a binary image
# ( black and white only image).
_, threshold = cv2.threshold(img, 110, 255, cv2.THRESH_BINARY)
# Detecting contours in image.
contours, _= cv2.findContours(threshold, cv2.RETR_TREE,
cv2.CHAIN_APPROX_SIMPLE)
# Going through every contours found in the image.
for cnt in contours :
approx = cv2.approxPolyDP(cnt, 0.009 * cv2.arcLength(cnt, True), True)
# draws boundary of contours.
cv2.drawContours(img2, [approx], 0, (0, 0, 255), 5)
# Used to flatted the array containing
# the co-ordinates of the vertices.
n = approx.ravel()
i = 0
for j in n :
if(i % 2 == 0):
x = n[i]
y = n[i + 1]
# String containing the co-ordinates.
string = str(x) + " " + str(y)
if(i == 0):
# text on topmost co-ordinate.
cv2.putText(img2, "Arrow tip", (x, y),
font, 0.5, (255, 0, 0))
else:
# text on remaining co-ordinates.
cv2.putText(img2, string, (x, y),
font, 0.5, (0, 255, 0))
i = i + 1
# Showing the final image.
cv2.imshow('image2', img2)
# Exiting the window if 'q' is pressed on the keyboard.
if cv2.waitKey(0) & 0xFF == ord('q'):
cv2.destroyAllWindows()

Indeed, you can do that with findContours. Since you have your contours there are several options:
Calculate enclosing rectangle and take e.g. the center point.
Calculate moments and take the centroid
Fit minimum enclosing circle and take the center
and so on...
Here are some examples of what you can do with your contours, including the options above.

First you need to find contours, draw a bounding box and then take the x and y from there. I hope this helps
import numpy as np
import cv2
im = cv2.imread('ctBI9.png')
imgray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(imgray, 127, 255, 0)
im2, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
for c in contours:
if cv2.contourArea(c) <= 50 :
continue
x,y,w,h = cv2.boundingRect(c)
cv2.rectangle(im, (x, y), (x + w, y + h), (0, 255,0), 2)
center = (x,y)
print (center)
while True:
cv2.imshow('test',im)
if cv2.waitKey(20) & 0xFF == 27:
break
cv2.destroyAllWindows()
result is something like this
(93, 746)
(1174, 738)
(147, 736)
(395, 729)
(506, 404)
(240, 168)
(918, 130)

Related

detect coordinates of black squares and crop image based on these coordinates

I am trying to crop this image by detecting coordinates of pitch black squares on the upper side, tick marked in this image one I detect coordinates I need to crop image in straight lines to these coordinates as mentioned in this image and only keep inner area. I have tried following code to detect coordinates of contours
import numpy as np
import cv2
# Reading image
font = cv2.FONT_HERSHEY_COMPLEX
img2 = cv2.imread("img.jpg", cv2.IMREAD_COLOR)
# Reading same image in another
# variable and converting to gray scale.
img = cv2.imread("img.jpg", cv2.IMREAD_GRAYSCALE)
# Converting image to a binary image
# ( black and white only image).
_, threshold = cv2.threshold(img, 110, 255, cv2.THRESH_BINARY)
# Detecting contours in image.
contours, _= cv2.findContours(threshold, cv2.RETR_TREE,
cv2.CHAIN_APPROX_SIMPLE)
# Going through every contours found in the image.
for cnt in contours :
approx = cv2.approxPolyDP(cnt, 0.009 * cv2.arcLength(cnt, True), True)
# draws boundary of contours.
cv2.drawContours(img2, [approx], 0, (0, 0, 255), 5)
# Used to flatted the array containing
# the co-ordinates of the vertices.
n = approx.ravel()
i = 0
for j in n :
if(i % 2 == 0):
x = n[i]
y = n[i + 1]
# String containing the co-ordinates.
string = str(x) + " " + str(y)
if(i == 0):
# text on topmost co-ordinate.
cv2.putText(img2, "Arrow tip", (x, y),
font, 0.5, (255, 0, 0))
else:
# text on remaining co-ordinates.
cv2.putText(img2, string, (x, y),
font, 0.5, (0, 255, 0))
i = i + 1
cv2.imwrite('img.jpg', img2)
but it isn't detecting coordinates properly as you can see here can someone suggest me what am I doing wrong here? Thank you

Detecting circle pattern in image using Python & OpenCV

I've got images like this one:
I need to detect the center of this circular element:
(More precisely - I'm looking for the midpoint of the circular element)
Currently my code detect the mold (the plastic circle that holds the circular element) and select the rectangle ROI to focus the image into the relevant area:
import cv2
import imutils
import numpy as np
if __name__ == "__main__":
image = cv2.imread('Dart - Overview Image - with Film.bmp')
img = imutils.resize(image, width=700)
image = img
output = image.copy()
roi = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# cv2.imshow("Gray", gray)
# cv2.waitKey(0)
# detect circles in the image
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1.2, 100)
# ensure at least some circles were found
if circles is not None:
# convert the (x, y) coordinates and radius of the circles to integers
circles = np.round(circles[0, :]).astype("int")
# loop over the (x, y) coordinates and radius of the circles
for (x, y, r) in circles:
# draw the circle in the output image, then draw a rectangle
# corresponding to the center of the circle
cv2.circle(output, (x, y), r, (0, 255, 0), 2)
cv2.rectangle(output, (x - 2, y - 2), (x + 2, y + 2), (0, 128, 255), -1)
roi = roi[y - r: y + r, x - r: x + r]
cv2.imshow("img", roi)
cv2.waitKey(0)
This will show this image:
Now, I'm trying to find the midpoint of the circular element inside this ROI image by detecting the circular element but It's challenged for me, I've try this methods:
gray_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray_roi, (3, 3), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_OTSU + cv2.THRESH_BINARY_INV)[1]
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)
for c in cnts:
(x, y), radius = cv2.minEnclosingCircle(c)
cv2.circle(roi, (int(x), int(y)), int(radius), (35, 255, 12), 3)
cv2.circle(roi, (int(x), int(y)), 1, (35, 255, 12), 2)
print(x, y)
break
# Find Canny edges
edged = cv2.Canny(roi, 30, 121, apertureSize=3, L2gradient=True)
cv2.waitKey(0)
# Finding Contours
# Use a copy of the image e.g. edged.copy()
# since findContours alters the image
contours, hierarchy = cv2.findContours(edged,
cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
cv2.imshow('Canny Edges After Contouring', edged)
cv2.waitKey(0)
And got this output:
I've also tried to change the threshold parameters in the cv2.Canny function but it's didn't give me better results.
Thanks a lot!

Using mask of image to find contours openCV

I have the task of find the contours of a red boundary drawn on a site location map. From the contours detected, I need to find the coordinates and save these to an array. I am able to filter for the red boundary and draw the contours, however I don't know how use this new image in my coordinate extraction. As a temporary solution I have screenshotted the mask generated, saved this, then in a new program have used this screenshot to find the coordinates. Is there a way to join all this code together?
This is the code for drawing the contours:
import cv2
img = cv2.imread(r'C:\Users\abbys\OneDrive\Pictures\agileapp\cornwall_cropped.png')
img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# Gen lower mask (0-5) and upper mask (175-180) of RED
mask1 = cv2.inRange(img_hsv, (0,50,20), (5,255,255))
mask2 = cv2.inRange(img_hsv, (175,50,20), (180,255,255))
# Merge the mask and crop the red regions
mask = cv2.bitwise_or(mask1, mask2 )
cropped = cv2.bitwise_and(img, img, mask=mask)
## Display
cv2.imshow("mask", mask)
cv2.imshow("cropped", cropped)
cv2.waitKey()
This is the code used to extract the coordinates - the image I read in is a screen shot of the 'cropped' image from the above code
# Reading image
font = cv2.FONT_HERSHEY_COMPLEX
img2 = cv2.imread(r'C:\Users\abbys\OneDrive\Pictures\agileapp\cropped.png', cv2.IMREAD_COLOR)
# Reading same image in another
# variable and converting to gray scale.
img = cv2.imread(r'C:\Users\abbys\OneDrive\Pictures\agileapp\cropped.png', cv2.IMREAD_GRAYSCALE)
# Converting image to a binary image
# ( black and white only image).
_, threshold = cv2.threshold(img, 110, 255, cv2.THRESH_BINARY)
# Detecting contours in image.
contours, _= cv2.findContours(threshold, cv2.RETR_LIST,
cv2.CHAIN_APPROX_SIMPLE)
# Going through every contour found in the image.
for cnt in contours :
approx = cv2.approxPolyDP(cnt, 0.009 * cv2.arcLength(cnt, True), True)
# draws boundary of contours.
cv2.drawContours(img2, [approx], 0, (0, 0, 255), 5)
# Used to flatted the array containing
# the co-ordinates of the vertices.
n = approx.ravel()
i = 0
for j in n :
if(i % 2 == 0):
x = n[i]
y = n[i + 1]
# String containing the co-ordinates.
string = str(x) + " " + str(y)
if(i == 0):
# text on topmost co-ordinate.
cv2.putText(img2, "Arrow tip", (x, y),
font, 0.5, (255, 0, 0))
else:
# text on remaining co-ordinates.
cv2.putText(img2, string, (x, y),
font, 0.5, (0, 255, 0))
i = i + 1
# Showing the final image.
cv2.imshow('image2', img2)
# Exiting the window if 'q' is pressed on the keyboard.
if cv2.waitKey(0) & 0xFF == ord('q'):
cv2.destroyAllWindows()

What condition should I use to cut off unnecessary shapes? (not the center of the image!)

I need to find the ellipses in the image with OpenCV. But my program finds both necessary and unnecessary ones. Idea was to separate the unnecessary ones using the condition of hitting the point area:
x_ellipse<(w/2+magic_num) and x_ellipse>(w/2-magic_num) and y_ellipse<(h/2+magic_num) and y_ellipse>(h/2-magic_num)
But the problem is that real center (w/2; h/2) of image is not the center of necessary ellipses. Maybe there is another way to separate or OpenCV has some cool functions that can find center of that I need?
I am only interested in those ellipses that describe only the first 3 light ones
import cv2
import numpy as np
input_image = cv2.imread('test_image_2.bmp')
thresh = cv2.cvtColor(t2, cv2.COLOR_BGR2GRAY)
cv2.imshow('gray', thresh)
thresh = cv2.adaptiveThreshold(thresh, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV, 101, 0)
cv2.imshow('circles', thresh)
#cv2.imwrite('thresh.bmp', thresh)
h, w, c = input_image.shape
#print('width: ', w)
#print('height: ', h)
#print('channel:', c)
contours, hierarchy = cv2.findContours( thresh, cv2.RETR_LIST, cv2.CHAIN_APPROX_TC89_KCOS)
for cnt in contours:
if len(cnt)>5:
ellipse = cv2.fitEllipse(cnt)
#cv2.ellipse(t2,ellipse,(0,0,255),2)
#param = ellipse[1][0]/ellipse[1][1]
#if ellipse[0][0] < (w/2 + 25) and ellipse[0][0] > (w/2 - 25) and ellipse[0][0] < (h/2 + 25) and ellipse[0][0] > (h/2 - 25):
cv2.ellipse(input_image,ellipse,(0,0,255),2)
#else:
#cv2.circle(t2, (int(ellipse[0][0]), int(ellipse[0][1])), 1, (255, 0, 0), -1)
#draw center of image
#cv2.circle(input_image, (int(w/2), int(h/2)), 10, (255, 255, 0), -1)
#if param < 0.88:
#cv2.ellipse(t2,ellipse,(0,0,255),2)
#else:
#cv2.ellipse(t2,ellipse,(0,255,0),2)
#print(ellipse[0])
cv2.imshow('contours', input_image)
cv2.waitKey()
Input image:
Center of image:
All ellipses:

Differentiate between Circles and Radio buttons Opencv python

I have a task to detect Circles and Radio buttons in an Image. For this I tried Hough circles by having different parameters.
Issues: If the circles in the Image are of same radius of Radio buttons both are detected, but in our case it should only detect only one.
Is there a way to differentiate between circles and Radio buttons (when they are not checked).
Right now I am limiting them by Radius with 2 different functions one for circle and one for radio button.
The above code is for circles
circle_contours=[]
# Converting the image Gray scale
gray = cv2.cvtColor(image1, cv2.COLOR_BGR2GRAY)
# Blur the image to reduce noise
img_blur = cv2.medianBlur(gray, 5)
# Apply hough transform on the image
circles = cv2.HoughCircles(img_blur, cv2.HOUGH_GRADIENT, 1,20, param1=50, param2=20,
minRadius=11, maxRadius=21)
# Draw detected circles
if circles is not None:
circles = np.uint16(np.around(circles))
for i in circles[0, :]:
# Draw outer circle
cv2.circle(image1, (i[0], i[1]), i[2], (34, 255, 34), 2)
circle_contours.append(circles)
I have used a similar approach for radio buttons but with different parameters as below.
radio_buttons= cv2.HoughCircles(img_blur, cv2.HOUGH_GRADIENT, 1,20, param1=50, param2=16,
minRadius=9, maxRadius=10)
Original Image
Image 1:
Image 2:
For the Image1 it detects circles correctly and when it is passed to the radio buttons function it also draws circles(Image2) for the inner part of it with a reduced radius which are also detected as radio buttons
In Image3Image3 it has to detect Circle and Radio buttons, where my code is only able to detect circles.
I have also tried using draw contours but it had issues when the Image also has checkboxes.
Is there any other approach or a better way for detection?
Find and draw all the contours in the answer-sheet.
Apply HoughCircles
Step #1: We could start with finding all contours in the given answer-sheet.
contourIdx=-1 means to draw all the contours.
import cv2
import numpy as np
image = cv2.imread('zip_grade_form.png')
# Converting the image Gray scale
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(src=gray, thresh=127, maxval=255, type=0)
contours, hierarchy = cv2.findContours(image=thresh,
mode=cv2.RETR_TREE,
method=cv2.CHAIN_APPROX_SIMPLE)
gray = cv2.drawContours(image=gray, contours=contours, contourIdx=-1,
color=(255, 255, 255), thickness=2)
Result:
From above we can see that all features except circles are removed. We use the findContours method to remove unwanted artifacts.
Step#2: Apply HoughCircles. The same code you wrote on the question. Result:
Code:
import cv2
import numpy as np
image = cv2.imread('zip_grade_form.png')
# Converting the image Gray scale
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(src=gray, thresh=127, maxval=255, type=0)
contours, hierarchy = cv2.findContours(image=thresh,
mode=cv2.RETR_TREE,
method=cv2.CHAIN_APPROX_SIMPLE)
gray = cv2.drawContours(image=gray, contours=contours, contourIdx=-1,
color=(255, 255, 255), thickness=2)
cv2.imwrite("gray.png", gray)
img_blur = cv2.medianBlur(gray, 5)
circles = cv2.HoughCircles(img_blur, cv2.HOUGH_GRADIENT, 1, 20, param1=50, param2=16,
minRadius=9, maxRadius=10)
circle_contours = []
if circles is not None:
circles = np.uint16(np.around(circles))
for i in circles[0, :]:
# Draw outer circle
cv2.circle(image, (i[0], i[1]), i[2], (108, 105, 255), 2)
circle_contours.append(circles)
cv2.imwrite("circles.png", image)
Update
For detecting check-boxes and radio-buttons you need to calculate the contour-perimeter (p) and the contour-approximation (a). source
We can separate each object using p and a value since each object has a unique p and a values.
For instance, in image-3,
check-box: p= 73 and a = 4
radio-button: p = 64 and a = 8.
You can find the values observing the code.
Apply the 1st step again.
Result:
Now find the contours in the above image:
if len(approx) == 8 and int(p) == 64:
cv2.drawContours(image, [c], -1, (180, 105, 255), 3)
elif len(approx) == 4 and int(p) == 73:
cv2.drawContours(image, [c], -1, (180, 105, 255), 3)
Result:
Code:
import cv2
from imutils import grab_contours as grb_cns
from imutils import resize as rsz
image = cv2.imread('K1Z94.png')
# Converting the image Gray scale
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(src=gray, thresh=127, maxval=255, type=0)
contours, hierarchy = cv2.findContours(image=thresh.copy(),
mode=cv2.RETR_TREE,
method=cv2.CHAIN_APPROX_SIMPLE)
gray = cv2.drawContours(image=gray, contours=contours, contourIdx=-1, color=(255, 255, 255), thickness=2)
resized = rsz(gray, width=300)
ratio = gray.shape[0] / float(gray.shape[0])
canny = cv2.Canny(gray, 50, 200)
thresh = cv2.threshold(src=canny, thresh=60, maxval=255,
type=cv2.THRESH_OTSU + cv2.THRESH_BINARY)[1]
cns = cv2.findContours(image=thresh.copy(), mode=cv2.RETR_EXTERNAL, method=cv2.CHAIN_APPROX_SIMPLE)
cns = grb_cns(cns)
for c in cns:
p = cv2.arcLength(c, True) # perimeter
approx = cv2.approxPolyDP(c, 0.04 * p, True)
M = cv2.moments(c)
# check if the all values of M are 0.
all_zr = all(value == 0 for value in M.values())
if not all_zr:
cX = int((M["m10"] / M["m00"]))
cY = int((M["m01"] / M["m00"]))
c = c.astype("float")
c *= ratio
c = c.astype("int")
# Circles: (radio-buttons)
if len(approx) == 8 and int(p) == 64:
cv2.drawContours(image, [c], -1, (180, 105, 255), 3)
elif len(approx) == 4 and int(p) == 73:
cv2.drawContours(image, [c], -1, (180, 105, 255), 3)
cv2.imwrite("result.png", image)

Categories