cv2.drawContours() - 在字符内填充圆圈(Python,OpenCV)

Lin*_*ink 2 python opencv opencv-contour opencv-drawcontour

正如@Silencer所建议的,我使用他在这里发布的代码来绘制图像中数字的轮廓.在某些时候,处理数字,就像0,6,8,9我看到他们的内部轮廓(圆圈)也被填充.我怎么能阻止这个?是否有为cv2.drawContours()设置的最小/最大动作区域,所以我可以排除内部区域?

例

我试图传递cv2.RETR_EXTERNAL但是使用此参数只考虑整个外部区域.

代码就是这样(再次感谢Silencer.几个月来一直在寻找这个......):

import numpy as np
import cv2

im = cv2.imread('imgs\\2.png')
imgray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(imgray, 127, 255, 0)
image, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

#contours.sort(key=lambda x: int(x.split('.')[0]))

for i, cnts in enumerate(contours):
    ## this contour is a 3D numpy array
    cnt = contours[i]
    res = cv2.drawContours(im, [cnt], 0, (255, 0, 0), 1)
    cv2.imwrite("contours.png", res)
    '''
    ## Method 1: crop the region
    x,y,w,h = cv2.boundingRect(cnt)
    croped = res[y:y+h, x:x+w]
    cv2.imwrite("cnts\\croped{}.png".format(i), croped)
    '''
    ## Method 2: draw on blank
    # get the 0-indexed coords
    offset = cnt.min(axis=0)
    cnt = cnt - cnt.min(axis=0)
    max_xy = cnt.max(axis=0) + 1
    w, h = max_xy[0][0], max_xy[0][1]
    # draw on blank
    canvas = np.ones((h, w, 3), np.uint8) * 255
    cv2.drawContours(canvas, [cnt], -1, (0, 0, 0), -1)

    #if h > 15 and w < 60:
    cv2.imwrite("cnts\\canvas{}.png".format(i), canvas)
Run Code Online (Sandbox Code Playgroud)

我工作的主要形象..

SRC

谢谢

UPDATE

我在下面实现了Fiver答案,结果如下:

import cv2
import numpy as np

img = cv2.imread('img.png')
img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
img_v = img_hsv[:, :, 2]

ret, thresh = cv2.threshold(~img_v, 127, 255, 0)
image, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

for i, c in enumerate(contours):
    tmp_img = np.zeros(img_v.shape, dtype=np.uint8)
    res = cv2.drawContours(tmp_img, [c], -1, 255, cv2.FILLED)

    tmp_img = np.bitwise_and(tmp_img, ~img_v)

    ret, inverted = cv2.threshold(tmp_img, 127, 255, cv2.THRESH_BINARY_INV)

    cnt = contours[i]

    x, y, w, h = cv2.boundingRect(cnt)
    cropped = inverted[y:y + h, x:x + w]

    cv2.imwrite("roi{}.png".format(i), cropped)
Run Code Online (Sandbox Code Playgroud)

Kin*_*t 金 5

绘制char没有填充封闭的内部区域:

  1. 找到具有层次结构的脱粒二进制图像上的轮廓.

  2. 找到没有内部对象的外部轮廓(通过标志层次结构i).

  3. 对于每个外部轮廓:

    3.1填写它(可能需要检查是否需要);

    3.2然后迭代它的内部儿童轮廓,然后填充其他颜色(如反转的颜色).

  4. 结合裁剪代码,裁剪它们.

  5. 也许你需要对它们进行排序,重新分类它们,使它们正常化.
  6. 也许,现在你可以用经过训练的模型做ocr.

FindContours,重新填充内部封闭区域.

在此输入图像描述

结合这个答案 将形状复制到空白画布(OpenCV,Python),做更多步骤,也许你可以得到这个或更好:

在此输入图像描述


refill内部封闭区域的核心代码如下:

#!/usr/bin/python3
# 2018.01.14 09:48:15 CST
# 2018.01.15 17:56:32 CST
# 2018.01.15 20:52:42 CST

import numpy as np
import cv2

img = cv2.imread('img02.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

## Threshold 
ret, threshed = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV|cv2.THRESH_OTSU)

## FindContours
cnts, hiers = cv2.findContours(threshed, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[-2:]

canvas = np.zeros_like(img)
n = len(cnts)
hiers = hiers[0]

for i in range(n):
    if hiers[i][3] != -1:
        ## If is inside, the continue 
        continue
    ## draw 
    cv2.drawContours(canvas, cnts, i,  (0,255,0), -1, cv2.LINE_AA)

    ## Find all inner contours and draw 
    ch = hiers[i][2]
    while ch!=-1:
        print(" {:02} {}".format(ch, hiers[ch]))
        cv2.drawContours(canvas, cnts, ch, (255,0,255), -1, cv2.LINE_AA)
        ch = hiers[ch][0]

cv2.imwrite("001_res.png", canvas)
Run Code Online (Sandbox Code Playgroud)

使用此图片运行此代码:

你会得到:

在此输入图像描述


当然,这是两个层次结构.我没有测试过两次以上.您需要的人可以自己做测试.


更新:

请注意,在不同的OpenCV中,cv2.findContours返回不同的值.为了保持代码可执行,我们可以使用最后两个返回值:cnts,hiers = cv2.findContours(...)[ - 2:]

在OpenCV 3.4中:

在此输入图像描述

在OpenCV 4.0中:

在此输入图像描述