How does cv2.findContours() edit the image? - python

I have two questions.
I am working with openCv and python and I am trying to have an image's contours. I am succesfull at that but when I try to se what is the difference between when I use cv2.drawContorus() functions and directly edit image with cv2.findContours() without sending a copy of original image as the source parameter. I have tried on some images but I couldnt see anything even happenning.
I am trying to get the contours of a square I created with paint square tool. But when I try with cv2.CHAIN_APPROX_SIMPLE method, it gives me coordinates of 6 points which none of the combinations from them is suitable for my square. Why does it do like that?
Can someone explain?
Here is my code for both problems:
import cv2
import numpy as np
image = cv2.imread(r"C:\Users\fazil\Desktop\12.png")
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
gray = cv2.Canny(gray,75,200)
gray = cv2.threshold(gray,127,255,cv2.THRESH_BINARY_INV)[1]
cv2.imshow("s",gray)
contours, hiearchy = cv2.findContours(gray,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
print(contours[1])
cv2.drawContours(image,contours,1,(45,67,89),5)
cv2.imshow("k",gray)
cv2.imshow("j",image)
cv2.waitKey(0)
cv2.destroyAllWindows()

Related

How to crop images using OpenCV without knowing the exact coordinates?

I am trying to crop an image of a piece of card/paper or such so that the card/paper is in focus. I tried the below code but the problem is that it works only when the object in question is alone in the picture. If it is a blank background with nothing else in it- the cropping is flawless, otherwise it does not work as expected.
I am attempting create a system which crops different kinds of images and puts them through a classifier and then extracts text from them.
import cv2
import numpy as np
filenames = "img.jpg"
img = cv2.imread(filenames)
blurred = cv2.blur(img, (3,3))
canny = cv2.Canny(blurred, 50, 200)
## find the non-zero min-max coords of canny
pts = np.argwhere(canny>0)
y1,x1 = pts.min(axis=0)
y2,x2 = pts.max(axis=0)
## crop the region
cropped = img[y1:y2, x1:x2]
filename_cropped = filenames.split('.')
filename_cropped[0] = filename_cropped[0] + '_cropped'
filename_cropped = '.'.join(filename_cropped)
cv2.imwrite(filename_cropped, cropped)
An sample image that works is
Something that does not work is
Can anyone help with this?
The first image works because the entire images besides your target is empty. Canny will also give other results when there is more in the image.
If you are looking for those specific cards I suggest you try to use some colour filtering first. You can try to filer for the blue/purple hue of the card.
Increasing the canny threshold could also work, but you will always still be finding the hand as well in this image unless you add some colour filtering.
You can also try Sobel edge detection . This will probably highlight the instant edges of the card pretty well. But then again, it will also show the hand, so you can't just take all the Sobel/Canny outputs. You need to add processing before it that isolates the card, or after it that can find the rectangular shape of the card in the sobel/canny.

Extract car images without Mask RCNN

I want to extract car images without using Mask RCNN. I tried a couple of methods but couldn't decide on how to proceed with any of them. I need recommendation on which method would be best and how to go through with it.
Method 1 - Using XML files and haar cascade classifier
I was thinking of using xml files to detection and crop car images. The problems I faced were:
They only detect car in square shapes. I needed car images cropped. So ultimately I ended up with better images of cropped cars. This didn't solve my problem.
The cropped image didn't detect car as a whole but small parts of it. Maybe due to XML file's config.
My code:
!wget https://raw.githubusercontent.com/shaanhk/New-GithubTest/master/cars.xml
import numpy as py
import cv2
car_cascade=cv2.CascadeClassifier('cars.xml')
img = cv2.imread('im1.jpg')
cars = car_cascade.detectMultiScale(img, 1.1, 1)
for (x,y,w,h) in cars:
cv2.rectangle(img,(x,y),(x+w,y+h),(0,0,255),2)
cv2.imshow('image',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
Resulting image:
Method 2 - Using Canny Edge Detection
I tried to perform canny edge detection for car. It worked to some extent that I managed to reduce edges to mostly car object. But I don't know how to proceed from there.
My code:
import cv2
import numpy as np
image= cv2.imread('im1.jpg')
imagecopy= np.copy(image)
grayimage= cv2.cvtColor(imagecopy, cv2.COLOR_RGB2GRAY)
canny= cv2.Canny(grayimage, 300,150)
cv2.imshow('Highway Edge Detection Image', canny)
cv2.waitKey(0)
cv2.destroyAllWindows()
Resulting Image:
Method 3 - Extract car image using color gradients
On googling I found a method using HSV transformation and then creating a custom mask to extract cars. But I don't know much about this method and have no idea how to go about it. I used the code provided and am posting it below.
Code:
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np
import cv2
%matplotlib inline
image = mpimg.imread('im1.jpg')
hsv = cv2.cvtColor(image, cv2.COLOR_RGB2HSV)
# HSV channels
h = hsv[:,:,0]
s = hsv[:,:,1]
v = hsv[:,:,2]
background_hue = h[10,10]
lower_hue = np.array([background_hue-10,0,0])
upper_hue = np.array([background_hue+10,255,255])
mask = cv2.inRange(hsv, lower_hue, upper_hue)
# Mask the image to let the car show through
masked_image = np.copy(image)
masked_image[mask != 0] = [0, 0, 0]
cv2.imwrite('mask.jpg',masked_image)
# Display it!
plt.imshow(masked_image)
Image:
I'd like to mention, I'm a complete beginner in Computer Vision and am trying to learn by doing some small stuff like these. My code is probably very flawed and hopefully I can work on it on the way. Please feel absolutely free to mention any other method (except Mask RCNN) or any problems with code.

Rotate image arbitrary in opencv

I trying to recognize some banknotes. I tried with a haar cascade algorithm in opencv but I can't get good results so I will try with template matching.
I think, first thing I should do is rotate the banknote so I always get it in horizontal mode.
this is what I am trying to recognize contours:
import numpy as np
import cv2
im = cv2.imread('10_euros_test1.jpg')
print im.shape #check if the image is loaded correctly
imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imgray,127,255,0)
contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(im,contours,-1,(255,255,0),-1)
cv2.imshow("window title", im)
cv2.waitKey()
this is my banknote images:
What should I do right now to rotate them? Any example of getRotationMatrix2d fucntion?, I don't know how to get angles from here.
I think, there is something wrong witht he background in the second photo, maybe it is because of the lines in the table...

Python opencv drawContours does not show anything

I followed the tutorial at this page but nothing seems to happen when the line cv2.drawContours(im,contours,-1,(0,255,0),3) is executed. I was expecting to see star.jpg with a green outline, as shown in the tutorial. Here is my code:
import numpy as np
import cv2
im = cv2.imread('C:\Temp\ip\star.jpg')
print im.shape #check if the image is loaded correctly
imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imgray,127,255,0)
contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(im,contours,-1,(0,255,0),3)
pass
There are no error messages. star.jpg is the star from the above mentioned webpage.
I am using opencv version 2.4.8 and Python 2.7.
Is drawContours supposed to show an image on my screen? If so, what did I do wrong? If not, how do I show the image?
Thanks
Edit:
Adding the following lines will show the image:
cv2.imshow("window title", im)
cv2.waitKey()
waitKey() is needed otherwise the window will just show a gray background. According to this post, that's because waitKey() tells it to start handling the WM_PAINT event.
I had the same issue. I believe the issue is that the underlying image is 1-channel rather than 3-channel. Therefore, you need to set the color so it's nonzero in the first element (e.g. (255,0,0)).
i too had the same problem. The thing is it shows, but too dark for our eyes to see.
Solution:
change the colour from (0,255,0) (for some weird reason, i too had give exactly the same color!) to (128,255,0) (or some better brighter colour)
You have to do something to the effect of:
cv2.drawContours(im,contours,-1,(255,255,0),3)
cv2.imshow("Keypoints", im)
cv2.waitKey(0)
I guess your original image is in gray bit plane. Since your bit plane is Gray instead of BGR and so the contour is not showing up. Because it's slightly black and grey which you cannot distinguish. Here's the simple solution [By converting the bit plane]:
im=cv2.cvtColor(im,cv2.COLOR_GRAY2BGR)
cv2.drawContours(im,contours,-1,(0,255,0),3)

Detect object with openCV and python

I'm trying to detect the white dots in the following image using OpenCV and Python.
I tried using the function cv2.HoughCircles but without any success.
Do I need to use a different method?
This is my code:
import cv2, cv
import numpy as np
import sys
if len(sys.argv)>1:
filename = sys.argv[1]
else:
filename = 'p.png'
img_gray = cv2.imread(filename,cv2.CV_LOAD_IMAGE_GRAYSCALE)
if img_gray==None:
print "cannot open ",filename
else:
img = cv2.GaussianBlur(img_gray, (0,0), 2)
cimg = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR)
circles = cv2.HoughCircles(img,cv2.cv.CV_HOUGH_GRADIENT,4,10,param1=200,param2=100,minRadius=3,maxRadius=100)
if circles:
circles = np.uint16(np.around(circles))
for i in circles[0,:]:
cv2.circle(cimg,(i[0],i[1]),i[2],(0,255,0),1)
cv2.circle(cimg,(i[0],i[1]),2,(0,0,255),3)
cv2.imshow('detected circles',cimg)
cv2.waitKey(0)
cv2.destroyAllWindows()
If you can reproduce a morphological reconstruction in OpenCV, you can easily build a h-dome transform which simplifies the task significantly. Otherwise, a simple threshold on a gaussian filtering might be enough too.
Binarize[FillingTransform[GaussianFilter[f, 2], 0.4, Padding -> 1]]
The gaussian filtering was done in the code above to effectively suppress the noise around the border of the input, which would remain after the h-dome transform otherwise.
Next there is the result of a simple threshold after a gaussian filtering (Binarize[GaussianFilter[f, 2], 0.5]) as well another result that is given by a direct binarization using Kapur's thresholding method (see the paper "A new method for gray-level picture thresholding using the entropy of the histogram" (which is no longer a new method, it is from 1985)):
The right image above has a lot of small points all over the border (which cannot be seen at this image resolution), but is fully automatic. From these 3 options, only the second one is already present in OpenCV.
I think a median filter will improve your image. Try to experiment with some kernels, 3x3 or 7x7. Then after that some (local) thresholding algorithm will get you shapes. You can either you HoughCircles, or just find contours and check them for roundness.
Convert the image to binary image using a suitable threshold technique (Otsu might help). Then use morphological operations like erosion to make circles smaller and then you can easily find their centers.

Categories

Resources