如何使用 OpenCV 从图像中裁剪和提取图章?
How to crop and extract stamp from an image with OpenCV?
我是 OpenCV 的新手。
我有一张邮票的“简单”图像,我已经对其进行了一些处理,如您在下面的代码中所见。
现在我遇到了裁剪图像以获得邮票的问题。
边缘上的点和条纹会干扰我当前识别邮票的代码。
图片可能不同,因此无法固定图片的位置。
代码:
img = cv2.imread('./images/image.JPG')
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img_blur = cv2.GaussianBlur(img_gray, (3,3), 0)
edges = cv2.Canny(image=img_blur, threshold1=100, threshold2=200)
真实图片
这是一个简单的方法:
得到二值图像。我们加载图像,转换为灰度,高斯模糊,然后Otsu的阈值得到二值图像。
去除小的伪像和噪音。 创建一个矩形结构元素并变形打开以去除小的噪音。然后变形接近以将单个轮廓组合成单个轮廓,假设图章是单个轮廓。
检测并提取图章 ROI。 查找轮廓,使用轮廓区域和形状近似进行过滤。这个想法是,如果一个轮廓有四个顶点,那么它就是一个正方形。我们可以使用 Numpy 切片提取图章 ROI 并保存图章
提取的 ROI 结果
这是来自评论的其他两个输入图像的结果。假设对于每个图像,只有一个图章或一组相邻的图章。对于这些情况,我们按轮廓区域排序并假设最大的轮廓是邮票。
代码
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()
我是 OpenCV 的新手。 我有一张邮票的“简单”图像,我已经对其进行了一些处理,如您在下面的代码中所见。 现在我遇到了裁剪图像以获得邮票的问题。 边缘上的点和条纹会干扰我当前识别邮票的代码。 图片可能不同,因此无法固定图片的位置。
代码:
img = cv2.imread('./images/image.JPG')
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img_blur = cv2.GaussianBlur(img_gray, (3,3), 0)
edges = cv2.Canny(image=img_blur, threshold1=100, threshold2=200)
真实图片
这是一个简单的方法:
得到二值图像。我们加载图像,转换为灰度,高斯模糊,然后Otsu的阈值得到二值图像。
去除小的伪像和噪音。 创建一个矩形结构元素并变形打开以去除小的噪音。然后变形接近以将单个轮廓组合成单个轮廓,假设图章是单个轮廓。
检测并提取图章 ROI。 查找轮廓,使用轮廓区域和形状近似进行过滤。这个想法是,如果一个轮廓有四个顶点,那么它就是一个正方形。我们可以使用 Numpy 切片提取图章 ROI 并保存图章
提取的 ROI 结果
这是来自评论的其他两个输入图像的结果。假设对于每个图像,只有一个图章或一组相邻的图章。对于这些情况,我们按轮廓区域排序并假设最大的轮廓是邮票。
代码
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()