contour approximation in opencv python is giving wrong result everytime - python

I am an absolute beginner in image processing.I want to detect a nested shape among various different edges.from my program I have successfully detected my expected contour through hierarchy relation.but my problem arises when I am going to detect the shape.for contour approximation, I am using cv2.approxpolyDP() method/function on my desired contour using its index number.but every time it is resulting in the same output, which is "1".I don't know where I am mistaking.please have a look and suggest me some.The code is given below and the images to be detected is also given in those links. please help me...
import cv2
import numpy as np
maxx=0
original_color=cv2.imread("tri.jpg",1)
original=cv2.cvtColor(original_color,cv2.COLOR_BGR2GRAY)
#cv2.imshow("original",original)
blur=cv2.GaussianBlur(original,(5,5),0)
ret,thresh=cv2.threshold(blur,50,255,cv2.THRESH_BINARY)
edges = cv2.Canny(thresh,100,200)
image,contours,hierarchy=cv2.findContours(edges.copy(),cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
print len(contours)
##for c in range(0,len(hierarchy)) :
## a=zip(hierarchy[c],contours[c])
for i in range(0,len(hierarchy[0])):
if hierarchy[0][i][2]>=maxx :
if(hierarchy[0][i][3]==(hierarchy[0][i][2]-2)):
maxx=hierarchy[0][i][2]
index=i
cnt=contours[index]
for c in cnt :
peri=cv2.arcLength(c,True)
approx=cv2.approxPolyDP(c,0.04*peri,True)
print hierarchy
print maxx
print len(approx)
cv2.drawContours(original_color,contours,index,(0,255,0),3)
cv2.imshow("Show",original_color)
cv2.waitKey()
cv2.destroyAllWindows()
Before Detection
Succesfully Detected

The result of findContours is a list of list of points, this means that the problem is here:
cnt=contours[index]
for c in cnt :
peri=cv2.arcLength(c,True)
approx=cv2.approxPolyDP(c,0.04*peri,True)
Here you select a contour(list of pointS) and then loop for each point and do the approxPolyDP with only 1 point. You should do it to the contour. So, if you want it to do it for the selected contour, you should do:
cnt=contours[index]
peri=cv2.arcLength(cnt,True)
approx=cv2.approxPolyDP(cnt,0.04*peri,True)
If you want to do it for each contour then do like this (keeping the print inside the loop, if not it will show only the last one):
for c in contours:
peri=cv2.arcLength(c,True)
approx=cv2.approxPolyDP(c,0.04*peri,True)
print len(approx)

Related

counting the number of objects in an image using python

I am trying to count the number of objects in this image:
I have a code for that:
import cv2
import numpy as np
image = cv2.imread('d:\obj.jpg')
blurred = cv2.pyrMeanShiftFiltering(image,31,91)
gray = cv2.cvtColor(blurred,cv2.COLOR_BGR2GRAY)
ret , threshold = cv2.threshold(gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
cv2.imshow("Threshold",threshold)
_, contours,_=cv2.findContours(threshold,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
print "Number of contours: %d "%len(contours)
cv2.drawContours(image,contours,-1,(0,255,255),2)
cv2.namedWindow('Display',cv2.WINDOW_NORMAL)
cv2.imshow('Display',image)
cv2.waitKey()
the number of objects is 9, but the output is 1015.
when I try to show the the objects this is what I get:
How can I fix that?
thanks to all :)
You can easily get the area of contours. I would suggest putting up a threshold on area of contours. I mean to say iterate over all the contours and just keep only those which have area greater than a number specified by you and reject others. This way you can avoid small contours which are there due to noises.

What does len(contour) means?

I have been working under the image of bacteria and a wish to take the number of bacteria from the image, and also need to classify the bacteria with specific shape and size.
I am using opencv python. Now i use the contour method.
contours,hierarchy = cv2.findContours(dst,1,2)
cnt = contours[0]
l = len(contours)
print l
li = list(contours)
print li
This give an output of l= 115 and li= some array values .
What does this means??
please help me in finding out the answer..e.coli image below:
Contours connects continuous points and puts all of them in an array. So each element in this array probably corresponds to a different bacteria (or a false detection, due to a connected color group that is a shadow etc).
When you say len(contours), you get the number of elements in this array. Therefore, you get a rough estimation of the number of bacterias.
In your case, there are 115 bacterias, or colors that are different than their surroundings which may or may not be bacterias. When you define a list for them and print the list, you get the properties of each element in this list, therefore you get the properties for each "connected point group" or each "object that is possibly a bacteria". Its all pretty straightforward really.
If you realize that you have many false detections here is what you do:
A group of bacterias appearing as one:
You threshold the image (convert it to black&white) and use the erode function first. Then use dilate function to remove their connections. Then go with findContours once more.
Stains detected as bacterias:
Make your thresholding only cover the bacterias color range, so everything else will be ignored.
See sources below, they might help:
http://docs.opencv.org/2.4/doc/tutorials/imgproc/shapedescriptors/find_contours/find_contours.html
http://docs.opencv.org/trunk/d4/d73/tutorial_py_contours_begin.html#gsc.tab=0
cv2.findCountours returns a list of contours where each contour is a numpy array of points (2 columns for x, y coordinates). len(foo) is the length of list foo. So in your case it found 115 contours and your li is just a copy of the contours list.
You can easily examine the contours by using the drawContours function.
# draws contours in white color, outlines only (not filled)
cv2.drawContours(dst, contours, -1, (255,))
cv2.imshow("result", dst)
cv2.waitKey(-1)

OpenCV finding contours

We are part of a FIRST robotics team that is using OpenCV for vision detection. Other teams have posted a working detection software This can be found on team2053tigertronics's Github (/2016Code/blob/master/Robot2016/src/vision/vision.cpp) and we are attempting to convert their code into Python as using this code as sample code that we can adjust later. While converting, we ran into a weird issue.
For debugging purposes we are using a print statement to print the contours so that we knew why we got the error when we tried to put the code into the boundingRectangle method
Here is our code so far:http://pastebin.com/7zh4c7Ej
Here is our output: http://pastebin.com/5fRQhC28
The error we are getting:
Traceback:
in line 146, processImage()
in line 98: rec = cv2.boundingRect(i[x])
index 256 is out of bounds for axis 0 with size 15/
Our output has been a list of different numpy arrays that hold integer values. We are confused on how to use these values to draw rectangles and eventually use these values for coordinates for use during the robotics game.
We appreciate any help!!!
Thanks!
Axton (and Team)
EDIT:
As asked for by other members, here is a more simpler question:
Here is our code that we are having problems with:
filler, contours, heirarchy = cv2.findContours(matThresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for i in contours:
for x in i:
rec = Rect()
print i[x]
rec = cv2.boundingRect(i[x])
We would like to know how to use the contour values as points to use the boundingRect method.
Thanks again!
it is indeed as easy as #Miki said above.
since contours is a list of contours, you only need one loop to access a single contour, and get the bounding rect of that:
for contour in contours:
rec = cv2.boundingRect(contour)
print rec
## now, just for the fun, let's look
## at a *single* contour, it consists of points:
for point in contour:
print point

OpenCV get centers of multiple objects

I'm trying to build a simple image analyzing tool that will find items that fit in a color range and then finds the centers of said objects.
As an example, after masking, I'm analyzing an image like this:
What I'm doing so far code-wise is rather simple:
import cv2
import numpy
bound = 30
inc = numpy.array([225,225,225])
lower = inc - bound
upper = inc + bound
img = cv2.imread("input.tiff")
cv2.imshow("Original", img)
mask = cv2.inRange(img, lower, upper)
cv2.imshow("Range", mask)
contours = cv2.findContours(mask, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_TC89_L1)
print contours
This, however, gives me a countless number of contours. I'm somewhat at a loss while reading the corresponding manpage. Can I use moments to reasonably analyze the contours? Are contours even the right tool for this?
I found this question, that vaguely covers finding the center of one object, but how would I modify this approach when there are multiple items?
How do I find the centers of the objects in the image? For example, in the above sample image I'm looking to find three points (the centers of the rectangle and the two circles).
Try print len(contours). That will give you around the expected answer. The output you see is the full representation of the contours which could be thousands of points.
Try this code:
import cv2
import numpy
img = cv2.imread('inp.png', 0)
_, contours, _ = cv2.findContours(img.copy(), cv2.RETR_CCOMP, cv2.CHAIN_APPROX_TC89_L1)
print len(contours)
centres = []
for i in range(len(contours)):
moments = cv2.moments(contours[i])
centres.append((int(moments['m10']/moments['m00']), int(moments['m01']/moments['m00'])))
cv2.circle(img, centres[-1], 3, (0, 0, 0), -1)
print centres
cv2.imshow('image', img)
cv2.imwrite('output.png',img)
cv2.waitKey(0)
This gives me 4 centres:
[(474, 411), (96, 345), (58, 214), (396, 145)]
The obvious thing to do here is to also check for the area of the contours and if it is too small as a percentage of the image, don't count it as a real contour, it will just be noise. Just add something like this to the top of the for loop:
if cv2.contourArea(contours[i]) < 100:
continue
For the return values from findContours, I'm not sure what the first value is for as it is not present in the C++ version of OpenCV (which is what I use). The second value is obviously just the contours (an array of arrays) and the third value is a hierarchy holding information on the nesting of contours, which can be very handy.
You can use the opencv minEnclosingCircle() function on your contours to get the center of each object.
Check out this example which is in c++ but you can adapt the logic Example

extract only one contour after FindContours operation

I am currently using FindContours and DrawContours function in order to segment an image.
I only extract external contours, and want to save only the contour which contains a given point.
I use h_next to move through the cv_seq structure and test if the point is contained using PointPolygonTest
I actually can find the contour that interests me, but my problem is to extract it.
Here is the python code :
def contour_from_point(contours, point, in_img):
"""
Extract the contour from a sequence of contours which contains the point.
For this to work in the eagle road case, the sequence has to be performed using the
FindContours function with CV_RETR_EXTERNAL
"""
if contours:
# We got at least one contour. Search for the one which contains point
contour = contours # first contour of the list
distance = cv.PointPolygonTest(contour, point, 0)
while distance < 0: # 0 means on eadge of contour
contour = contour.h_next()
if contour: # avoid end of contours
distance = cv.PointPolygonTest(contour, point, 0)
else :
contour = None
else:#
contour = None
return contour
At the end, I got contour. But this structure still contains all the contours that have not been tested yet.
How can I do to keep only the first contour of my output sequence?
Thanks by advance !
There is finally a way to get only one contour. Juste use another function that needs a cvseq in input, as ConvexHull for example. The output will be only the first contour of the sequence.

Categories

Resources