I am trying to detect circles in an image, and am using OpenCV Python for the same. I am facing problems when I use the HoughCircles method. I am using the following custom image , but my code is unable to detect both circles.
I tried the following implementation
circles = cv2.HoughCircles(thresh1,cv2.cv.CV_HOUGH_GRADIENT,2,1,param1=100,param2=100,minRadius=0,maxRadius=1000)
and this is only properly detecting the bigger circle in the image. I'm pretty sure if I tinker around with the parameters , I might hit upon a combination that works, but is there any way I can calculate, or figure out the parameters, given an image?
EDIT
Here is the entire code that I have written:
import cv2
import numpy as np
def show(s , i):
cv2.imshow(s , i)
cv2.waitKey(0)
cv2.destroyAllWindows()
img = cv2.imread('ball2.jpg')
show("img" , img)
img = cv2.medianBlur(img,5)
cimg = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh1 = cv2.threshold(cimg,10,255,cv2.THRESH_BINARY)
show('thresh' , thresh1)
circles = cv2.HoughCircles(thresh1,cv2.cv.CV_HOUGH_GRADIENT,2,1,param1=100,param2=100,minRadius=0,maxRadius=1000)
print circles
circles = np.uint16(np.around(circles))
for i in circles[0,:]:
# draw the outer circle
cv2.circle(thresh1,(i[0],i[1]),i[2],(100,150,120),2)
# draw the center of the circle
cv2.circle(thresh1,(i[0],i[1]),2,(0,0,0),3)
cv2.imshow('detected circles',thresh1)
cv2.waitKey(0)
cv2.destroyAllWindows()
Have you seen http://www.pyimagesearch.com/2014/07/21/detecting-circles-images-using-opencv-hough-circles/?
Author there suggests to tinker with minDist, as the most important parameter, but you have that set to 1, so rather we should expect false positive than not found circles.
I suggest also to increase param1 to 200 to set upper threshold for the internal Canny edge detector for increased detection.
Also I found some people reported weird anomaly, where increasing maxradius resulted in getting fewer circles. Sometimes it's good idea to leave optional parameters as default (value 0).
From my experience with openCV it often ends up with tinkering parameters to get best results.
Related
I'm currently working on an openCV course through Udemy and have run into the trouble where my kernel is dying. I tried eliminating line by line to see what could the cause, and I found that when the code comes to the line: keypoints = detector.detect(image) it fails. Now I am kind of an amateur when it comes to this kind of stuff, but would appreciate some feedback as to why this could be occurring. Here's the code i'm working with:
import cv2
import numpy as np;
# Read image
image = cv2.imread("images/Sunflowers.jpg")
# Set up the detector with default parameters.
detector = cv2.SimpleBlobDetector()
# Detect blobs.
keypoints = detector.detect(image)
# Draw detected blobs as red circles.
# cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS ensures the size of
# the circle corresponds to the size of blob
blank = np.zeros((1,1))
blobs = cv2.drawKeypoints(image, keypoints, blank, (0,255,255),
cv2.DRAW_MATCHES_FLAGS_DEFAULT)
# Show keypoints
cv2.imshow("Blobs", blobs)
cv2.waitKey(0)
cv2.destroyAllWindows()```
Please replace:
detector = cv2.SimpleBlobDetector()
with:
detector = cv2.SimpleBlobDetector_create()
1. I am doing a project regarding face detection, i just want to know how to display like this
I able to get that rectangle but not able to display the string within the box.
2. I have done the detection using haar and it is only detecting when we are looking directly to it. i want to make it more accurate when we turn left/right/up down - help me
My code looks like this.
import cv2
import sys
import logging as log
import datetime as dt
from time import sleep
cascPath = "haarcascade_frontalface_default.xml"
faceCascade = cv2.CascadeClassifier(cascPath)
log.basicConfig(filename='webcam.log',level=log.INFO)
video_capture = cv2.VideoCapture(0)
anterior = 0
while True:
if not video_capture.isOpened():
print('Unable to load camera.')
sleep(5)
pass
# Capture frame-by-frame
ret, frame = video_capture.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = faceCascade.detectMultiScale(
gray,
scaleFactor=1.1,
minNeighbors=5,
minSize=(30, 30)
)
# Draw a rectangle around the faces
for (x, y, w, h) in faces:
cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
if anterior != len(faces):
anterior = len(faces)
log.info("faces: "+str(len(faces))+" at "+str(dt.datetime.now()))
# Display the resulting frame
cv2.imshow('Video', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# Display the resulting frame
cv2.imshow('Video', frame)
# When everything is done, release the capture
video_capture.release()
cv2.destroyAllWindows()
You need: Posing and Projecting Faces
Humans can easily recognize that both images are of Will Ferrell, but computers would see these pictures as two completely different people:
To account for this, we will try to warp each picture so that the eyes and lips are always in the sample place in the image. This will make it a lot easier for us to compare faces in the next steps.
To do this, we are going to use an algorithm called face landmark estimation. There are lots of ways to do this, but we are going to use the approach invented in 2014 by Vahid Kazemi and Josephine Sullivan.
The 68 landmarks we will locate on every face. This image was created by Brandon Amos of CMU who works on OpenFace.
Here’s the result of locating the 68 face landmarks on our test image:
PROTIP: You can also use this same technique to implement your own version of Snapchat’s real-time 3d face filters!
Now that we know were the eyes and mouth are, we’ll simply rotate, scale and shear the image so that the eyes and mouth are centered as best as possible. We won’t do any fancy 3d warps because that would introduce distortions into the image. We are only going to use basic image transformations like rotation and scale that preserve parallel lines (called affine transformations):
Now no matter how the face is turned, we are able to center the eyes and mouth are in roughly the same position in the image. This will make our next step a lot more accurate.
If you want to try this step out yourself using Python and dlib, here’s the code for finding face landmarks and here’s the code for transforming the image using those landmarks.
This explanation taken from this medium post.
The source code is available on GitHub.
To your first question, you can use
cv2.putText(image, 'ABC', (x, y-12), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (30,255,30), 2)
I am trying to do some white blob detection using OpenCV. But my script failed to detect the big white block which is my goal while some small blobs are detected. I am new to OpenCV, and am i doing something wrong when using simpleblobdetection in OpenCV? [Solved partially, please read below]
And here is the script:
#!/usr/bin/python
# Standard imports
import cv2
import numpy as np;
from matplotlib import pyplot as plt
# Read image
im = cv2.imread('whiteborder.jpg', cv2.IMREAD_GRAYSCALE)
imfiltered = cv2.inRange(im,255,255)
#OPENING
kernel = np.ones((5,5))
opening = cv2.morphologyEx(imfiltered,cv2.MORPH_OPEN,kernel)
#write out the filtered image
cv2.imwrite('colorfiltered.jpg',opening)
# Setup SimpleBlobDetector parameters.
params = cv2.SimpleBlobDetector_Params()
params.blobColor= 255
params.filterByColor = True
# Create a detector with the parameters
ver = (cv2.__version__).split('.')
if int(ver[0]) < 3 :
detector = cv2.SimpleBlobDetector(params)
else :
detector = cv2.SimpleBlobDetector_create(params)
# Detect blobs.
keypoints = detector.detect(opening)
# Draw detected blobs as green circles.
# cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS ensures
# the size of the circle corresponds to the size of blob
print str(keypoints)
im_with_keypoints = cv2.drawKeypoints(opening, keypoints, np.array([]), (0,255,0), cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
# Show blobs
##cv2.imshow("Keypoints", im_with_keypoints)
cv2.imwrite('Keypoints.jpg',im_with_keypoints)
cv2.waitKey(0)
EDIT:
By adding a bigger value of area maximum value, i am able to identify a big blob but my end goal is to identify the big white rectangle exist or not. And the white blob detection i did returns not only the rectangle but also the surrounding areas as well. [This part solved]
EDIT 2:
Based on the answer from #PSchn, i update my code to apply the logic, first set the color filter to only get the white pixels and then remove the noise point using opening. It works for the sample data and i can successfully get the keypoint after blob detection.
If you just want to detect the white rectangle you can try to set a higher threshold, e.g. 253, erase small object with an opening and take the biggest blob. I first smoothed your image, then thresholding it:
and the opening:
now you just have to use findContours and take the boundingRect. If your rectangle is always that white it should work. If you get lower then 251 with your threshold the other small blobs will appear and your region merges with them, like here:
Then you could still do an opening several times and you get this:
But i dont think that it is the fastest idea ;)
You could try setting params.maxArea to something obnoxiously large (somewhere in the tens of thousands): the default may be something lower than the area of the rectangle you're trying to detect. Also, I don't know how true this is or not, but I've heard that detection by color is bugged with a logic error, so it may be worth a try disabling it just in case that is causing problems (this has probably been fixed in later versions, but it could still be worth a try)
I'm a semi-noob in Video Analysis.
I have a Petri dish with some colored droplets inside and I must detect them, and keep trace of their position,area and color.
I want first to detect my Petri dish (maybe using HoughCircles) and define a ROI on which work later.
The problem is that mi dish detection is very "noisy": the program detects many circles (and I only need the one corresponding to the dish) and it never detects the right one.
Here is my code:
import cv2
import numpy as np
def main():
cap=cv2.VideoCapture("dropletsS.wmv")
cv2.namedWindow("prova")
while(1):
ret, RGBframe = cap.read()
grayFrame = cv2.cvtColor(RGBframe,cv2.COLOR_BGR2GRAY)
grayFrame=cv2.medianBlur(grayFrame,7)
circles=cv2.HoughCircles(grayFrame,cv2.HOUGH_GRADIENT ,50,50)
for c in circles[0,:]:
cv2.circle(RGBframe,(c[0],c[1]),c[2],(0,255,0),2)
cv2.imshow("prova", RGBframe)
cv2.imshow("grigio", grayFrame)
cv2.waitKey(10)
if __name__ == "__main__":
main()
And here is the result.
Do someone have some suggestions? Suggestions on the way I can later identify and track droplets are welcome too.
Thanks in advance!
Its kind of hard to come up with a solution without having much of an idea on how the dish actually looks like, but I'll try helping you anyways.
If the problem is what I think it is, then you can probably open and dilate your image to join all the discontinuous blobs.
Do the following before you apply Hough Transform:
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5)) #declare outside while
grayFrame = cv2.morphologyEx(grayFrame, cv2.MORPH_OPEN, kernel)
grayFrame = cv2.dilate(grayFrame, kernel, iterations = 2)
Let me know if the output is output image that you desire. Also play around with the parameters to get the required result. You can change the dimensions of the MORPH_ELLIPSE and also the number of iterations. Increasing any of them would increase the degree of dilation, thus more of the blobs would join up and vice versa.
I want to extract the silhouette of an image, and I'm trying to do it using the contour function of MatplotLib. This is my code:
from PIL import Image
from pylab import *
# read image to array
im = array(Image.open('HOJA.jpg').convert('L'))
# create a new figure
figure()
# show contours with origin upper left corner
contour(im, origin='image')
axis('equal')
show()
This is my original image:
And this is my result:
But I just want to show the external contour, the silhouette. Just the read lines in this example.
How can I do it? I read the documentation of the contour function, but I can't get what I want.
If you know a better way to do this in Python, please tell me! (MatplotLib, OpenCV, etc.)
If you want to stick with your contour approach you can simply add a levels argument with a value 'thresholding' the image between the white background and the leaf.
You could use the histogram to find an appropriate value. But in this case any value slightly lower than 255 will do.
So:
contour(im, levels=[245], colors='black', origin='image')
Make sure you checkout Scikit-Image if you want to do some serious image processing. It contains several edge detection algoritms etc.
http://scikit-image.org/docs/dev/auto_examples/
For those who want the OpenCV solution, here it is:
ret,thresh = cv2.threshold(image,245,255,0)
contours, hierarchy = cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
tam = 0
for contorno in contours:
if len(contorno) > tam:
contornoGrande = contorno
tam = len(contorno)
cv2.drawContours(image,contornoGrande.astype('int'),-1,(0,255,0),2)
cv2.imshow('My image',image)
cv2.waitKey()
cv2.destroyAllWindows()
In this example, I only draw the biggest contour. Remember that 'image' must be a single-channel array.
You should change the parameters of the threshold function, the findContours function and the drawContours function to get what you want.
threshold Documentation
findContours Documentation
drawContours Documentation
I do the conversion to 'int' in the drawContours function because there is a bug in the Open CV 2.4.3 version, and if you don't do this conversion, the program breaks.
This is the bug.
I would recommand using OpenCV for performance.
It has a findContour functions accessible from python using the cv2 binding.
This function can be set to return only the external contour.
You will have to threshold your image as well.