1
import numpy as np
import cv2

blank_image = np.zeros((40,40,3), np.uint8)
blank_image.fill(255)

#cv2.imshow('i', blank_image)
#cv2.waitKey(0)

im = cv2.imread('img.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)

cnt = contours[4]
cnts = cv2.drawContours(im,[cnt],0,(255,0,0), -1)

cv2.imshow('i', im)
cv2.waitKey(0)

for a in cnt:
    print(a) #this contour is a 3D numpy array

Source image:

src

I am using this code to: 1. create a white canvas of 40x40 pixels 2. found the contours of number (in this case 5) using Opencv function findContours.

out1

What I want to do is to copy this shape (please, not the bounding box or rectangle, the blue shape) into the canvas.

After some research I learned that an opencv image is just a numpy array. This array, theoretically, should be translated in the new image (my white canvas..) and then reconstruct the shape using the values inside the array. I am right ?

Someone know how to do that ? Creating a bounding box / rectangle around the numbers would, in some cases, result inaccurate. Please, don't give that as solution. I already did this process in atleast 3-4 different ways and the results are not satisfactory enough.

So, the desired output would be something like this..

out2

Thanks.

lucians
  • 2,239
  • 5
  • 36
  • 64

1 Answers1

1

For contours image enter image description here

I think want something like enter image description here


For opened number such as 1, 2, 5 , it is easy to do: Crop from the whole image, or draw on new image. For closed number such as 0, 6, 8, 9, more steps are needed. Here is example for 5, you will get enter image description here.


Details and description are in the code.

#!/usr/bin/python3
# 2018.01.14 09:48:15 CST
# 2018.01.14 11:39:03 CST

import numpy as np
import cv2

im = cv2.imread('test.png')
imgray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(imgray, 127, 255, 0)
contours = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[-2]


## this contour is a 3D numpy array
cnt = contours[4]
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("croped.png", 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, (255,0,0), -1)
cv2.imwrite("canvas.png", canvas)
Kinght 金
  • 17,681
  • 4
  • 60
  • 74
  • Yes! Finally! Do you confirm it crop, using the 2nd method, only the contour and after it paste it into the canvas ? It's perfect. Thank you. – lucians Jan 14 '18 at 18:09
  • Also, is there a way to define a minArea of contour to detect ? For example, number 8 comes out filled with the color I selected in drawContours: [example](https://imgur.com/a/lpl1O)... – lucians Jan 14 '18 at 18:25