这是一个简单的方法:
-
获取二值图像。我们加载图像,转换为灰度,高斯模糊,然后Otsu阈值以获得二值图像。
-
消除小伪影和噪音。创建一个矩形结构元素并变形打开以消除少量噪音。然后,假设印章是单个轮廓,则变形接近以将各个轮廓组合成单个轮廓。
-
检测并提取邮票投资回报率。查找轮廓,使用轮廓面积和形状近似进行过滤。这个想法是,如果轮廓有四个顶点,那么它就是正方形。我们可以使用 Numpy 切片提取邮票 ROI 并保存邮票
提取的 ROI 结果
这是评论中其他两个输入图像的结果。假设对于每个图像,只有一个图章或一组相邻的图章。对于这些情况,我们按轮廓区域排序并假设最大的轮廓是印章。
Code
import cv2
# Load image, grayscale, Gaussian blur, Otsu's threshold
image = cv2.imread("1.jpg")
original = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (5,5), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
# Morph operations to remove small artifacts and noise
open_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, open_kernel, iterations=1)
close_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (7,7))
close = cv2.morphologyEx(opening, cv2.MORPH_CLOSE, close_kernel, iterations=2)
# Find contours, filter using contour area, and shape approximation
cnts = cv2.findContours(close, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)
for c in cnts:
peri = cv2.arcLength(c, True)
area = cv2.contourArea(c)
approx = cv2.approxPolyDP(c, 0.05 * peri, True)
# Assumption is if the contour has 4 vertices then its a square shape
# 2nd assumption is that there's only one stamp, or one group of stamps
if len(approx) == 4 and area > 100:
x,y,w,h = cv2.boundingRect(approx)
ROI = original[y:y+h, x:x+w]
cv2.imshow("ROI", ROI)
cv2.imwrite("ROI.png", ROI)
break
cv2.waitKey()