无法分割手写字符

Unable to segment handwritten characters

我正在尝试从图像中提取手写数字和字母表,为此我遵循了这个 Whosebug link。对于大多数使用标记书写字母的图像,它工作正常,但是当我使用使用 Pen 写入数据的图像时,它会失败得很惨。需要一些帮助来解决这个问题。

下面是我的代码:

import cv2
import imutils
from imutils import contours

# Load image, grayscale, Otsu's threshold
image = cv2.imread('xxx/pic_crop_7.png')
image = imutils.resize(image, width=350)
img=image.copy()

# Remove border
kernel_vertical = cv2.getStructuringElement(cv2.MORPH_RECT, (1,50))
temp1 = 255 - cv2.morphologyEx(image, cv2.MORPH_CLOSE, kernel_vertical)
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (50,1))
temp2 = 255 - cv2.morphologyEx(image, cv2.MORPH_CLOSE, horizontal_kernel)
temp3 = cv2.add(temp1, temp2)
result = cv2.add(temp3, image)

# Convert to grayscale and Otsu's threshold
gray = cv2.cvtColor(result, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray,(5,5),0)
_,thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU | cv2.THRESH_BINARY_INV)
# thresh=cv2.dilate(thresh,None,iterations=1)

# Find contours and filter using contour area
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[0]

MIN_AREA=45

digit_contours = []
for c in cnts:
    if cv2.contourArea(c)>MIN_AREA:
        x,y,w,h = cv2.boundingRect(c)
        cv2.rectangle(img, (x, y), (x + w, y + h), (36,255,12), 2)
        digit_contours.append(c)
#         cv2.imwrite("C:/Samples/Dataset/ocr/segmented" + str(i) + ".png", image[y:y+h,x:x+w])


sorted_digit_contours = contours.sort_contours(digit_contours, method='left-to-right')[0]
contour_number = 0
for c in sorted_digit_contours:
    x,y,w,h = cv2.boundingRect(c)
    ROI = image[y:y+h, x:x+w]
    cv2.imwrite('xxx/segment_{}.png'.format(contour_number), ROI)
    contour_number += 1
    
    
cv2.imshow('thresh', thresh)
cv2.imshow('img', img)
cv2.waitKey()

使用记号笔书写时能够正确提取数字。

下面是一个例子:

原图

正确提取字符

无法读取的图像。

原图

提取不正确

在这种情况下,您只需调整您的参数即可。 因为你的手写字背景没有竖线,所以我决定删掉。

# Remove border
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (50,1))
temp2 = 255 - cv2.morphologyEx(image, cv2.MORPH_CLOSE, horizontal_kernel)
result = cv2.add(temp2, image)

而且有效。

CodingPeter 给出的解决方案非常好,除了它可能不适合您发布的两个测试图像。因此,这是我的看法,可能适用于您的两张测试图像,尽管准确性稍差。

import numpy as np
import cv2
import matplotlib.pyplot as plt

plt.rcParams['figure.figsize'] = (20, 20)
plt.rcParams["image.cmap"] = 'gray'

img_rgb = cv2.imread('path/to/your/image.jpg')
img = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)

th = cv2.adaptiveThreshold(img,255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY_INV,11,2)

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (15,1))
horiz = cv2.morphologyEx(th, cv2.MORPH_OPEN, kernel, iterations=3)
ctrs, _ = cv2.findContours(horiz,cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
for ctr in ctrs:
    x,y,w,h = cv2.boundingRect(ctr)
    if w < 20:
        cv2.drawContours(horiz, [ctr], 0, 0, cv2.FILLED)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,10))
vert = cv2.morphologyEx(th, cv2.MORPH_OPEN, kernel, iterations=3)
ctrs, _ = cv2.findContours(vert,cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
for ctr in ctrs:
    x,y,w,h = cv2.boundingRect(ctr)
    if h < 25:
        cv2.drawContours(vert, [ctr], 0, 0, cv2.FILLED)

th = th - (horiz | vert)
ctrs, _ = cv2.findContours(th,cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
min_ctr_area = 400 # Min character bounding box area

for ctr in ctrs:
    x, y, w, h = cv2.boundingRect(ctr)
    # Filter contours based on size
    if w * h > min_ctr_area and \
    w < 100 and h < 100:
        cv2.rectangle(img_rgb, (x, y), (x+w, y+h), (0, 255, 0), 1)
plt.imshow(img_rgb)

当然这里的一些参数是为了过滤而硬编码的,比较轮廓的高度和宽度以确定它是线条的一部分还是字符。对于不同的图像,您可能需要巧妙地更改这些值。