Before the actual project, we first learn a knowledge point: connected domain outside rectangle

There are two strategies for finding an enclosing rectangle:

  • One is to look for the edge of the contour and find the outermost bounding rectangle. In order to distinguish, we call it boundingRect, as shown in the green rectangle.
  • Another strategy isThe rectangle can be rotated to find the rectangle with the smallest area,Just enough to fit the outline inside, we call it* Minimum enclosing rectangle * minAreaRect, the blue rectangle in the picture below.

Extract handwritten digital image samples

  • Enclosing rectangle boudningRect
  • Minimum enclosing rectangle minAreaRect
  • Extract the minimum enclosing rectangle region
  • Digital sample image conversion to uniform size
  • Resource portal
  • “❤️ thank you.”

Enclosing rectangle boudningRect

The function is simpler and the only argument passed in is the set of contour Points (single).

rect = cv2.boundingRect(cnt)
(x, y, w, h) = rect
Copy the code

The return value is rect, the data structure is tuple, the coordinates of the upper left corner of the rectangle (x, y), and the width w and height H of the rectangle, respectively

We print the information of the rectangular area in turn.

for cidx,cnt in enumerate(contours):
    (x, y, w, h) = cv2.boundingRect(cnt)
    print('RECT: x={}, y={}, w={}, h={}'.format(x, y, w, h))
Copy the code

Output result:

RECT: x=92, y=378, w=94, h=64
RECT: x=381, y=328, w=69, h=102
RECT: x=234, y=265, w=86, h=70
RECT: x=53, y=260, w=61, h=95
RECT: x=420, y=184, w=49, h=66
RECT: x=65, y=124, w=48, h=83
RECT: x=281, y=71, w=70, h=108
Copy the code

It is more intuitive to draw on the canvas. The specific code is as follows:

Img = cv2.imread("color_number_handwriting. PNG ") # convert to gray gray image gray = Cv2.cvtcolor (img, cv2.color_bgr2gray) # contours, hier = cv2.findContours(gray, cv2.retr_external, Cv2. CHAIN_APPROX_SIMPLE) # declare canvas copied from img canvas = np.copy(img) for cidx, CNT in enumerate(contours): (x, y, w, h) = cv2.boundingRect(cnt) print('RECT: X = {}, y = {}, w = {}, h = {} '. The format (x, y, w, h) # artwork. Draw a circle cv2 rectangle (canvas, pt1 = (x, y), pt2 = (x + w, y + h), color = (255, 255, Imwrite ("number_boudingrect_cidx_{}.png". Format (cidx), img[y:y+h, x:x+w]) cv2.imwrite("number_boundingrect_canvas.png", canvas)Copy the code

Original image:



Drawing result:

Img [y:y+h, x:x+w] :

Imwrite (" number_boudingRect_cidx_ {}.png". Format (cidx), img[y:y+h, x:x+w]Copy the code

So we’ve captured a picture of a single number:

Minimum enclosing rectangle minAreaRect

The minAreaRect function is used to get the smallest area of the rectangle.

minAreaRect = cv2.minAreaRect(cnt)
Copy the code

Let’s print minAreaRect to see the data structure it returns:

(133.10528564453125, 404.7727966308594), (100.10702514648438, 57.51853942871094), -49.184913635253906)Copy the code

Data structure parsing

((cx, cy), (width, height), theta)
Copy the code
  • cxRectangle center point x coordinates center x
  • cyRectangle center y coordinate center y
  • widthWidth of the rectangle
  • heightRectangular height
  • thetaAngle of rotation (not radians)

Note: the above values are decimal and cannot be used directly for image indexing or rectangle drawing.

See figure

Python OpencV minAreaRect generates the smallest enclosing rectangle

Note: Rotation Angle θ is the Angle between the horizontal axis (x axis) rotated counterclockwise and the first side of the rectangle encountered. And the length of this side is width, and the length of this side is height. That is, in this case, width and height are not defined in terms of length.

In OpencV, the origin of the coordinate system is in the upper left corner, and the Angle of rotation relative to the X-axis is negative counterclockwise and positive clockwise.

And just for intuition’s sake, we can just assign it this way

((cx, cy), (width, height), theta) = cv2.minAreaRect(cnt)
1
Copy the code

A more complete demo sample:

for cidx,cnt in enumerate(contours):
    ((cx, cy), (width, height), theta) = cv2.minAreaRect(cnt)
    print('center: cx=%.3f, cy=%.3f, width=%.3f, height=%.3f, roate_angle=%.3f'%(cx, cy, width, height, theta))
Copy the code

Output result:

