At my website I receive an image contains the user fingerprint and signature, I wan't to extract these two pieces of information.
for example:
Original Image
import os
import cv2
import numpy as np
def imshow(label, image):
cv2.imshow(label, image)
cv2.waitKey(0)
cv2.destroyAllWindows()
#read image
rgb_img = cv2.imread('path')
rgb_img = cv2.resize(rgb_img, (900, 600))
gray_img = cv2.cvtColor(rgb_img, cv2.COLOR_BGR2GRAY)
Gray Image
#canny edge detection
canny = cv2.Canny(gray_img, 50, 120)
canny edge image
# Morphology Closing
kernel = np.ones((7, 23), np.uint8)
closing = cv2.morphologyEx(canny, cv2.MORPH_CLOSE, kernel)
Morphology Closing
# Find contours
contours, hierarchy = cv2.findContours(closing.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
# Sort Contors by area and then remove the largest frame contour
n = len(contours) - 1
contours = sorted(contours, key=cv2.contourArea, reverse=False)[:n]
copy = rgb_img.copy()
# Iterate through contours and draw the convex hull
for c in contours:
if cv2.contourArea(c) < 750:
continue
hull = cv2.convexHull(c)
cv2.drawContours(copy, [hull], 0, (0, 255, 0), 2)
imshow('Convex Hull', copy)
Image divided to parts
Now my goals are:
Know which part is the signature and which is the fingerprint
Resolve the contours overlapping if exist
P.S: I'm not sure if the previous steps are final so please if you have better steps tell me.
These are some hard examples i may wanna deal with
You can use morphology for finger print and signature selecting.
By example:
import cv2
import numpy as np
img = cv2.imread('fhZCs.png')
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
img=cv2.bitwise_not(img) #negate image
#color definition
blue_upper = np.array([130,255,255])
blue_lower = np.array([115,0,0])
#blue color mask (sort of thresholding, actually segmentation)
mask = cv2.inRange(hsv, blue_lower, blue_upper)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (20,20))
finger=cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
mask2=cv2.morphologyEx(finger, cv2.MORPH_DILATE, kernel)
signature=cv2.compare(mask2, mask, cv2.CMP_LT)
signature=cv2.morphologyEx(signature, cv2.MORPH_DILATE, kernel)
signature=cv2.bitwise_and(img, img, mask=signature)
signature=cv2.bitwise_not(signature)
finger=cv2.bitwise_and(img, img, mask=finger)
finger=cv2.bitwise_not(finger)
cv2.imwrite('finger.png', finger)
cv2.imwrite('signature.png',signature)
Related
Need to apply erosion only to the lines in my image which are more thicker using python
Here is my input image
I'm having a image which contains white lines with both thick and thin lines,my goal is to erode only the lines which are more thicker using python.i used normal erosion using opencv when applying this method thin lines are removing from the image.Erosion has to apply only on thick lines
import cv2
import numpy as np
img = cv2.imread('123.png',0)
kernel = np.ones((6,6),np.uint8)
erosion = cv2.erode(img,kernel,iterations = 1)
cv2.imshow("Result", erosion)
cv2.waitKey(0)
cv2.destroyAllWindows()
How can i achieve this any answers will be highly useful for me.Thanks in advance
Here is one way to do that in Python/OpenCV.
Read the input as grayscale
Threshold it
Apply morphology close to remove the thin lines and save as a mask image
Apply morphology dilate to the threshold image again to thin the lines
Use np.where() to combine the threshold and dilated images using the mask
Save the results
Input:
import cv2
import numpy as np
# read the input as grayscale
img = cv2.imread('black_lines.jpg', cv2.IMREAD_GRAYSCALE)
# threshold
thresh = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)[1]
# apply morphology close to remove the thin lines and save as mask
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
mask = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
# apply morphology dilate to thin image as desired
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
dilate = cv2.morphologyEx(thresh, cv2.MORPH_DILATE, kernel)
# combine the thresh and dilate using mask
result = np.where(mask==0, dilate, thresh)
# save results
cv2.imwrite('black_lines_mask.jpg', mask)
cv2.imwrite('black_lines_dilate.jpg', dilate)
cv2.imwrite('black_lines_thinned.jpg', result)
# show results
cv2.imshow('mask', mask)
cv2.imshow('dilate', dilate)
cv2.imshow('thinned', result)
cv2.waitKey(0)
Mask Image:
Dilate Image:
Combined Image with thin lines:
I have an image of a robot moving, I need to extract the white rings
in order to find the midpoint of the robot. But thresholding is not giving correct result:
What method should I try to extract only the white rings.
%code to get second image
img=imread('data\Image13.jpg');
hsv=rgb2hsv(img);
bin=hsv(:,:,3)>0.8;
Something like that?
import cv2
import numpy as np
# get bounding rectangles of contours
img = cv2.imread('img.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY)
contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# filter contours by area and width
contours = [c for c in contours if (50 < cv2.contourArea(c) < 500) and cv2.boundingRect(c)[2] > 20]
# draw contours on empty mask
out = np.zeros(thresh.shape, dtype=np.uint8)
cv2.drawContours(out, contours, -1, 255, -1)
cv2.imwrite('out.png', out)
Output:
Since image processing and computer vision aren't of my field of study I'm having difficulty finding an algorithm that can identify the positions of rectangles of known size and proportion in certain images to automate a process.
These are grayscale images containing some circles and only one or none white rectangle with rounded edges, as can be seen in the example figure below.
3 different imagens with the "same" retangle to be found
Thank you
Try OpenCV, it stands for Open Computer Vision. It’s free. This is written in Python.
import cv2
import numpy as np
img = cv2.imread("C:\\Users\\mogar\\Desktop\\temp.jpg")
grayImage = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(grayImage, 160, 255, cv2.THRESH_BINARY)
kernel = np.ones((5,5),np.uint8)
thresh = cv2.erode(thresh,kernel,iterations = 1)
#thresh = np.invert(thresh)
cv2.imshow("Threholded Image", thresh)
cv2.waitKey(0) & 0xFF == ord('q')
cv2.destroyAllWindows()
_, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
for cnts in contours:
rect = cv2.minAreaRect(cnts)
box = cv2.boxPoints(rect)
box = np.int0(box)
(x,y),(w,h),angle = rect
w = int(w)
h = int(h)
area = w*h
if area > 10000 and area < 100000:
print("Area Check", area)
cv2.drawContours(img, [box], 0, (0,0,255), 5)
small = cv2.resize(img, (0,0), fx=0.3, fy=0.3)
cv2.imshow("Contours", small)
cv2.waitKey(0) & 0xFF == ord('q')
cv2.destroyAllWindows()
You may need to adjust some of the threshold values and area values so that you'll be enclosing only the rectangles. You'll notice the rectangles are not fully enclosed right now, that is literally because the text is getting in the way and cutting the rectangles in half. If you had a clean image; I'm sure this would work great. If you have any questions please don't hesitate the ask, but it may take some time before I can answer.
I have been trying to separate the human body in an image from the background, but all the methods I have seen don't seem to work very well for me.
I have collected the following images;
The image of the background
The image of the background with the person in it.
Now I want to cut out the person from the background.
I tried subtracting the image of the background from the image with the person using res = cv2.subtract(background, foreground) (I am new to image processing).
Background subtraction methods in opencv like cv2.BackgroundSubtractorMOG2() and cv2.BackgroundSubtractorMOG2() only works with videos or image sequence and contour detection methods I have seen are only for solid shapes.
And grabCut doesn't quite work well for me because I would like to automate the process.
Given the images I have (Image of the background and image of the background with the person in it), is there a method of cutting the person out from the background?
I wouldn't recommend a neural net for this problem. That's a lot of work for something like this where you have a known background. I'll walk through the steps I took to do the background segmentation on this image.
First I shifted into the LAB color space to get some light-resistant channels to work with. I did a simple subtractions of foreground and background and combined the a and b channels.
You can see that there is still significant color change in the background even with a less light-sensitive color channel. This is likely due to the auto white balance on the camera, you can see that some of the background colors change when you step into view.
The next step I took was thresholding off of this image. The optimal threshold values may not always be the same, you'll have to adjust to a range that works well for your set of photos.
I used openCV's findContours function to get the segmentation points of each blob and I filtered the available contours by size. I set a size threshold of 15000. For reference, the person in the image had a pixel area of 27551.
Then it's just a matter of cropping out the contour.
This technique works for any good thresholding strategy. If you can improve the consistency of your pictures by turning off auto settings and ensure good contrast of the person against the wall then you can use simpler thresholding strategies and get good results.
Just for fun:
Edit:
I forgot to add in the code I used:
import cv2
import numpy as np
# rescale values
def rescale(img, orig, new):
img = np.divide(img, orig);
img = np.multiply(img, new);
img = img.astype(np.uint8);
return img;
# get abs(diff) of all hue values
def diff(bg, fg):
# do both sides
lh = bg - fg;
rh = fg - bg;
# pick minimum # this works because of uint wrapping
low = np.minimum(lh, rh);
return low;
# load image
bg = cv2.imread("back.jpg");
fg = cv2.imread("person.jpg");
fg_original = fg.copy();
# blur
bg = cv2.blur(bg,(5,5));
fg = cv2.blur(fg,(5,5));
# convert to lab
bg_lab = cv2.cvtColor(bg, cv2.COLOR_BGR2LAB);
fg_lab = cv2.cvtColor(fg, cv2.COLOR_BGR2LAB);
bl, ba, bb = cv2.split(bg_lab);
fl, fa, fb = cv2.split(fg_lab);
# subtract
d_b = diff(bb, fb);
d_a = diff(ba, fa);
# rescale for contrast
d_b = rescale(d_b, np.max(d_b), 255);
d_a = rescale(d_a, np.max(d_a), 255);
# combine
combined = np.maximum(d_b, d_a);
# threshold
# check your threshold range, this will work for
# this image, but may not work for others
# in general: having a strong contrast with the wall makes this easier
thresh = cv2.inRange(combined, 70, 255);
# opening and closing
kernel = np.ones((3,3), np.uint8);
# closing
thresh = cv2.dilate(thresh, kernel, iterations = 2);
thresh = cv2.erode(thresh, kernel, iterations = 2);
# opening
thresh = cv2.erode(thresh, kernel, iterations = 2);
thresh = cv2.dilate(thresh, kernel, iterations = 3);
# contours
_, contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE);
# filter contours by size
big_cntrs = [];
marked = fg_original.copy();
for contour in contours:
area = cv2.contourArea(contour);
if area > 15000:
print(area);
big_cntrs.append(contour);
cv2.drawContours(marked, big_cntrs, -1, (0, 255, 0), 3);
# create a mask of the contoured image
mask = np.zeros_like(fb);
mask = cv2.drawContours(mask, big_cntrs, -1, 255, -1);
# erode mask slightly (boundary pixels on wall get color shifted)
mask = cv2.erode(mask, kernel, iterations = 1);
# crop out
out = np.zeros_like(fg_original) # Extract out the object and place into output image
out[mask == 255] = fg_original[mask == 255];
# show
cv2.imshow("combined", combined);
cv2.imshow("thresh", thresh);
cv2.imshow("marked", marked);
# cv2.imshow("masked", mask);
cv2.imshow("out", out);
cv2.waitKey(0);
Since it is very easy to find dataset consist a lot of human body, I suggest you to implement neural network segmentation tecniques to extract human body perfectly. Please check this link to see similar example.
I'm doing small project using tesseract OCR.
What I want to read is Digital Number which is generated by oven.
I pre-treat the image using openCV
but, tesseract can't read the image correct.
eg. 194 as 794..
let me know is there any way to deal with this.
thanks.
the Image which I want to read is shown below
import cv2
import numpy
img_color = cv2.imread('20190509_103247.jpg', cv2.IMREAD_COLOR)
dst = img_color.copy()
roi = img_color[1600:1800,600:1100]
dst[0:200,0:500]=roi
blur = cv2.GaussianBlur(roi,(5,5),0)
gray_dst = cv2.cvtColor(blur, cv2.COLOR_BGR2GRAY)
ret, thr = cv2.threshold(gray_dst, 70, 255,cv2.THRESH_BINARY)
canny = cv2.Canny(roi,100,255)
sobel = cv2.Sobel(gray_dst,cv2.CV_8U,1,0,3)
laplacian = cv2.Laplacian(gray_dst,cv2.CV_8U,ksize=3)
rev = cv2.bitwise_not(canny)
# blur = cv2.GaussianBlur(roi,(5,5),0)
# stencil = numpy.zeros(rev.shape).astype(rev.dtype)
# _, contours, _ = cv2.findContours(rev, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# color = [255, 255, 255]
# cv2.fillPoly(stencil, contours, color)
# result = cv2.bitwise_and(rev, stencil)
cv2.namedWindow('Show Image')
cv2.imshow('Show Image', rev)
cv2.waitKey(0)
cv2.imwrite('savedimage.jpg', rev)
cv2.destroyAllWindows()
You can create training data that will work for your font / glyphs to improve how the numeric display gets transformed to the correct digits.
References:
https://github.com/tesseract-ocr/tesseract/wiki/TrainingTesseract-4.00#creating-training-data
https://github.com/DevashishPrasad/LCD-OCR