Get angle of contour shape found in OpenCV - python

I am working on an OCR project using OpenCV & Tesseract. I have successfully identified the shape of the receipt and now I am trying to extract the angle of the shape (drawn with green below) to deskew the image.
To detect the contour I used more RETR_EXTERNAL method, as I found it produces the best results for my dataset (the contours of background noise is minimal)
code to extract all contours
image2 = cv2.imread('./Dataset - Receipt Images/1036-receipt.jpg')
img_gray2 = cv2.cvtColor(image2, cv2.COLOR_BGR2GRAY)
ret, thresh2 = cv2.threshold(img_gray2, 150, 255, cv2.THRESH_BINARY)
contours4, hierarchy4 = cv2.findContours(thresh2, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
image_copy5 = image2.copy()
cv2.drawContours(image_copy5, contours4, -1, (0, 255, 0), 2, cv2.LINE_AA)
cv2.imshow('EXTERNAL', image_copy5)
To get the largest contour (blue box) I applied the following:
def drawMaxAreaContour(contours, image):
if len(contours) != 0:
c = max(contours, key=cv2.contourArea)
cv2.drawContours(image, c, 1, (0, 0, 255), 5)
x, y, w, h = cv2.boundingRect(c)
cv2.rectangle(image, (x, y), (x + w, y + h), (250, 0, 0), 2)
To get the angle of the shape, i tried:
cv2.minAreaRect(c)
And the results is 0 - the angle of the green box is 0, which is obviously not true.
So, specifically, my question:
2. OR how can I get the angle of that shape? (assuming it would be applied on the shape of a receipt, not a rectangular shape, like the blue one in my case)
Processed picture

Related

How do I find a traffic light with simple image processing?

I want to implement simple traffic light detection algorithm in Python with help of OpenCV. Of course if we want to get high accuracy, we should use some pre-trained deep learning models, but now I want just simplest and not comprehensive approach. Namely I know that traffic lights are (green, red , yellow), therefore I found following link which contains code about three color detection.
I know once again, that it is not an accurate method, just self learning. I have tested this code on one video. Here is a cropped frame from the corresponding video:
After running my code, I got following image:
As you can see, the lowest part of the image is ignored and upper part is considered.
How can I adapt or change my code such that it should check whole image and detect actual traffic lights as well?
Should I resize the image to a lower resolution?
Should I use some other approach?
import numpy as np
import cv2
import warnings
warnings.filterwarnings("ignore")
# Capturing video through webcam
live_video = cv2.VideoCapture("traffic_light.mp4")
# Start a while loop
while (1):
# Reading the video from the
# webcam in image frames
_, imageFrame = live_video .read()
# Convert the imageFrame in
# BGR(RGB color space) to
# HSV(hue-saturation-value)
# color space
hsvFrame = cv2.cvtColor(imageFrame, cv2.COLOR_BGR2HSV)
# Set range for red color and
# define mask
red_lower = np.array([136, 87, 111], np.uint8)
red_upper = np.array([180, 255, 255], np.uint8)
red_mask = cv2.inRange(hsvFrame, red_lower, red_upper)
# Set range for green color and
# define mask
green_lower = np.array([25, 52, 72], np.uint8)
green_upper = np.array([102, 255, 255], np.uint8)
green_mask = cv2.inRange(hsvFrame, green_lower, green_upper)
# Set range for blue color and
# define mask
blue_lower = np.array([94, 80, 2], np.uint8)
blue_upper = np.array([120, 255, 255], np.uint8)
blue_mask = cv2.inRange(hsvFrame, blue_lower, blue_upper)
# Morphological Transform, Dilation
# for each color and bitwise_and operator
# between imageFrame and mask determines
# to detect only that particular color
kernal = np.ones((5, 5), "uint8")
# For red color
red_mask = cv2.dilate(red_mask, kernal)
res_red = cv2.bitwise_and(imageFrame, imageFrame,
mask=red_mask)
# For green color
green_mask = cv2.dilate(green_mask, kernal)
res_green = cv2.bitwise_and(imageFrame, imageFrame,
mask=green_mask)
# For blue color
blue_mask = cv2.dilate(blue_mask, kernal)
res_blue = cv2.bitwise_and(imageFrame, imageFrame,
mask=blue_mask)
# Creating contour to track red color
contours, hierarchy = cv2.findContours(red_mask,
cv2.RETR_TREE,
cv2.CHAIN_APPROX_SIMPLE)
for pic, contour in enumerate(contours):
area = cv2.contourArea(contour)
if (area > 300):
x, y, w, h = cv2.boundingRect(contour)
imageFrame = cv2.rectangle(imageFrame, (x, y),
(x + w, y + h),
(0, 0, 255), 2)
cv2.putText(imageFrame, "Red Colour", (x, y),
cv2.FONT_HERSHEY_SIMPLEX, 1.0,
(0, 0, 255))
# Creating contour to track green color
contours, hierarchy = cv2.findContours(green_mask,
cv2.RETR_TREE,
cv2.CHAIN_APPROX_SIMPLE)
for pic, contour in enumerate(contours):
area = cv2.contourArea(contour)
if (area > 300):
x, y, w, h = cv2.boundingRect(contour)
imageFrame = cv2.rectangle(imageFrame, (x, y),
(x + w, y + h),
(0, 255, 0), 2)
cv2.putText(imageFrame, "Green Colour", (x, y),
cv2.FONT_HERSHEY_SIMPLEX,
1.0, (0, 255, 0))
# Creating contour to track blue color
contours, hierarchy = cv2.findContours(blue_mask,
cv2.RETR_TREE,
cv2.CHAIN_APPROX_SIMPLE)
for pic, contour in enumerate(contours):
area = cv2.contourArea(contour)
if (area > 300):
x, y, w, h = cv2.boundingRect(contour)
imageFrame = cv2.rectangle(imageFrame, (x, y),
(x + w, y + h),
(255, 0, 0), 2)
cv2.putText(imageFrame, "Blue Colour", (x, y),
cv2.FONT_HERSHEY_SIMPLEX,
1.0, (255, 0, 0))
# Program Termination
cv2.imshow("Multiple Color Detection in Real-TIme", imageFrame)
if cv2.waitKey(10) & 0xFF == ord('q'):
live_video .release()
cv2.destroyAllWindows()
break
I am thinking about resizing of frames, but first I would like to listen your opinions. The main tricky part, I think, is located in the following code, since it tries to locate cursor in the specific contours determined by coordinates. How can I change it?

OpenCV python code to calculate distance of object relative to a point

Consider the image below:
I want to write an OpenCV program to calculate the distance (blue line) in pixels between the midpoint of the table (red dot) and the midpoint of the brown box (blue dot).
I figured using I would use cv2.findContours to find the boundaries of the table, the boundaries of the box, get the midpoint of the table, the midpoint of the box and then probably use dist.euclidean to calculate the distance between the box's midpoint and table's midpoint. However, I am stuck at this point:
My code (shown below) is drawing contours for the wires and the glare and I have no interest in them:
cv2.namedWindow("Object detector", cv2.WINDOW_NORMAL)
image = cv2.imread(PATH_TO_IMAGE)
cv2.resizeWindow('Object detector', 800, 600)
im_bw = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,2))
morphology_img = cv2.morphologyEx(im_bw, cv2.MORPH_OPEN, kernel,iterations=1)
edged = cv2.Canny(morphology_img, 50, 100)
edged = cv2.dilate(edged, None, iterations=1)
cnts= cv2.findContours(edged.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
(cnts, _) = contours.sort_contours(cnts)
cv2.drawContours(image, cnts, -1, (0,255,0), 3)
orig = image.copy()
cv2.imshow('Object detector', image)
cv2.waitKey(0)
cv2.destroyAllWindows()
I even added the following piece of code to filter out contours of a certain size:
for (i, c) in enumerate(cnts):
# if the contour is not sufficiently large, ignore it
if cv2.contourArea(c) < 50000:
continue
else:
box = cv2.minAreaRect(c)
box = cv2.cv.BoxPoints(box) if imutils.is_cv2() else cv2.boxPoints(box)
box = np.array(box, dtype="int")
cv2.drawContours(image, [box.astype("int")], -1, (0, 255, 0), 1)
(tl, tr, br, bl) = box
(tltrX, tltrY) = midpoint(tl, tr)
(blbrX, blbrY) = midpoint(bl, br)
(tlblX, tlblY) = midpoint(tl, bl)
(trbrX, trbrY) = midpoint(tr, br)
# compute the Euclidean distance between the midpoints
dA = dist.euclidean((tltrX, tltrY), (blbrX, blbrY))
dB = dist.euclidean((tlblX, tlblY), (trbrX, trbrY))
cv2.putText(image, "{:.1f}".format(dA),
(int(tltrX - 15), int(tltrY - 10)), cv2.FONT_HERSHEY_SIMPLEX,
0.65, (255, 255, 255), 2)
cv2.putText(image, "{:.1f}".format(dB),
(int(trbrX + 10), int(trbrY)), cv2.FONT_HERSHEY_SIMPLEX,
0.65, (255, 255, 255), 2)
But even that didn't help.
How can I accomplish this task of calculating relative distance of the box from the center of the table?

Trying to Capture Shapes in an image in openCV Python

i have the image shown below and i am attempting to just capture the Squares and place a green line around them any help or direction would be great.
import numpy as np
import cv2
img = cv2.imread('beef.png')
imgGry = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret , thrash = cv2.threshold(imgGry, 240 , 255, cv2.CHAIN_APPROX_NONE)
contours , hierarchy = cv2.findContours(thrash, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
for contour in contours:
approx = cv2.approxPolyDP(contour, 0.01* cv2.arcLength(contour, True), True)
cv2.drawContours(img, [approx], 0, (0, 0, 0), 5)
x = approx.ravel()[0]
y = approx.ravel()[1] - 5
x, y , w, h = cv2.boundingRect(approx)
aspectRatio = float(w)/h
print(aspectRatio)
if aspectRatio >= 0.95 and aspectRatio < 1.05:
cv2.putText(img, "square", (x, y), cv2.FONT_HERSHEY_COMPLEX, 0.5, (0, 0, 0))
else:
cv2.putText(img, "rectangle", (x, y), cv2.FONT_HERSHEY_COMPLEX, 0.5, (0, 0, 0))
cv2.imshow('shapes', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
I don't know exactly what your problem is (are the contours wrong? Nothing is being drawn on the image? etc) but here are some guesses.
To draw lines around the contours, it looks like you are currently using white (0,0,0) to outline it. -1 is to draw all contours to see if you are getting any results.
Also some cv2 functions are destructive so I never use img when I am creating the output image. I would imShow and drawContours on a copy of the original img.
cv2.drawContours(img, contours, -1, GREEN, 5)

OpenCV: using Canny and Shi-Tomasi to detect round corners of a playing card

I want to do some planar rectification, to convert from left to right:
I have the code to do the correction, but I need the 4 corner coords.
I'm using the following code to find them:
import cv2
image = cv2.imread('input.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
canny = cv2.Canny(gray, 120, 255, 1)
corners = cv2.goodFeaturesToTrack(canny,4,0.5,50)
for corner in corners:
x,y = corner.ravel()
cv2.circle(image,(x,y),5,(36,255,12),-1)
cv2.imshow("result", image)
cv2.waitKey()
It reads the image, and transforms it to grayscale + canny
But the resultant corners (found by cv2.goodFeaturesToTrack) aren't the desired ones:
I need the external corners of the card, any clue to achieve it?
Thanks
This is the input.png:
Update: Added four point perspective transform.
I have skipped perspective transform as the question is about finding right corners.
You can skip the loop by getting contour with maximum area then processing it. Some blurring may help it further. Press Esc button to get next image output.
Another useful method, how to find corners points of a shape in an image in opencv?
Ouput Images
Code
"""
Task: Detect card corners and fix perspective
"""
import cv2
import numpy as np
img = cv2.imread('resources/KSuVq.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(gray,127,255,0)
cv2.imshow('Thresholded original',thresh)
cv2.waitKey(0)
## Get contours
contours,h = cv2.findContours(thresh,cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)
## only draw contour that have big areas
imx = img.shape[0]
imy = img.shape[1]
lp_area = (imx * imy) / 10
#################################################################
# Four point perspective transform
# https://www.pyimagesearch.com/2014/08/25/4-point-opencv-getperspective-transform-example/
#################################################################
def order_points(pts):
# initialzie a list of coordinates that will be ordered
# such that the first entry in the list is the top-left,
# the second entry is the top-right, the third is the
# bottom-right, and the fourth is the bottom-left
rect = np.zeros((4, 2), dtype = "float32")
# the top-left point will have the smallest sum, whereas
# the bottom-right point will have the largest sum
s = pts.sum(axis = 1)
rect[0] = pts[np.argmin(s)]
rect[2] = pts[np.argmax(s)]
# now, compute the difference between the points, the
# top-right point will have the smallest difference,
# whereas the bottom-left will have the largest difference
diff = np.diff(pts, axis = 1)
rect[1] = pts[np.argmin(diff)]
rect[3] = pts[np.argmax(diff)]
# return the ordered coordinates
return rect
def four_point_transform(image, pts):
# obtain a consistent order of the points and unpack them
# individually
rect = order_points(pts)
(tl, tr, br, bl) = rect
# compute the width of the new image, which will be the
# maximum distance between bottom-right and bottom-left
# x-coordiates or the top-right and top-left x-coordinates
widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))
widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))
maxWidth = max(int(widthA), int(widthB))
# compute the height of the new image, which will be the
# maximum distance between the top-right and bottom-right
# y-coordinates or the top-left and bottom-left y-coordinates
heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))
heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))
maxHeight = max(int(heightA), int(heightB))
# now that we have the dimensions of the new image, construct
# the set of destination points to obtain a "birds eye view",
# (i.e. top-down view) of the image, again specifying points
# in the top-left, top-right, bottom-right, and bottom-left
# order
dst = np.array([
[0, 0],
[maxWidth - 1, 0],
[maxWidth - 1, maxHeight - 1],
[0, maxHeight - 1]], dtype = "float32")
# compute the perspective transform matrix and then apply it
M = cv2.getPerspectiveTransform(rect, dst)
warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))
# return the warped image
return warped
#################################################################
## Get only rectangles given exceeding area
for cnt in contours:
approx = cv2.approxPolyDP(cnt,0.01 * cv2.arcLength(cnt, True), True)
## calculate number of vertices
#print(len(approx))
if len(approx) == 4 and cv2.contourArea(cnt) > lp_area:
print("rectangle")
tmp_img = img.copy()
cv2.drawContours(tmp_img, [cnt], 0, (0, 255, 255), 6)
cv2.imshow('Contour Borders', tmp_img)
cv2.waitKey(0)
tmp_img = img.copy()
cv2.drawContours(tmp_img, [cnt], 0, (255, 0, 255), -1)
cv2.imshow('Contour Filled', tmp_img)
cv2.waitKey(0)
# Make a hull arround the contour and draw it on the original image
tmp_img = img.copy()
mask = np.zeros((img.shape[:2]), np.uint8)
hull = cv2.convexHull(cnt)
cv2.drawContours(mask, [hull], 0, (255, 255, 255), -1)
cv2.imshow('Convex Hull Mask', mask)
cv2.waitKey(0)
# Draw minimum area rectangle
tmp_img = img.copy()
rect = cv2.minAreaRect(cnt)
box = cv2.boxPoints(rect)
box = np.int0(box)
cv2.drawContours(tmp_img, [box], 0, (0, 0, 255), 2)
cv2.imshow('Minimum Area Rectangle', tmp_img)
cv2.waitKey(0)
# Draw bounding rectangle
tmp_img = img.copy()
x, y, w, h = cv2.boundingRect(cnt)
cv2.rectangle(tmp_img, (x, y), (x + w, y + h), (0, 255, 0), 2)
cv2.imshow('Bounding Rectangle', tmp_img)
cv2.waitKey(0)
# Bounding Rectangle and Minimum Area Rectangle
tmp_img = img.copy()
rect = cv2.minAreaRect(cnt)
box = cv2.boxPoints(rect)
box = np.int0(box)
cv2.drawContours(tmp_img, [box], 0, (0, 0, 255), 2)
x, y, w, h = cv2.boundingRect(cnt)
cv2.rectangle(tmp_img, (x, y), (x + w, y + h), (0, 255, 0), 2)
cv2.imshow('Bounding Rectangle', tmp_img)
cv2.waitKey(0)
# determine the most extreme points along the contour
# https://www.pyimagesearch.com/2016/04/11/finding-extreme-points-in-contours-with-opencv/
tmp_img = img.copy()
extLeft = tuple(cnt[cnt[:, :, 0].argmin()][0])
extRight = tuple(cnt[cnt[:, :, 0].argmax()][0])
extTop = tuple(cnt[cnt[:, :, 1].argmin()][0])
extBot = tuple(cnt[cnt[:, :, 1].argmax()][0])
cv2.drawContours(tmp_img, [cnt], -1, (0, 255, 255), 2)
cv2.circle(tmp_img, extLeft, 8, (0, 0, 255), -1)
cv2.circle(tmp_img, extRight, 8, (0, 255, 0), -1)
cv2.circle(tmp_img, extTop, 8, (255, 0, 0), -1)
cv2.circle(tmp_img, extBot, 8, (255, 255, 0), -1)
print("Corner Points: ", extLeft, extRight, extTop, extBot)
cv2.imshow('img contour drawn', tmp_img)
cv2.waitKey(0)
#cv2.destroyAllWindows()
## Perspective Transform
tmp_img = img.copy()
pts = np.array([extLeft, extRight, extTop, extBot])
warped = four_point_transform(tmp_img, pts)
cv2.imshow("Warped", warped)
cv2.waitKey(0)
cv2.destroyAllWindows()
References
https://docs.opencv.org/4.5.0/dd/d49/tutorial_py_contour_features.html
https://www.pyimagesearch.com/2016/04/11/finding-extreme-points-in-contours-with-opencv/
https://www.pyimagesearch.com/2014/08/25/4-point-opencv-getperspective-transform-example/
Canny is a tool for edge detection, and if correctly tuned it does what it says on the tin.
Once you get the edges, you must define what a corner is. For instance, is it a sharp turn in a edge?
You'd like to use the function cv2.goodFeaturesToTrack, which is supposed to be a corner detection tool, but once again, what is a corner? It uses the Shi-Tomasi algorithm to find the N "best" corners in an image, which is just a threshold, and some minimum distance between points.
In the end, it is guaranteed to almost never bear the four corners you want. You should try these alternatives, and stick with the best option:
try to get more corners and geometrically determine the four "outmost" ones.
combine your method with some other transformation, or object-matching. For instance, if you are looking for a rectangular-ish image, try to match it against a template, compute the transform matrix and resolve edges after transformation.
use a different edge detection method, or a combination of methods.
Note that a card doesn't have sharp corners like a piece of paper, so you'll end up cropping the card or skewing it if using any "corner" on the rounded edges, or trying to locate an edge outside the actual "white" of the card, to avoid the skew (try to inscribe the card into a sharp-edge rectangle) - note that Canny is not effective in this case.
Here is one way to find the corners in Python OpenCV. I note this is more complicates since the green dots on the input complicate the issue and they likely would not be in the input image. One could simply threshold on the green dots using cv2.inRange() to find the green dots. But I will assume this is not really what you want.
- Read the input
- Convert to gray
- Threshold
- Get the largest contour and draw it on the input
- Reduce the number of vertices in the contour as a polygon and draw the polygon on the input.
- The polygon has 5 vertices and two are virtually the same. Normally, one would get 4 verices if the green dots were not there. So draw a white filled polygon on a black background.
- Get the corners from the white polygon on black background and draw on these vertices
- Save the results
Input:
import cv2
import numpy as np
import time
# load image
img = cv2.imread("hello.png")
# convert to gray
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# threshold
thresh = cv2.threshold(gray, 128, 255, cv2.THRESH_BINARY)[1]
# get the largest contour
contours = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
big_contour = max(contours, key=cv2.contourArea)
peri = cv2.arcLength(big_contour, True)
# draw contour on input in red
result = img.copy()
result2 = np.zeros_like(img)
cv2.drawContours(result, [big_contour], 0, (0,0,255), 1)
cv2.drawContours(result2, [big_contour], 0, (0,0,255), 1)
# reduce to fewer vertices on polygon
poly = cv2.approxPolyDP(big_contour, 0.1 * peri, False)
# draw polygon on input in green
cv2.polylines(result, [poly], False, (0,255,0), 1)
cv2.polylines(result2, [poly], False, (0,255,0), 1)
# list polygon points
print("Polygon Points:")
for p in poly:
px = p[0][0]
py = p[0][1]
print(px,py)
print('')
# draw white filled polygon on black background
result3 = np.zeros_like(thresh)
cv2.fillPoly(result3,[poly],255)
# get corners
corners = cv2.goodFeaturesToTrack(result3,4,0.01,50,useHarrisDetector=True,k=0.04)
# print corner coords and draw circles
result3 = cv2.merge([result3,result3,result3])
print("Corners:")
for c in corners:
x,y = c.ravel()
print(int(x), int(y))
cv2.circle(result3,(x,y),3,(0,0,255),-1)
# save result
cv2.imwrite("hello_contours.png", result)
cv2.imwrite("hello_polygon.png", result2)
cv2.imwrite("hello_corners.png", result3)
# display it
cv2.imshow("thresh", thresh)
cv2.imshow("result", result)
cv2.imshow("result2", result2)
cv2.imshow("result3", result3)
cv2.waitKey(0)
Contours and Polygon on input image:
Contours and Polygon on black background:
Polygon Vertices:
227 69
41 149
114 284
307 167
228 70
Note the first and last vertices are within one pixel of each other
Corners on white polygon on black background:
Corner Vertices:
306 167
42 149
114 283
227 69

