python- splitting an array into sub arrays dependant on value (opencv- image cropping)

353 Views Asked by At

I am trying to crop an image of dot matrix print into individual characters. I have dilated the characters, threhold and inverted them.

SEGMENTAION

I have created an array that has the pixel values of the blank spaces in the image. (the red lines) in order to crop individual characters

array of spaces

I am trying to write a function that will return the pixels of the character eg

L - [0 62]

o - [74 137]

r - [149 199] etc.

I have tried a couple of methods of for loops but canot reach a solution to produce the required arrays. Any tips appreciated!

##dot matrix print
##import the required libraries
import cv2
import numpy as np

## import the image
image = cv2.imread('/home/pi/Downloads/dot-matrix-unknown-sample.png')

##create the kernal for the dilation
kernel = np.ones((4,4),np.uint8)

##crop the image to one line
cropped =image[0:101, 0:]

##crop the first letter 'l'
##l = cropped[0:101, 0:62]

## convert the image to gray and use the otsu threshold and invert
img=cv2.cvtColor(cropped,cv2.COLOR_BGR2GRAY)
ret3, th3 = cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
inverted = cv2.bitwise_not(th3)

##dilate the dots in the matrixto take up the gaps between the dots.
dilation = cv2.dilate(inverted,kernel,iterations = 1)

##display the image
cv2.imshow('img',dilation)
cv2.waitKey(0)
cv2.destroyAllWindows()

##provides the location of spaces in the image in 2d arrray
vpp = np.sum(dilation, axis =0)
space= np.where(vpp == 0)
space= np.array(space)

##convert to a 1d array (as image)
space=space.ravel()
print(space)

p.s if there is a better way to do this please sugggest.

1

There are 1 best solutions below

2
On

I assume the output you want bounding box for each letter.

Steps:

1.Dilate the image to bring contours (dots) closer

2- Find the contours

3- Sort Contours According to the sizes of their bounding boxes

4- Remove Unwanted contours if any (I did this by taking only largest 2 contours, where 2 is number of letters in my test case.

5-Sort contours according to their X positions (left to right, I dont know if this is necessary for you)

6- Find bounding boxes for each coordinate, optionally draw it

Code:

# Dilate
dilated = cv2.dilate(gray, (5, 5), iterations=8)

# Find Contours
contours, hierarchy = cv2.findContours(dilated, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# Sort the contours descending according to their area
contours = sorted(contours, key=lambda x: cv2.contourArea(x), reverse=False)

NUMBER_OF_LETTERS = 2
# Delete the smalles contours to match len(contours) to number of letters.
del contours[len(contours) - NUMBER_OF_LETTERS]

# Sort the Contours According to their position (left to right)
contours = sorted(contours, key=lambda x: cv2.boundingRect(x)[0], reverse=True)

bboxes = []

# Find and draw bounding boxes, and append to bboxes list for future use.
for c in contours:
    x, y, w, h = cv2.boundingRect(c)
    bboxes.append((x, y, w, h))
    cv2.rectangle(dot_matrix, (x, y), (x + w, y + h), (0, 0, 255), 2)

Output: (Original, Dilated, BoundingBoxes)

enter image description here