Removing curved line from captcha - python

I am trying to read a captcha generated by SimpleCaptcha:
I've managed to remove the gradient and color:
import cv2 as cv
import numpy as np
import PyDIP as dip
import pytesseract
img = cv.imread('capt.jpg')
img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
img = cv.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,\
cv.THRESH_BINARY,11,2)
However, I can't remove the curved line or fill the letters.
I have tried the code from there and got this:
lines = dip.PathOpening(img, length=400, mode={'constrained'})
img = img-lines
img = 255 - img
lines = np.array(lines)
And with this other method I get:
# image is the previous img
gray = cv.cvtColor(image,cv.COLOR_BGR2GRAY)
thresh = cv.threshold(gray, 0, 255, cv.THRESH_BINARY_INV + cv.THRESH_OTSU)[1]
horizontal_kernel = cv.getStructuringElement(cv.MORPH_RECT, (25,1))
detected_lines = cv.morphologyEx(thresh, cv.MORPH_OPEN, horizontal_kernel, iterations=2)
cnts = cv.findContours(detected_lines, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
cv.drawContours(image, [c], -1, (255,255,255), 2)
repair_kernel = cv.getStructuringElement(cv.MORPH_RECT, (1,6))
result = 255 - cv.morphologyEx(255 - image, cv.MORPH_CLOSE, repair_kernel, iterations=1)
# results:
# detected_lines:
I'm trying to read the text with:
captcha_val=pytesseract.image_to_string(img)
This is the source of captcha. Any help?

Related

How to create an image of a Licence Plate?

I am using tesseract 5.3.0 With the code below I am able to identify the licence plate and mask it out, however when I resize the licence plate part does not increase. How do I grab just the licence portion and increase it? Any tips on reading the licence plate would also be appreciated.
import cv2
import numpy as np
import imutils
import pytesseract
pytesseract.pytesseract.tesseract_cmd = r'/usr/local/bin/tesseract'
# Load the image and convert it to grayscale
image = cv2.imread('/Users/PythonProg/IMG_4592.JPG')
if image is None:
print("Error: Could not load the image")
exit()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Apply Gaussian Blur to reduce noise and smooth the image
gray = cv2.bilateralFilter(gray, 13, 15, 15)
edged = cv2.Canny(gray, 30, 200)
contours = cv2.findContours(edged.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contours = imutils.grab_contours(contours)
contours = sorted(contours, key = cv2.contourArea, reverse = True)[:10]
screenCnt = None
# Loop over the contours and find the one with the largest area
licence_plate = None
for c in contours:
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.018 * peri, True)
if len(approx) == 4:
screenCnt = approx
break
if screenCnt is None:
detected = 0
print ("No contour detected")
else:
detected = 1
if detected == 1:
cv2.drawContours(image, [screenCnt], -1, (0, 0, 255), 3)
cv2.imwrite('/Users/PythonProg/output.jpg', image)
mask = np.zeros(gray.shape,np.uint8)
licence_plate = cv2.drawContours(mask,[screenCnt],0,255,-1,)
licence_plate = cv2.bitwise_and(image,image,mask=mask)
cv2.imwrite('/Users/anthonywilson/PythonProg/mask.jpg', licence_plate)
# Resize the masked image to a specific size
resized = cv2.resize(licence_plate, (400, 200), interpolation = cv2.INTER_AREA)
# Save the resized image
cv2.imwrite('/Users/PythonProg/resized.jpg', resized)

Detecting and ignoring rectangles that fall under another rectangle and efficient cropping

I am working on a project where I take a floor plan image as input that contains 2-3 floor plans and I need to detect each floorplan and crop them and save in as a different file.
Following are the sample input and output images.
Input:
Output:
So as you can see the second output is wrongly cropped. Also I get smaller rectangles (which are part of the output images) as byproducts.
Following is the code that I am using:
import cv2
import download_imgs_R1
import floorplan_threshold_R2
import pandas as pd
import os
filename = 'project_image.csv'
df = pd.read_csv(filename)
pids = df['id']
urls = df['complete_url']
for pid,url in zip(pids,urls):
name = url.split('/')[-1]
ext = name.split('.')[-1]
filepath = './xxxx/{}/original_images/'.format(pid)
savepath = './xxxx/{}/processed_images/'.format(pid)
savename = name.split('.')[0]
save = savepath+savename+'{}.png'
if ext == 'pdf':
image_name = download_imgs_R1.extract_from_pdf(filename=name, dest=filepath)
else:
image_name = filepath+name
print(image_name)
no_padding_image, crop_img_name = floorplan_threshold_R2.remove_white_space(image_name)
feature_dict = floorplan_threshold_R2.get_img_features(no_padding_image)
cont, hier = floorplan_threshold_R2.contour_method(no_padding_image)
area_dict = floorplan_threshold_R2.max_rect(cont)
roi_area = []
print(feature_dict)
img_area = feature_dict['area']
for area in area_dict:
if area >= img_area*0.1 and area < img_area:
roi_area.append(area)
plan_no = 1
for a in roi_area:
plan = area_dict[a]
# del area_dict[a]
x,y,w,h = plan
aspect_ratio = h/w
if x <=50 or y <= 25:
roi = no_padding_image[y:y+h, x:x+w]
else:
roi = no_padding_image[y-50:y+h+10, x-20:x+w+10]
print('PID: {}, No. {}'.format(pid,plan_no))
# cv2.rectangle(no_padding_image, (x-10,y-10), (x+w+10, y+h+10), (255,255,255), 2)
# roi = cv2.copyMakeBorder(roi, 10, 10, 10, 10, cv2.BORDER_CONSTANT, None, value = [255,255,255])
# cv2.imshow('ROI-{}'.format(image_name),roi)
cv2.imwrite(save.format(plan_no),roi)
cv2.waitKey(0)
plan_no += 1
floor_plan_threshold_R2.py:
import cv2
from cv2 import dilate
from cv2 import findContours
import imutils
import numpy as np
import download_imgs_R1
def remove_white_space(filename:str):
savename = filename
img = cv2.imread(filename=filename)
orignal = img.copy()
gray = cv2.cvtColor(orignal, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (25,25), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
# Perform morph operations, first open to remove noise, then close to combine
noise_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, noise_kernel, iterations=2)
close_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (7,7))
close = cv2.morphologyEx(opening, cv2.MORPH_CLOSE, close_kernel, iterations=3)
# Find enclosing boundingbox and crop ROI
coords = cv2.findNonZero(close)
x,y,w,h = cv2.boundingRect(coords)
# cv2.rectangle(orignal, (x, y), (x + w, y + h), (36,255,12), 2)
if x <= 50 or y <= 10:
crop = orignal[y:y+h, x:x+w]
else:
crop = orignal[y-10:y+h+10, x-60:x+w+10]
cv2.imwrite(savename,crop)
# cv2.imshow('Removed White space (Preprocess - 1)',crop)
cv2.waitKey(0)
return crop, savename
def get_img_features(image, filename:str=None,resize:bool=False):
if not filename:
res = image.copy()
else:
res = cv2.imread(filename)
img_height, img_width, img_channel = image.shape
if resize is True and image.shape[0] > 800:
res = imutils.resize(res, height=720)
img_height, img_width, img_channel = res.shape
img_area = img_width * img_height
img_aspect_ratio = img_width/img_height
img_features = {'height':img_height, 'width':img_width, 'area':img_area, 'aspect_ratio':img_aspect_ratio}
return img_features
def mask_method(image, filename:str=None):
if not filename:
res = image.copy()
else:
res = cv2.imread(filename)
hsv_plan = cv2.cvtColor(res, cv2.COLOR_BGR2HSV)
#define range for blue color (HSV Range)
blue_min = np.array([14,100,76])
blue_max = np.array([130,255,255])
bluemask = cv2.inRange(hsv_plan,blue_min,blue_max)
blue_output = cv2.bitwise_and(hsv_plan, hsv_plan, mask=bluemask)
grey_mask = cv2.cvtColor(blue_output, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(grey_mask, 100, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
kernel = np.ones((3,3), np.uint8)
dil = dilate(thresh, kernel, iterations=2)
cont,hier = findContours(dil, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
return cont, hier
def contour_method(image, filename:str=None):
if not filename:
res = image.copy()
else:
res = cv2.imread(filename)
grey_plan = cv2.cvtColor(res, cv2.COLOR_BGR2GRAY)
ret2, thresh2 = cv2.threshold(grey_plan, 160, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
kernel = np.ones((3,3), np.uint8)
dil_grey = dilate(thresh2, kernel, iterations=2)
cont,hier = findContours(dil_grey, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
return cont,hier
def max_rect(cntrs):
ar = {}
for cnt in cntrs:
x,y,w,h = cv2.boundingRect(cnt)
area = w*h
ar[area] = (x,y,w,h)
return ar
I need to find a generic solution for cropping the image as just providing a number for cropping will affect other images as well.

Drawing contures on canvas with OpenCV

I want to detect contours in freshly made screenshot, and while I can access number of contours found, I cannot draw them on black canva, this is my code:
while True:
keyboard.wait('right')
img = pyautogui.screenshot()
img = cv.cvtColor(np.array(img), cv.COLOR_RGB2BGR)
img = CropImage(img)
blank = np.zeros(img.shape[:2], dtype='uint8')
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(gray, 122, 255, cv.THRESH_BINARY)
contours, hierarchies = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
print(f'{len(contours) } contours found')
cv.drawContours(blank, contours, -1, (0,255,0))
cv.imwrite('C:/screeny/screen0.png', blank)

OpenCV: Remove doubled contours on outlines of shapes without using RETR_EXTERNAL

Open CV will register both an inner and an outer contour for an outline of a polygon.
Running with the test code below
import cv2
import numpy as np
def extract_contours():
path = 'test.png'
blank = np.zeros((184,184,3), np.uint8)
blank[:] = (255,255,255)
raw = cv2.imread(path, cv2.IMREAD_UNCHANGED)
raw = 255-raw
img = cv2.cvtColor(raw, cv2.COLOR_BGR2GRAY)
contours, hierarchy = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
print(len(contours))
for cnt in contours:
area = cv2.contourArea(cnt)
if area > 400:
approx = cv2.approxPolyDP(cnt, 0.009 * cv2.arcLength(cnt, True), True)
cv2.drawContours(blank, [approx], 0, (0, 0, 255), 1)
cv2.imwrite('contours.png', blank)
extract_contours()
On the image
will yield two sets of contours on the outer and inner edge as shown in
Is there any fast way to collapse the two sets of contours into a single contour, preferably the average of the two? Using I am fairly new to CV2 and computer vision in general so I don't know a lot of the tricks. I would rather not use RETR_EXTERNAL since I do not want to miss out on any nested shapes.
You can use the hierarchy variable you defined (when calling the cv2.findContours method) to determine whether a contour is on the exterior of the outline or the interior:
import cv2
import numpy as np
def extract_contours():
path = 'test.png'
blank = np.zeros((184, 184, 3), np.uint8)
blank[:] = (255, 255, 255)
raw = cv2.imread(path, cv2.IMREAD_UNCHANGED)
raw = 255 - raw
img = cv2.cvtColor(raw, cv2.COLOR_BGR2GRAY)
contours, hierarchy = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
for cnt, hrc in zip(contours, hierarchy[0]):
area = cv2.contourArea(cnt)
if area > 400:
approx = cv2.approxPolyDP(cnt, 0.009 * cv2.arcLength(cnt, True), True)
if hrc[2] < 0:
cv2.drawContours(blank, [approx], 0, (0, 0, 255), 1)
elif hrc[3] < 0:
cv2.drawContours(blank, [approx], 0, (0, 255, 0), 1)
cv2.imwrite('contours.png', blank)
extract_contours()
Resulting image:
Drawing the contour in between the exterior and interior contours:
import cv2
import numpy as np
def extract_contours():
path = 'test.png'
blank = np.zeros((184, 184, 3), np.uint8)
blank[:] = (255, 255, 255)
raw = cv2.imread(path, cv2.IMREAD_UNCHANGED)
raw = 255 - raw
img = cv2.cvtColor(raw, cv2.COLOR_BGR2GRAY)
contours, hierarchy = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
exte = None
inte = None
for cnt, hrc in zip(contours, hierarchy[0]):
area = cv2.contourArea(cnt)
if area > 400:
approx = cv2.approxPolyDP(cnt, 0.009 * cv2.arcLength(cnt, True), True)
if hrc[2] < 0:
exte = approx.squeeze()
elif hrc[3] < 0:
inte = approx.squeeze()
exte = exte[np.lexsort(exte.T)]
inte = inte[np.lexsort(inte.T)]
box = cv2.convexHull((exte[exte[:, 0].argsort()] + inte[inte[:, 0].argsort()]) // 2)
cv2.drawContours(blank, [box], -1, (0, 0, 255), 1)
cv2.imwrite('contours.png', blank)
extract_contours()
Resulting image:

Separation of bounding boxes

In this problem we are trying to detect persons in a WEBCAM video in REAL TIME. The code is working fine for 1 person but when more than one person is entering then the code is failing miserably. Here is the code :-
import cv2
import numpy as np
cap = cv2.VideoCapture(0)
kernel = np.ones((5,5), np.uint8)
background = None
while True:
ret,frame = cap.read()
gray = frame.copy()
gray = cv2.cvtColor(gray, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (11,11), 0)
if background is None:
background = gray
continue
delta = cv2.absdiff(background, gray)
thresh = cv2.threshold(delta, 5, 255,
cv2.THRESH_BINARY+cv2.THRESH_OTSU)[1]
thresh = cv2.dilate(thresh, kernel, iterations=2)
_,contours,hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
if(len(contours)==0):
continue
#areas = [cv2.contourArea(c) for c in contours]
#max_index = np.argmax(areas)
#cnt=contours[max_index]
#(x,y,w,h) = cv2.boundingRect(cnt)
#if(1.0*(w*h)/(640*480)<0.75):
#cv2.rectangle(frame, (x,y), (x+w,y+h), (0,0,255), 3)
#print("Area: ",w*h)
for i in range(len(contours)):
(x,y,w,h) = cv2.boundingRect(contours[i])
if(w*h<=90000):
cv2.rectangle(frame, (x,y), (x+w,y+h), (0,0,255), 5)
#cv2.imshow('thresh', thresh)
cv2.imshow('frame', frame)
if cv2.waitKey(1)==27:
break
cap.release()
cv2.destroyAllWindows()
I think the problem is that the code is not able to separate the different contours of the different persons detected but I may not be the only reason. Can someone help me?

Categories