Improve text area detection (OpenCV, Python)

I am working on a project which ask me to detect text area in an image. This is the result I achieved until now using the code below.
Original Image
Result
The code is the following:
import cv2
import numpy as np
# read and scale down image
img = cv2.pyrDown(cv2.imread('C:\\Users\\Work\\Desktop\\test.png', cv2.IMREAD_UNCHANGED))
# threshold image
ret, threshed_img = cv2.threshold(cv2.cvtColor(img, cv2.COLOR_BGR2GRAY),
127, 255, cv2.THRESH_BINARY)
# find contours and get the external one
image, contours, hier = cv2.findContours(threshed_img, cv2.RETR_TREE,
cv2.CHAIN_APPROX_SIMPLE)
# with each contour, draw boundingRect in green
# a minAreaRect in red and
# a minEnclosingCircle in blue
for c in contours:
# get the bounding rect
x, y, w, h = cv2.boundingRect(c)
# draw a green rectangle to visualize the bounding rect
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), thickness=1, lineType=8, shift=0)
# get the min area rect
#rect = cv2.minAreaRect(c)
#box = cv2.boxPoints(rect)
# convert all coordinates floating point values to int
#box = np.int0(box)
# draw a red 'nghien' rectangle
#cv2.drawContours(img, [box], 0, (0, 0, 255))
# finally, get the min enclosing circle
#(x, y), radius = cv2.minEnclosingCircle(c)
# convert all values to int
#center = (int(x), int(y))
#radius = int(radius)
# and draw the circle in blue
#img = cv2.circle(img, center, radius, (255, 0, 0), 2)
print(len(contours))
cv2.drawContours(img, contours, -1, (255, 255, 0), 1)
cv2.namedWindow('contours', 0)
cv2.imshow('contours', img)
while(cv2.waitKey()!=ord('q')):
continue
cv2.destroyAllWindows()
As you can see, this can do more than I need. Look for commented parts if you need more.
By the way, what I need is to bound every text area in a single rectangle not (near) every char which the script is finding. Filter the single number or letter and to round everything in a single box.
For example, the first sequence in a box, the second in another one and so on.
I searched a bit and I found something about "filter rectangle area". I don't know if it is useful for my purpose.
Tooked a look also at some of the first result on Google but most of them don't work very well. I guess the code need to be tweaked a bit but I am a newbie in OpenCV world.
Solved using the following code.
import cv2
# Load the image
img = cv2.imread('image.png')
# convert to grayscale
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# smooth the image to avoid noises
gray = cv2.medianBlur(gray,5)
# Apply adaptive threshold
thresh = cv2.adaptiveThreshold(gray,255,1,1,11,2)
thresh_color = cv2.cvtColor(thresh,cv2.COLOR_GRAY2BGR)
# apply some dilation and erosion to join the gaps - change iteration to detect more or less area's
thresh = cv2.dilate(thresh,None,iterations = 15)
thresh = cv2.erode(thresh,None,iterations = 15)
# Find the contours
contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
# For each contour, find the bounding rectangle and draw it
for cnt in contours:
x,y,w,h = cv2.boundingRect(cnt)
cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
cv2.rectangle(thresh_color,(x,y),(x+w,y+h),(0,255,0),2)
# Finally show the image
cv2.imshow('img',img)
cv2.imshow('res',thresh_color)
cv2.waitKey(0)
cv2.destroyAllWindows()
Parameters that need to be modified to obtain the result below is numbers of iterations in erode and dilate functions.
Lower values will create more bounding rectangles around (nearly) every digit/character.
Result

Categories

Resources