我想从扫描件上剪下身份证 请注意,id 下有很多空白(直到这里)
首先,我对图像进行预处理:
def preprocess_before_crop_2(scan_path, output_dir):
# Read the image
original_image = cv2.imread(scan_path)
# Grayscale
gray = cv2.cvtColor(original_image, cv2.COLOR_BGR2GRAY)
# Histogram Equalization on grayscale image
equalized = cv2.equalizeHist(gray)
# Initial Denoising
denoised = cv2.fastNlMeansDenoising(equalized, None, h=20, templateWindowSize=7, searchWindowSize=21)
# Sharpening kernel
kernel = np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]])
sharpened = cv2.filter2D(denoised, -1, kernel)
# Bilateral filter
bilateral_filtered = cv2.bilateralFilter(sharpened, d=9, sigmaColor=75, sigmaSpace=75)
# Increase Contrast
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
contrast = clahe.apply(bilateral_filtered)
# Apply slight Gaussian blur before binarization for anti-aliasing
blurred = cv2.GaussianBlur(contrast, (3, 3), 0)
# Binary conversion with Otsu's thresholding
_, binary = cv2.threshold(blurred, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# Adaptive thresholding
adaptive_thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
return adaptive_thresh
然后我用它来裁剪图像:
def crop_document(scan_path, output_dir):
original_image = cv2.imread(scan_path)
# preprocess image
preprocessed_image = preprocess_before_crop(scan_path, output_dir)
contours, hierarchy = cv2.findContours(preprocessed_image,cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
# Find object with the biggest bounding box
mx = (0,0,0,0) # biggest bounding box so far
mx_area = 0
areas = []
for cont in contours:
x,y,w,h = cv2.boundingRect(cont)
area = w*h
ratio = float(w) / float(h)
areas.append((area,ratio))
if area > mx_area and ratio > 1:
mx = x,y,w,h
mx_area = area
x,y,w,h = mx
# Crop and save
cropped_image=original_image[y:y+h,x:x+w]
return cropped_image
但是,生成的裁剪图像如下所示:(我添加了一个我想要裁剪的红色矩形)
我尝试删除/更改预处理步骤中的一些步骤,但无济于事。
问题是您感兴趣的对象连接到左上角的黑色角。 这已经发生在 cv2.equalizeHist() 步骤中:
import matplotlib.pyplot as plt
plt.imshow(equalized)
plt.axis('off')
plt.show()
只需忽略该步骤并采用第二大轮廓即可完成工作:
denoised = cv2.fastNlMeansDenoising(gray, None, h=20, templateWindowSize=7, searchWindowSize=21)
# ...
preprocessed_image = adaptive_thresh
#sort by area
contours = cv2.findContours(preprocessed_image, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
contours = sorted(contours, key=cv2.contourArea, reverse=True)
#select 2nd largest contour
x,y,w,h = cv2.boundingRect(contours[1])
cropped_image=original_image[y:y+h,x:x+w]
#display cropped image
plt.imshow(cropped_image)
plt.axis('off')
plt.show()
#display the respective contour
cv2.drawContours(original_image, [contours[1]], -1, (0, 255, 0), 20)
plt.imshow(original_image)
plt.axis('off')
plt.show()
裁剪后的图像:
感兴趣的轮廓: