How to detect and split the stamps of each image using OpenCV (C++ or python)?
Below are two sample images:
One simple method would be to use contouring/edge detection to extract the desired shape.
You should try out Canny Edge Detector, it has support on OpenCV.
If you're trying contouring, you will have to try changing the number of iteration of the dilation or erosion functions (depending on your code) so that each stamp remains a separate entity.
Following that, you can simply find extract each contour and extract them into separate images. This snippet should help you out with the above mentioned part
x, y, w, h = cv2.boundingRect(contour)
cv2.rectangle(rgb_image, (x, y), (x + w, y + h), settings['outline_color'],settings['outline_thickness'])
roi = rgb_image[y:y+h, x:x+w]
cv2.imwrite("/Path/",roi)
#Settings is a dictionary, ignore it.
Related
I have a hundreds of ID card images which some of them provided below:
(Disclaimer: I downloaded the images from the Web, all rights (if exist) belong to their respective authors)
As seen, they are all different in terms of brightness, perspective angle and distance, card orientation. I'm trying to extract only rectangular card area and save it as a new image. To achieve this, I came to know that I must convert an image to grayscale image and apply some thresholding methods. Then, cv2.findCountours() is applied to threshold image to get multiple vector points.
I have tried many methods and come to use cv2.adaptiveThreshold() as it is said that it finds a value for threshold (because, I can't manually set threshold values for each image). However, when I apply it to images, I am not getting what I want. For example:
My desired output should look like this:
It seems like it also includes affine transformations to make the card area (Obama case) proper but I am finding it difficult to understand. If that's possible I'd further extract and save the image separately.
Is there any other method or algorithm that can achieve what I want? It should consider different lighting conditions and card orientations. I am expecting one-fits-all solution given there will be only one rectangle ID card. Please, guide me through this with whatever you think will be of help.
Note that I can't use CNNs as object detector, it must be based on purely image-processing.
Thank you.
EDIT:
The code for the above results is pretty simple:
image = cv2.imread(args["image"])
gray_img = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh_img = cv2.adaptiveThreshold(gray_img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV,51,9)
cnts = cv2.findContours(thresh_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
area_treshold = 1000
for cnt in cnts:
if cv2.contourArea(cnt) > area_treshold:
x,y,w,h = cv2.boundingRect(cnt)
print(x,y,w,h)
cv2.rectangle(image, (x, y), (x + w, y + h), (36,255,12), 3)
resize = ResizeWithAspectRatio(image, width=640)
cv2.imshow("image", resize)
cv2.waitKey()
EDIT 2:
I provide the gradient magnitude images below:
Does it mean I must cover both low and high intensity values? Because the edges of the ID cards at the bottom are barely noticeable.
I have a video file and I need to circle all moving objects in a certain frame I select. My idea of a solution to this problem is:
Circle all moving objects (white areas) on a video on which was applied motion detector and circle the same areas on the original frame.
I am using BackgroundSubtractorGMG() from cv2 to detect movement
Below I show the way I expect this program to work(I used to paint, so I am now sure this is correct, but I hope it is good enough to demonstrate the concept)
As others have said in comments:
Get the mask from you background subtraction algorithm
use cv.findContours(mask, ...) to find contours
(optional) select which contours you want to keep (something like ((x, y), radius) = cv.minEnclosingCircle(contour) or a, b, w, h = cv.boundingRect(c)
and if radius > 5
use drawing functions like cv.rectangle or similar to draw the shape around the contour (like so: cv.rectangle(img, (a, b), (a + w, b + h), (0, 255, 0), 2))
I have a bounding box whose coordinates are given by (x, y, w, h) where x and y are top-left coordinates of the box. I'd like to apply a blur or gradient outside the box. How would I create a mask using the coordinates above and apply this effect outside the mask with either PIL or cv2 similar to the image below?
Here is an example, I think that should be helpful to adapt it to your program.
import cv2
original = cv2.imread("spidy.png", 3)
blurred = cv2.GaussianBlur(original, (25,25), 0)
original[0:500, 0:500] = blurred[0:500, 0:500]
cv2.imwrite('cvBlurredOutput.jpg', original)
1) First read Image
2) Blur it, the parameter (25,25) is the blur kernel, basically the width/height of your "blur Brush"
3) finally copy the region of interest from the blurred to the original
I have extracted features from hog.compute function and then used those features to train an SVM classifier. I used a script that I found online to separate rho and support vectors from the classified file.
tree = ET.parse('svm_data.xml')
root = tree.getroot()
SVs = root.getchildren()[0].getchildren()[-2].getchildren()[0]
rho = float( root.getchildren()[0].getchildren()[-1].getchildren()[0].getchildren()[1].text)
svmvec = [float(x) for x in re.sub( '\s+', ' ', SVs.text).strip().split(' ')]
svmvec.append(-rho)
pickle.dump(svmvec, open("svm.pickle", 'wb'))
This code saved the rho and support vectors to a different file which I provided to the hog.DetectMultiScale function. Initially I got the CheckDetectorSize errors, but somehow i dealt with them. But now that it finally executes, why does it always draw a rectangle on the center instead of a person?
Check here
The final code that uses the file generated from the above code, to draw rectangles on the detected area(s):
hog = cv2.HOGDescriptor("hog.xml") svm =
pickle.load(open("svmcoeff.pickle", 'rb'))
hog.setSVMDetector(np.array(svm))
for i in range(1,9): image = cv2.imread('test-'+str(i)+'.png') image =
imutils.resize(image, width=min(300, image.shape[1])) orig =
image.copy()
(rects, weights) = hog.detectMultiScale(image)
for (x, y, w, h) in rects: cv2.rectangle(orig, (x, y), (x + w, y + h), (0, 0, 255),2)
rects = np.array([[x, y, x + w, y + h] for (x, y, w, h) in rects])
pick = non_max_suppression(rects, probs=None,overlapThresh=0.65)
for (xA, yA, xB, yB) in pick: cv2.rectangle(image, (xA, yA), (xB, yB), (0, 255, 0), 2)
cv2.imshow("Before NMS", orig) cv2.imshow("After NMS", image)
key = cv2.waitKey(0) if key == 27: continue
I can't directly answer your question but I can suggest debugging steps.
First, have you checked what the SVM coefficients look like (the upper code post)? You are making a lot of content dependent operations such as picking the last element in an array, and the text field in there, and text substitution, etc. I don't know the format of your svm_data.xml and can't say anything about the correctness of these steps. But you should definitely check the output at every step of this code, and especially svmvec. Compare these values to what you get from the original object/method/etc. you produced svm_data.xml with - most SVM implementations have methods to access these parameters interactively, e.g. in Matlab or python.
You should correct the formatting of your second code post, which is significant for python code. I guess you're somehow missing line breaks.
Here again first step should be to check the values you read into svm and compare to the originals.
Make sure the rectangle parameters returned by HoG detector and those used by cv.rectangle are compatible. Your code looks OK (and checks with online examples). But I would still try drawing a few rectangles manually just to check.
You also do a non-max suppression. Is there a difference before and after? You should first verify that you get something meaningful before. First check HoG detector returns something meaningful in rects, something other than a rectangle at the center of the image. If it is not doing that, then your problem is before that point in the process. If the rects contain nice rectangles but you don't see them drawn, then your problem is there and should be easy to fix.
If the problem is in rects, then you should go back and verify each step beforehand. I already mentioned tracking the SVM parameters from where you generate them up until you set them to HoG detector. Then you can try running the HoG detector with its default person detector to see if you have the whole detection process working.
These are what I can think of at this point.
I have "n" number of contour detected images(frame). I wants to find mean value for the rectangle portion of that image. (Instead of finding mean value for a full image, i need to calculate the mean value for the rectangle portion of that image.)
I have rectangle's x,y position and width, height values. First Image x,y,w,h is 109,45 ,171,139 and second image x,y,w,h is 107,71,175,110. I get the values using the below code. cv2.rectangle(frame, (x,y),(x+w,y+h), (0,0,255), 3) I know using "ROI" concept we can do mean calculation. So, I referred some links. Ex. Get the ROI of two binary images and find difference of the mean image intesities between 2 ROI in python. But, I have confused with the parameter settings. Can anyone help me to resolve my problem ? Thanks in advance...
There's easier way to get rectangle from an image in Python. Since cv2 operates on NumPy arrays, you can use normal slicing (note, that i corresponds to y and j - to x, not the other way):
rect = image[i:i+h, j:j+w]
And taking mean is even simpler:
rect.mean()