python - 如何使用 OpenCV 从图像中裁剪和提取图章?

标签 python image opencv image-processing computer-vision

我是 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)

First Example Image

Second Example Image

真实图像 First Real Example Image

Second Real Example Image

最佳答案

这是一个简单的方法:

  1. 获取二值图像。我们加载图像,转换为灰度、高斯模糊,然后进行 Otsu 阈值以获得二值图像。

  2. 消除小瑕疵和噪音。创建一个矩形结构元素并变形打开以消除小噪音。然后假设印章是单个轮廓,将各个轮廓合并为单个轮廓。

  3. 检测并提取印章 ROI。查找轮廓,使用轮廓区域和形状近似进行过滤。这个想法是,如果轮廓有四个顶点,那么它就是正方形。我们可以使用 Numpy 切片提取图章 ROI 并保存图章


提取的 ROI 结果

这是评论中另外两个输入图像的结果。假设对于每个图像,只有一个图章或一组相邻的图章。对于这些情况,我们按轮廓区域排序并假设最大的轮廓是印章。

enter image description here

enter image description here

代码

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()

关于python - 如何使用 OpenCV 从图像中裁剪和提取图章?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72020710/

相关文章:

python - 高效计算过滤列表的大小

安卓图像和按钮

opencv - 是否有将 3 channel 垫拆分为三个 3 channel 垫而不是分成三个 1 channel 垫的内置函数?

android - 在Android上使用USB相机和OpenCV

python - 在 Python 中,如何确定对象是否仍然存在?

python - 是否可以将 Python 或 Perl 与 Ruby 集成?

image - Sprite 和纹理的区别?

html - "img"中的"td"和"background-image"中的"td"高度不同

java - 将帧(android 中的 mat 数据)从 android 传递到 native c++ 并检测人脸

python - 函数可以知道它们是否已经在 Python 中被多处理(joblib)