python 基于OpenCV的手写体方框检测

uemypmqf  于 2023-02-18  发布在  Python
关注(0)|答案(2)|浏览(138)

我有下面的图像:

我想这样提取方框图:

以下是我的尝试:

import cv2
import matplotlib.pyplot as plt

# Load the image
image = cv2.imread('diagram.jpg')

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

# Apply thresholding to create a binary image
_, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV)

# Find contours
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# Draw the contours
cv2.drawContours(image, contours, -1, (0, 0, 255), 2)

# Show the final image
plt.imshow(image), plt.show()

然而,我意识到提取图表会很困难,因为轮廓不是闭合的:

我尝试过使用形态学闭合来闭合长方体边缘的间隙:

# Define a rectangular kernel for morphological closing
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))

# Perform morphological closing to close the gaps in the box edges
closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)

但这几乎改变不了什么。我应该如何处理这个问题呢?

cx6n0qe3

cx6n0qe31#

我们可以用扩张然后侵 eclipse 来代替形态闭合,但是**填充扩张和侵 eclipse 之间的轮廓。
为了填补空白,内核大小应该比5x5大得多(我使用了51x51)。
假设手写框是彩色的,我们可以从BGR转换为HSV,并在HSV的饱和度通道上应用阈值:

hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)  # Convert from BGR to HSV color space 
gray = hsv[:, :, 1]  # Use saturation from HSV channel as "gray".
_, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU)  # Apply automatic thresholding (use THRESH_OTSU).

应用大核扩张,并使用drawContours填充轮廓:

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (51, 51))  # Use relatively large kernel for closing the gaps   
dilated = cv2.dilate(thresh, kernel)  # Dilate with large kernel

contours, hierarchy = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(dilated, contours, -1, 255, -1)

填充轮廓后应用侵 eclipse 扩张后侵 eclipse 等同于闭合,但这里我们是填充后闭合。

closed = cv2.erode(dilated, kernel)

代码示例:

import cv2
import numpy as np

# Load the image
image = cv2.imread('diagram.png')

hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)  # Convert from BGR to HSV color space 

# Convert to grayscale
#gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = hsv[:, :, 1]  # Use saturation from HSV channel as "gray".

# Apply thresholding to create a binary image
_, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU)  # Apply automatic thresholding (use THRESH_OTSU).

thresh = np.pad(thresh, ((100, 100), (100, 100)))  # Add zero padding (required due to large dilate kernels).

# Define a rectangular kernel for morphological operations.
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (51, 51))  # Use relatively large kernel for closing the gaps

dilated = cv2.dilate(thresh, kernel)  # Dilate with large kernel

# Fill the contours, before applying erode.
contours, hierarchy = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(dilated, contours, -1, 255, -1)

closed = cv2.erode(dilated, kernel)  # Apply erode after filling the contours.

closed = closed[100:-100, 100:-100]  # Remove the padding.

# Find contours
contours, hierarchy = cv2.findContours(closed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# Draw the contours
cv2.drawContours(image, contours, -1, (255, 0, 0), 2)

# Show images for testing
# plt.imshow(image), plt.show()
cv2.imshow('gray', gray)
cv2.imshow('thresh', thresh)
cv2.imshow('dilated', dilated)
cv2.imshow('closed', closed)
cv2.imshow('image', image)
cv2.waitKey()
cv2.destroyAllWindows()

结果:

gray(饱和通道):

thresh

dilated(灌装后):

closed

m1m5dgzv

m1m5dgzv2#

只需要扩大图像以使矩形闭合,然后定义轮廓面积的阈值:

import cv2

# Load the image
image = cv2.imread('diagram.jpg')

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

# Apply thresholding to create a binary image
ret,thresh = cv2.threshold(gray,200,255,1)

# Need to dilate the image to make the contours closed
dilate = cv2.dilate(thresh,None)
erode = cv2.erode(dilate,None)

# Find contours
contours,hierarchy = cv2.findContours(erode,cv2.RETR_CCOMP,cv2.CHAIN_APPROX_SIMPLE)

for i,cnt in enumerate(contours):
    # Check if it is an external contour and its area is more than 8000
    if hierarchy[0,i,3] == -1 and cv2.contourArea(cnt)>8000:
        x,y,w,h = cv2.boundingRect(cnt)
        cv2.rectangle(image,(x,y),(x+w,y+h),(0,255,0),2)
        cv2.imwrite('template {0}.jpg'.format(i), image[y:y+h,x:x+w])
cv2.imshow('img',image)

您将获得:

相关问题