如何使用OpenCV从图像中检测和提取签名?

5
我正在导入附加的图片。 导入图像后,我想删除水平线,检测签名,然后提取它,创建围绕签名的矩形,裁剪矩形并保存。 我很难确定整个签名区域是一个轮廓还是一组轮廓。
我已经尝试了findcontour,然后使用不同的方法来检测签名区域。 请参考下面的代码。 Python脚本:
imagePath

#read image
image = cv2.imread(imagePath,cv2.COLOR_BGR2RGB)

#Convert to greyscale
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY) # grayscale

#Apply threshold
ret,thresh1 = cv2.threshold(gray, 0, 255,cv2.THRESH_OTSU|cv2.THRESH_BINARY_INV)

plt.imshow(thresh1,cmap = 'gray')


#preprocessing
rect_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (15,15))
dilation = cv2.dilate(thresh1, rect_kernel, iterations = 1)
plt.imshow(dilation,cmap = 'gray')


#Detect contours
contours, hierarchy = cv2.findContours(dilation, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
contours[0]

height, width, _ = image.shape
min_x, min_y = width, height
max_x = max_y = 0   
for contour, hier in zip(contours, hierarchy):
    (x,y,w,h) = cv2.boundingRect(contour)
    min_x, max_x = min(x, min_x), max(x+w, max_x)
    min_y, max_y = min(y, min_y), max(y+h, max_y)
    if w > 80 and h > 80:
        cv2.rectangle(frame, (x,y), (x+w,y+h), (255, 0, 0), 2)

if max_x - min_x > 0 and max_y - min_y > 0:
    fin=cv2.rectangle(image, (min_x, min_y), (max_x, max_y), (255, 0, 0), 2)

 

plt.imshow(fin)



final=cv2.drawContours(image, contours,-1,(0,0,255),6)

plt.imshow(final,cmap = 'gray')

最终目标是在整个签名周围创建矩形

我正在尝试的签名图像

试图推广到其他图像:

输入图像描述

1个回答

10

如果不想去掉水平线,可以尝试使用HSV颜色阈值处理。方法是将签名隔离到一个掩膜中,然后提取出来。我们将图像转换为HSV格式,然后使用较低/较高的颜色阈值生成掩膜。

lower = np.array([90, 38, 0])
upper = np.array([145, 255, 255])
mask = cv2.inRange(image, lower, upper)

口罩检测

enter image description here

要检测口罩的签名,我们可以使用 np.concatenate() 得到所有轮廓的联合边界框,然后使用 cv2.boundingRect() 获取坐标。

enter image description here

现在,我们有了边界框坐标,我们可以使用Numpy切片去剪裁并提取ROI(感兴趣区域)

import numpy as np
import cv2

# Load image and HSV color threshold
image = cv2.imread('1.jpg')
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
lower = np.array([90, 38, 0])
upper = np.array([145, 255, 255])
mask = cv2.inRange(hsv, lower, upper)
result = cv2.bitwise_and(image, image, mask=mask)
result[mask==0] = (255, 255, 255)

# Find contours on extracted mask, combine boxes, and extract ROI
cnts = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cnts = np.concatenate(cnts)
x,y,w,h = cv2.boundingRect(cnts)
cv2.rectangle(image, (x, y), (x + w, y + h), (36,255,12), 2)
ROI = result[y:y+h, x:x+w]

cv2.imshow('result', result)
cv2.imshow('mask', mask)
cv2.imshow('image', image)
cv2.imshow('ROI', ROI)
cv2.waitKey()

注意:下限/上限颜色范围是从选择正确的HSV边界来进行使用cv::inRange(OpenCV)进行颜色检测获得的。


谢谢。有一个问题。使用这种方法,我将无法仅提取签名。如何确定签名的起始和结束点,并仅裁剪图像的该部分?您能帮忙解决这个问题吗? - user3203657
检查更新,您可以获取所有轮廓的边界框,然后使用Numpy找到左上角和右下角坐标。从那里,您可以提取ROI。 - nathancy
我无法将此解决方案推广到其他一些图像。尝试在另一张图片上使用相同的方法,但它不起作用。我已经上传了上面的图片。你能帮忙吗? - user3203657
1
是的,尝试了一些形态学转换,效果非常好...谢谢nathancy.. - user3203657
@nathancy,你知道我怎么在Android Studio中使用OpenCV进行这个提取吗? - Tecnologia da Net
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接