i am trying to write a code using opencv python that automatically get canny threshold values instead of doing them manually every time.
img= cv2.imread('micro.png',0)
output = np.zeros(img.shape, img.dtype)
# Otsu's thresholding
ret2,highthresh = cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
lowthresh=0.1*highthres
edges = cv2.Canny(img,output,lowthresh,highthresh)
cv2.imshow('canny',edges)
i am getting this error
"File "test2.py", line 14, in
edges = cv2.Canny(img,output,lowthresh,highthresh)
TypeError: only length-1 arrays can be converted to Python scalars"
can anyone help me to sort out this error.thankx in advance
It seems like cv2.threshold returns the detected edges, and Canny applies them to the image. The code below worked for me and gave me some nice detected edges in my image.
import cv2
cv2.namedWindow('canny demo')
img= cv2.imread('micro.png',0)
ret2,detected_edges = cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
edges = cv2.Canny(detected_edges,0.1,1.0)
dst = cv2.bitwise_and(img,img,mask = edges)
cv2.imshow('canny',dst)
if cv2.waitKey(0) == 27:
cv2.destroyAllWindows()
You are running:
cv2.Canny(img,output,lowthresh,highthresh)
It is looking for
cv2.Canny(img,lowthresh,highthresh,output)
I think the ordering changed in some version, because I have seen references to both.
Related
I have this image : https://imgur.com/9A7542w
And i am trying to get the contours of the image but as we can see in this : https://imgur.com/VU7KqiS
where there is glare, the contours of some circles are not drawn.
I assume that if i get the glare off on this photo, when i use canny, the edges will be drawn correctly?
I am new to openCV, i've read some post on here and tried out some techniques, but it didn't work out at all.
Note: i am doing this in python
Anyone could help ? Thanks a lot.
What i tried first :
import cv2 as cv
img = cv.imread('Photos/board.jpg')
canny = cv.Canny(img, 125, 175)
contours, hierarchies = cv.findContours(canny, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_NONE)
blank = np.zeros(img.shape, dtype='uint8')
cv.drawContours(blank, contours, -1, (0,0,255),1)
cv.imshow('Contours drawn', blank)
results : https://imgur.com/yLVFCh2
Second attempt a bit better but useless things appears in the result
adaptive_thresh = cv.adaptiveThreshold(gray, 255, cv.ADAPTIVE_THRESH_MEAN_C, cv.THRESH_BINARY, 13, 2)
cv.imshow('Adaptive thresholding', adaptive_thresh)
canny = cv.Canny(adaptive_thresh, 125, 175)
cv.imshow('Canny edges', canny)
Results (Theres so much white pixels that appear on the photo : https://imgur.com/mqljl1m
I think the easiest way to do this is to change the 2nd value of your Canny detection like this :
canny = cv.Canny(img, 25, 175)
the lower threshold (second argument) is set lower then you can avoid this glare effect. More info here
From my point of view, you can also work in hsv space which is more confomfortable if you want to extract informations from images with effects like this. More info about hsv. The Fig. 3 a) speaks for itself.
Here is the full code, you had some errors in yours (and maybe you use an old opencv release)
import numpy as np
img = cv.imread(r'C:\Users\MyUser\Desktop\board.jpeg')
canny = cv.Canny(img, 25, 175)
img2, contours, hierarchy = cv.findContours(canny, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_NONE)
blank = np.zeros(img.shape, dtype='uint8')
cv.drawContours(blank, contours, -1, (0,0,255),1)
cv.imshow('Contours drawn', blank)
cv.waitKey(0)
EDIT: I also want to tell you that it'll be difficult to use the extracted coordinates here. You'd better use circle detection and line detection to extract and use the coordinates of the board and pucks.
I need help thresholding a picture. I need identify different types of gummies but i cannot get past the thresholding part of my project.
I have various pictures but this is one of them:
I have done this using mean_c threshold but i need better results to find the countours after.
This is the original picture:
You may get better results by converting the image from RGB to HSV color space and threshold by hue (that's color value) and saturation (that's how much color is there compared to the gray value). Using saturation you might get the most of your gummies, except the transparent ones -- these are quite hard to get.
On the other hand, you may try to use edge detections, since your paper is flat and gummies really stand out. Here's the edge detection result I've got:
here's the code:
#!/usr/bin/env python
import cv2
img = cv2.imread( 'Downloads/gummies.jpg' )
img = cv2.pyrDown(cv2.pyrDown( img ))
laplacian = cv2.Laplacian(img, cv2.CV_8U)
cv2.normalize( laplacian, img, 0, 600, cv2.NORM_MINMAX)
cv2.imshow( 'frame', img )
cv2.waitKey(0)
cv2.destroyAllWindows()
In the opencv documentation it says:
If mode equals to RETR_CCOMP or RETR_FLOODFILL, the input can also be
a 32-bit integer image of labels (CV_32SC1).
After sending a converted image to the function, I got 180k contours, resulting the black mess below, if I plot them. So what does RETR_FLOODFILL do and how do I use it correctly?
img = cv2.imread("lena.png")
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, contours, _ = cv2.findContours(image=np.array(img, dtype=np.int32), mode=cv2.RETR_FLOODFILL, method=cv2.CHAIN_APPROX_SIMPLE)
len(contours)
Out[7]: 183295
I think it does whatever function cv2.floodFill does. Finds all the pixels that are:
1-connected to each other
2-have intensity values close to each other
and consider them as a connected component. For example In your sample image, you have 183295 groups of pixels that are stick together and have a close intensity.
I want to find the bright spots in the above image and tag them using some symbol. For this i have tried using the Hough Circle Transform algorithm that OpenCV already provides. But it is giving some kind of assertion error when i run the code. I also tried the Canny edge detection algorithm which is also provided in OpenCV but it is also giving some kind of assertion error. I would like to know if there is some method to get this done or if i can prevent those error messages.
I am new to OpenCV and any help would be really appreciated.
P.S. - I can also use Scikit-image if necessary. So if this can be done using Scikit-image then please tell me how.
Below is my preprocessing code:
import cv2
import numpy as np
image = cv2.imread("image1.png")
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
binary_image = np.where(gray_image > np.mean(gray_image),1.0,0.0)
binary_image = cv2.Laplacian(binary_image, cv2.CV_8UC1)
If you are just going to work with simple images like your example where you have black background, you can use same basic preprocessing/thresholding then find connected components. Use this example code to draw a circle inside all circles in the image.
import cv2
import numpy as np
image = cv2.imread("image1.png")
# constants
BINARY_THRESHOLD = 20
CONNECTIVITY = 4
DRAW_CIRCLE_RADIUS = 4
# convert to gray
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# extract edges
binary_image = cv2.Laplacian(gray_image, cv2.CV_8UC1)
# fill in the holes between edges with dilation
dilated_image = cv2.dilate(binary_image, np.ones((5, 5)))
# threshold the black/ non-black areas
_, thresh = cv2.threshold(dilated_image, BINARY_THRESHOLD, 255, cv2.THRESH_BINARY)
# find connected components
components = cv2.connectedComponentsWithStats(thresh, CONNECTIVITY, cv2.CV_32S)
# draw circles around center of components
#see connectedComponentsWithStats function for attributes of components variable
centers = components[3]
for center in centers:
cv2.circle(thresh, (int(center[0]), int(center[1])), DRAW_CIRCLE_RADIUS, (255), thickness=-1)
cv2.imwrite("res.png", thresh)
cv2.imshow("result", thresh)
cv2.waitKey(0)
Here is resulting image:
Edit: connectedComponentsWithStats takes a binary image as input, and returns connected pixel groups in that image. If you would like to implement that function yourself, naive way would be:
1- Scan image pixels from top left to bottom right until you encounter a non-zero pixel that does not have a label (id).
2- When you encounter a non-zero pixel, search all its neighbours recursively( If you use 4 connectivity you check UP-LEFT-DOWN-RIGHT, with 8 connectivity you also check diagonals) until you finish that region. Assign each pixel a label. Increase your label counter.
3- Continue scanning from where you left.
import cv2
import numpy as np
cap = cv2.VideoCapture(0)
while(1):
# Take each frame
_, frame = cap.read()
frame = cv2.medianBlur(frame,5)
cimg = cv2.cvtColor(frame,cv2.COLOR_GRAY2BGR)
circles = cv2.HoughCircles(frame,cv2.HOUGH_GRADIENT,1,20,
param1=50,param2=30,minRadius=0,maxRadius=0)
circles = np.uint16(np.around(circles))
for i in circles[0,:]:
# draw the outer circle
cv2.circle(cimg,(i[0],i[1]),i[2],(0,255,0),2)
# draw the center of the circle
cv2.circle(cimg,(i[0],i[1]),2,(0,0,255),3)
cv2.imshow('frame',cimg)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
I am trying to find circles, but my code fails OpenCV Error: Assertion failed (scn == 1 && (dcn == 3 || dcn == 4)). Any idea why? In addition, how to get coordinates of a circle?
The flag you pass to cvt Color should be cv2.COLOR_BGR2GRAY instead of cv2.COLOR_GRAY2BGR - you want convert to grayscale to have single channeled image instead of RGB 3 channeled image and that's what assertion says. (look at the docs to see what paramaters you need, an input image is clearly a 8-bit, single-channel, grayscale input image.)
Rest of the code looks ok and is an answer to second part of your question.
EDIT: (after OP having another problem with passing constant):
After changing cvtColor constant we had following code:
cimg = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
circles = cv2.HoughCircles(cimg,cv2.HOUGH_GRADIENT,1,20,
param1=50,param2=30,minRadius=0,maxRadius=0)
which actually caused another problem:
AttributeError: 'module' object has no attribute 'HOUGH_GRADIENT'
Since I'm working with OpenCV mostly with C++ and not with Python, I solved it in different way. I tried to find number equivalent of CV_HOUGH_GRADIENT constant. In turned out to be located in opencv\sources\modules\imgproc\include\opencv2\imgproc\types_c.h:
enum
{
CV_HOUGH_STANDARD =0,
CV_HOUGH_PROBABILISTIC =1,
CV_HOUGH_MULTI_SCALE =2,
CV_HOUGH_GRADIENT =3
};
That is why we can use following snippet instead of predefined constant:
circles = cv2.HoughCircles(cimg,3,1,20, param1=50,param2=30,minRadius=0,maxRadius=0)