I am starting to get crazy with openCVs drawContours. Every time I run the Code, nothing shows up. Src image and contours are computed fine, but what am I doing wrong?
grayFrame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
blurredImg = cv2.GaussianBlur(grayFrame,(5,5),0)
optimumThreshold, bw = cv2.threshold(blurredImg,120,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
contours, hierarchy = cv2.findContours(bw, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(bw, contours, 1, (153,0,0), 4)
Related
I have to find out automatically coordinates (only one point) where border (object) begin, I do not know how to handle function findContours.
testImage.jpg
image = cv2.imread("testImage.jpg")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Threshold
ret, thresh = cv2.threshold(gray,225,255,0)
# Contours
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# Here are coordinates that I have to find out
coord = contours[0][1]
# Coordinates to point
point = (coord[0][0],coord[0][1])
# Draw circle on coordinates
cv2.circle(image,point,10,(0,255,0),1)
cv2.imshow("Image", image)
cv2.waitKey()
cv2.destroyAllWindows()
Output
And my goal is find out coordinates anywhere on the border (blue line) - see last image.
Goal
Thanks.
I tweaked your code a little. It seems to do the trick. Check out if it helps:
import cv2
import numpy as np
image = cv2.imread("test.jpg")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
t = 230 # threshold: tune this number to your needs
# Threshold
ret, thresh = cv2.threshold(gray,t,255,cv2.THRESH_BINARY_INV)
#kernel = np.ones((9,9),np.uint8)
#thresh = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
cv2.imshow("thresh", thresh)
cv2.waitKey(1)
# Contours
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# find the coordinate with the smallest x value
for contour in contours:
coord = min(contour[0], key=lambda c: c[0])
# Coordinates to point
point = (coord[0],coord[1])
#draw circles on coordinates
cv2.circle(image,point,10,(0,255,0),5)
cv2.imshow("Image", image)
cv2.waitKey()
cv2.destroyAllWindows()
Note: Increase parameter t to move your green circle 'farther outside' of the contour. Decrease it to move inside.
#Sparkofska
Thanks for your idea, I use it with another way to find out.
image = cv2.imread('testImage.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
t=230
ret, thresh = cv2.threshold(gray,t,255,cv2.THRESH_BINARY_INV)
cv2.imshow("filter", thresh)
# Canny Edge detection
canny = cv2.Canny(thresh, 0, 100)
cv2.imshow("canny", canny)
# Find contours
cnts = cv2.findContours(canny, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2:]
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
x, y, w, h = cv2.boundingRect(c)
# My coordinates
cv2.circle(image,(x,y), 10, (0,255,0), 5)
cv2.imshow("output", image)
cv2.waitKey()
cv2.destroyAllWindows()
I am trying to do perspective transform for documents in various background and light conditions. Currently, I can't do it on this image because the contour is not close.
The original Image
Edge Detection of image
So far, I have tried Adaptive Threshold, GaussianBlur, MedianBlur,all kind of Morphology operations, Hough Transform and Histogram Equalization and play with all of the parameters in them but nothing has worked.
Can anyone help me with this issue ?
Use Canny Edges, Dilation and Erosion getting this output
imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(img,20,40)
kernel = np.ones((5,5),np.uint8)
dilation = cv2.dilate(edges,kernel,iterations = 1)
erosion = cv2.erode(dilation,kernel,iterations = 1)
ret,thresh = cv2.threshold(erosion, 200, 255, 0)
contours, hierarchy = cv2.findContours(thresh,
cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
largest_areas = sorted(contours, key=cv2.contourArea)
cv2.drawContours(img, [largest_areas[-2]], -1, 255, 2)
cv2.imshow("image", img)
cv2.waitKey(0)
I am new to computer vision and haven't really went through any tutorials on thresholding or blurring or other filters.
I am using the below two piece of codes which finds out the contours in an image. On one hand the method is working but on the other it is not. I would need help in understanding the reason this is happening so as to convince myself what is happening in the background.
Working code snippet:
img=cv2.imread('path.jpg')
imgBlurred = cv2.GaussianBlur(img, (5, 5), 0)
gray = cv2.cvtColor(imgBlurred, cv2.COLOR_BGR2GRAY)
sobelx = cv2.Sobel(gray, cv2.CV_8U, 1, 0, ksize=3)
cv2.imshow("Sobel",sobelx)
cv2.waitKey(0)
ret2, threshold_img = cv2.threshold(sobelx, 120, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
im2, contours, hierarchy = cv2.findContours(threshold_img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
Not working code snippet
# read image
src = cv2.imread(file_path, 1)
# show source image
cv2.imshow("Source", src)
# convert image to gray scale
gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
# blur the image
blur = cv2.blur(gray, (3, 3))
# binary thresholding of the image
ret, thresh = cv2.threshold(blur, 200, 255, cv2.THRESH_BINARY)
# find contours
im2, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
I would really appreciate if anyone can find out the reason for the wrong which is happening here.
The error that i am facing is:
Traceback (most recent call last): File "convexhull.py", line 27, in
im2, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) ValueError: not enough values to unpack
(expected 3, got 2)
Let me know if any other information is also required.
This is due to a change in openCV. Since version 4.0 findContours returns only 2 values: the contours and the hierarchy. Before, in version 3.x, it returned 3 values. You can use the documentation to compare the different versions.
The second code snippet should work when you change your code to:
# find contours
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
Why the first snippet picks a different openCV version can't be determined from the information given.
The following snippet will work irrespective of the OpenCV version installed in your system/environment and will also store all the tuples in individual variables that can be used later in the code.
Store the major version of OpenCV installed:
import cv2
major_version = cv2.__version__[0]
Based on the version either of the following two statements will be executed and the corresponding variables will be populated:
if major_version == '4':
contours, hierarchy = cv2.findContours(image_binary, cv2.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
elif major_version == '3':
image, contours, hierarchy = cv2.findContours(image_binary, cv2.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
The contours returned from the function in either scenarios will be stored in contours.
Why the contour is in reverse order? I use the RETR_EXTERNAL flag for contours hierarchy for detect only the external contours
_, contours, hierarchy = cv2.findContours(connected.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
For example my my output is r,e B, why in reverse order?
You could use some heuristic to sort the contours. The following example uses the minimum x coordinate of each contour to sort them:
import cv2
import numpy as np
img = cv2.imread('BB7eu.png')
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, contours, hierarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours.sort(key=lambda c: np.min(c[:,:,0]))
for i in range(len(contours)):
cur = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
cv2.drawContours(cur, contours, i, (0,0,255), -1)
cv2.putText(cur, "i=%d" % i, (140,90), cv2.FONT_HERSHEY_PLAIN, 1, (0,255,255), 1)
cv2.imshow("img", cur)
cv2.waitKey()
You'll see that the contours are highlighted "in order": B,e,r.
I'm currently reading through the example code on the OpenCV website tyring to find contours in an image.
I first read an image and convert to gray-scale:
img = cv2.imread('/.../.../four.png')
imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
I then convert the image into binary by applying a threshold:
thresh = cv2.threshold(imgray, 127, 255, 0, cv2.THRESH_BINARY)
According to the tutorials.. I should then be able to call findContours() on the thresholded image:
contours = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
When trying to execute this code, for some reason i'm getting a type error:
contours =
cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
TypeError: image is not a numerical tuple
Unsure why?
Here's the full code for easier readability:
img = cv2.imread('/Users/samtozer/Desktop/four.png')
imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(imgray, 127, 255, 0, cv2.THRESH_BINARY)
contours = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(img, contours, -1, (0,255,0), 3)
Wondering if anyone has experienced this problem before? And if so, what is going wrong xD
Thanks in advance
As mentioned in the comments there are two issues that you have to look out for:
Return type of cv2.findContours()
There are two return values in cv2.findContours():
Contours present in the image
The hierarchy of these contours
Return type of cv2.threshold()
There are two return values in cv2.threshold():
Return value. (It returns float value of the threshold value which is used to classify the pixel values)
Thresholded image