I'm new to Image Processing in Python and I'm trying to solve a common problem. I have an image having a signature of a person. I want to find the edges and crop it to fit the signature in the image.
Input Image
Expected Output
I tried Canny Edge Detection and cropping the image using a list of existing solutions (articles & answers) using PIL, CV2, but none seem to work. I'm looking for a working solution.
Some solutions I tried:
https://www.quora.com/How-can-I-detect-an-object-from-static-image-and-crop-it-from-the-image-using-openCV
Crop Image from all sides after edge detection
How to crop biggest rectangle out of an image
and many more... None worked although seems very simple. I encountered either errors or not expected output using any of the existing solutions.
What you need is thresholding. In OpenCV you can accomplish this using cv2.threshold()
.
I took a shot at it. My approach was the following:
- Convert to grayscale
- Threshold the image to only get the signature and nothing else
- Find where those pixels are that show up in the thresholded image
- Crop around that region in the original grayscale
- Create a new thresholded image from the crop that isn't as strict for display
Here was my attempt, I think it worked pretty well.
import cv2
import numpy as np
# load image
img = cv2.imread('image.jpg')
rsz_img = cv2.resize(img, None, fx=0.25, fy=0.25) # resize since image is huge
gray = cv2.cvtColor(rsz_img, cv2.COLOR_BGR2GRAY) # convert to grayscale
# threshold to get just the signature
retval, thresh_gray = cv2.threshold(gray, thresh=100, maxval=255, type=cv2.THRESH_BINARY)
# find where the signature is and make a cropped region
points = np.argwhere(thresh_gray==0) # find where the black pixels are
points = np.fliplr(points) # store them in x,y coordinates instead of row,col indices
x, y, w, h = cv2.boundingRect(points) # create a rectangle around those points
x, y, w, h = x-10, y-10, w+20, h+20 # make the box a little bigger
crop = gray[y:y+h, x:x+w] # create a cropped region of the gray image
# get the thresholded crop
retval, thresh_crop = cv2.threshold(crop, thresh=200, maxval=255, type=cv2.THRESH_BINARY)
# display
cv2.imshow("Cropped and thresholded image", thresh_crop)
cv2.waitKey(0)
And here's the result: