opencv等高线和/或数字的boundingrect无法正确检测

时间:2018-10-24 21:06:38

标签: opencv bounding-box opencv-contour

我试图分割下图的数字和/或字符,然后使用ocr将每个单独的num / char转换为文本:

enter image description here

这是使用的代码(在python中):

new, contours, hierarchy = cv2.findContours(gray, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

digitCnts = []

final = gray.copy()    

# loop over the digit area candidates
for c in contours:

    (x, y, w, h) = cv2.boundingRect(c)
    # if the contour is sufficiently large, it must be a digit
    if (w >= 20 and w <= 290) and h >= (gray.shape[0]>>1)-15:
        x1 = x+w
        y1 = y+h
        digitCnts.append([x,x1,y,y1])
        #print(x,x1,y,y1)
        # Drawing the selected contour on the original image
        cv2.rectangle(final,(x,y),(x1,y1),(0, 255, 0), 2)

plt.imshow(final, cmap=cm.gray, vmin=0, vmax=255)

我得到以下输出:

enter image description here

您会看到所有内容都可以正确检测,除了中间2的顶部只有边框而不是整个数字。我无法弄清楚为什么只有一个无法正确检测到,尤其是与其他相似。任何想法如何解决这个问题?

2 个答案:

答案 0 :(得分:1)

据我所知,大多数用于二进制映像的OpenCV方法都运行white objects on the black background

Src:

enter image description here

阈值INV和变通打开:

enter image description here

按高度过滤并在src上绘制:

enter image description here


#!/usr/bin/python3
# 2018/10/25 08:30 
import cv2
import numpy as np

# (1) src 
img = cv2.imread( "car.png")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# (2) threshold-inv and morph-open 
th, threshed = cv2.threshold(gray, 100, 255, cv2.THRESH_OTSU|cv2.THRESH_BINARY_INV)
morphed = cv2.morphologyEx(threshed, cv2.MORPH_OPEN, np.ones((2,2)))
# (3) find and filter contours, then draw on src 
cnts = cv2.findContours(morphed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2]

nh, nw = img.shape[:2]
for cnt in cnts:
    x,y,w,h = bbox = cv2.boundingRect(cnt)
    if h < 0.3 * nh:
        continue
    cv2.rectangle(img, (x,y), (x+w, y+h), (255, 0, 255), 1, cv2.LINE_AA)

cv2.imwrite("dst.png", img)
cv2.imwrite("morphed.png", morphed)

答案 1 :(得分:0)

您的图像有点吵,因此将其二值化就可以解决问题。

cv2.threshold(gray,  127, 255, cv2.THRESH_BINARY, gray)
new, contours, hierarchy = cv2.findContours(gray, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)

# cv2.drawContours(gray, contours, -1, 127, 5)
digitCnts = []

final = gray.copy()

# loop over the digit area candidates
for c in contours:
    (x, y, w, h) = cv2.boundingRect(c)
    # if the contour is sufficiently large, it must be a digit
    if (w >= 20 and w <= 290) and h >= (gray.shape[0]>>1)-15:
        x1 = x+w
        y1 = y+h
        digitCnts.append([x,x1,y,y1])
        #print(x,x1,y,y1)
        # Drawing the selected contour on the original image
        cv2.rectangle(final,(x,y),(x1,y1),(0, 255, 0), 2)

this article