Center: cx=133.105, cy=404.773, width=100.107, height=57.519, roate_angle=-49.185 center: Cx =415.190, cy=378.853, width=66.508, height=100.537, roate_angle=-1.710 center: Cx =278.323, cy=296.089, width=71.608, height=78.065, roate_angle=-78.440 center: Cx =83.000, cy=307.000, width=60.000, height=94.000, roate_angle=0.000 center: Cx =448.346, cy=213.731, width=47.068, height=64.718, roate_angle=-11.310 center: Cx =89.642, cy=164.695, width=17.204, height=88.566, roate_angle=-25.427 center: Cx =330.578, cy=123.387, width=92.325, height=72.089, roate_angle=-66.666Copy the code

Complete code display:

Img = cv2.imread("color_number_handwriting. PNG ") # convert to gray gray image gray = Cv2.cvtcolor (img, cv2.color_bgr2gray) # contours, hier = cv2.findContours(gray, cv2.retr_external, Cv2. CHAIN_APPROX_SIMPLE) # declare canvas copied from img canvas = np.copy(img) for cidx, CNT in enumerate(contours): MinAreaRect = cv2.minarearect (CNT) # Convert to integer point set coordinates rectCnt = Np.int64 (cv2.boxpoints (minAreaRect)) # Draw polygons Cv2. Polylines (img = canvas, PTS = [rectCnt], isClosed = True, color = (0,0,255), thickness=3) cv2.imwrite("number_minarearect_canvas.png", canvas)Copy the code

Extract the minimum enclosing rectangle region

According to the data structure returned by the minAreaRect function, we can take the center of the rectangle (Cx, cy) as the center point of rotation of the original image, and set the rotation Angle as Theta:

RotateMatrix = cv2.getrotationMatrix2D ((cx, cy), Theta, 1.0) rotateMatrix, (img.shape[1], img.shape[0]))Copy the code

The specific code is as follows:

"Draw the minimum area rectangle with minAreaRect and draw" import numpy as NP import cv2 # Read the colored handwritten number img = on a black background Cv2.imread ("color_number_handwriting. PNG ") # convert gray = cv2.cvtcolor (img, cv2.color_bgr2gray) # convert contours, hier = cv2.findContours(gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for cidx,cnt in enumerate(contours): MinAreaRect = np.int64(cv2.boxpoints (minAreaRect)) ((cx, cy), (w, h), Theta = minAreaRect cx = int(cx) cy = int(cy) w = int(w) h = int(h Cv2. getRotationMatrix2D((cx, cy), Theta, 1.0) rotatedImg = cv2.warpAffine(img, rotateMatrix, (img.shape[1], img.shape[0])) pt1 = (int(cx - w/2), int(cy - h/2)) pt2 = (int(cx + w/2), Rectangle (pt1=pt1, pt2=pt2,color=(255, 255, 255)); rectangle(pt1=pt1, pt2=pt2,color=(255, 255)); Thickness =3) # draw center cv2. Circle (rotatedImg, (cx, cy), 5, color=(255, 0, 0), thickness=-1) cv2.imwrite("minarearect_cidx_{}.png".format(cidx), rotatedImg)Copy the code

Digital sample image conversion to uniform size

We’ve captured the outer rectangles that contain numbers, and they’re all different shapes. (Manual rotation may be required)

If it’s a sample image we need to make a neural network, we need to scale it down to a uniform size.

Now let’s unify the image to15 * 25And convert it to a binary image.



The specific code is as follows:

Import numpy as np import cv2 from glob import glob img_paths = glob('./ *.png')  25) for img_path in img_paths: Img = cv2.imread(img_path, cv2.imread_grayscale) img_name = img_path.split('/')[-1] # resized = cv2.resize(img, New_dimension) # binary image ret,thresh = cv2.threshold(resized,10,255,0) cv2.imwrite('./number/'+img_name,thresh)Copy the code

Resource portal

  1. Pay attention to [be a gentle program ape] public account
  2. In [do a tender program ape] public account background reply [Python information] [2020 autumn recruit] can get the corresponding surprise oh!

“❤️ thank you.”

  1. Click “like” to support it, so that more people can see this content.
  2. Share your thoughts with me in the comments section, and record your thought process in the comments section.
  • Excel/Word/CSV with Python (160 +)
  • The average programmer likes to browse 40 websites, so many years, I will not hide private, personally strongly recommend (230+)
  • Image Encryption and Restoration Based on Chaotic Logistic Encryption Algorithm
  • Draw dynamic fireworks in Python
  • Error: AttributeError: ‘Module’ object has no attribute ‘XXXXX’
  • How to parse XML and PDF easily in Python (300 +)
  • Affine transformations (translation, rotation, scaling, and flip)
  • ValueError: Not enough values to unpack (Expected 3, got 2) (100+)
  • Python raspberry PI camera continuously recording and sending to host (200+)