How to create an image of a Licence Plate? - python

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)

Related

how to delete objects in image using opencv

I'm relatively new to openCV, my requirement is to delete smaller island (could not attach image because of post limitation)
I have followed below code:
(1)Applied background subtraction to keep only moving objects
(2)Applied Erosion Dilation to fill the holes
(3)calculated the Average area of objects (contours)
(4)Now I want to keep only objects which is greater than Average area(Here is where i need literally help, i tried online but could not find a solution)
from __future__ import print_function
import cv2 as cv
import argparse
import numpy as np
array = [None] * 100
parser = argparse.ArgumentParser(description='')
parser.add_argument('--input', type=str, help='Path to a video or a sequence of image.', default='vtest.avi')
# parser.add_argument('--algo', type=str, help='Background subtraction method (KNN, MOG2).', default='MOG2')
parser.add_argument('--algo', type=str, help='Background subtraction method (KNN, MOG2).', default='KNN')
args = parser.parse_args()
# create Background Subtractor objects
if args.algo == 'MOG2':
backSub = cv.createBackgroundSubtractorMOG2()
else:
backSub = cv.createBackgroundSubtractorKNN()
capture = cv.VideoCapture("test.mp4")
if not capture.isOpened():
print('Unable to open: ' + args.input)
exit(0)
while True:
ret, frame = capture.read()
if frame is None:
break
# update the background model
fgMask = backSub.apply(frame)
# Erosion and Dilation
kernel = np.ones((3, 3), np.int8)
erosion = cv.erode(fgMask, kernel, iterations=1)
dilation = cv.dilate(erosion, kernel, iterations=2)
## [apply]
# contours, hierarchy = cv2.findContours(dilation, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
contours, hierarchy = cv.findContours(dilation, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
print("Number of Contours = " + str(len(contours)))
# Find max contours
# contour = max(contours, key=len)
'''contourImg = cv.drawContours(frame, contour, -1, (0, 255, 0), 3)
cv.imshow("Contours", contourImg)'''
Contour_Cnts = 0
Total_Area_Of_all_Contour = 0
Average_Area_Of_Contour = 0
for cnt in contours:
area = cv.contourArea(cnt)
Total_Area_Of_all_Contour = Total_Area_Of_all_Contour + area
Contour_Cnts = Contour_Cnts + 1
Average_Area_Of_Contour = Total_Area_Of_all_Contour // Contour_Cnts
print("Number of contours", Contour_Cnts)
Contour_Cnts = 0
index = 0
for cnt in contours:
Contour_Cnts = Contour_Cnts + 1
area = cv.contourArea(cnt)
if area > Average_Area_Of_Contour:
index = int(index) + 1
# array[index] = contours[Contour_Cnts]
# cv.drawContours(frame, array, -1, (0,0,255), 2)
cv.imshow('Frame', frame)
cv.imshow('FG Mask', fgMask)
cv.imshow('Dilation', dilation)
capture.release()
cv.destroyAllWindows()

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.

problem to recognize the text on a plate with tesseract

I need a hand to be able to fix my project with opencv, which consists in detecting plates and using tesseract to extrapolate the content, but I don't understand why only the text written on a white background detects me and not when I use a real plate. I tried to arrange the image in order to make it more legible and maybe frame only the white part of the European license plates in order to simplify the extrapolation of the text, but nothing I can not isolate only the white. I using a raspberry pi 4, i don't know if it can be useful
Could anyone help me? Many thanks in advance.
print("Aspetta 5 secondi per catturare l'immagine, oppure premi <space> per scattare...")
cam = cv2.VideoCapture(0)
num_frames = 0
while True:
ret, image = cam.read()
if not ret:
print("La webcam non funziona...")
sys.exit(1)
cv2.imshow('image', image)
# Catturo l'immagine se premo <space>
if (cv2.waitKey(1) & 0xFF) == ord(' '):
break
# Aspetto 5 secondi prima di catturare l'immagine
num_frames += 1
if num_frames / 10 == 5:
break
cam.release()
cv2.destroyAllWindows()
cv2.imwrite("/home/pi/Desktop/Riconoscimento Targa/imagee.jpg", image)
filename = 'imagee.jpg'
img = np.array(Image.open(filename))
img = cv2.resize(img, (600,400) )
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = cv2.bilateralFilter(gray, 13, 15, 15)
edged = cv2.Canny(gray, 30, 200) #Perform Edge detection
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
for c in contours:
# approximate the contour
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.018 * peri, True)
# if our approximated contour has four points, then
# we can assume that we have found our screen
if len(approx) == 4:
screenCnt = approx
break
# Masking the part other than the number plate
mask = np.zeros(gray.shape,np.uint8)
new_image = cv2.drawContours(mask,[screenCnt],0,255,-1,)
new_image = cv2.bitwise_and(img,img,mask=mask)
# Now crop
(x, y) = np.where(mask == 255)
(topx, topy) = (np.min(x), np.min(y))
(bottomx, bottomy) = (np.max(x), np.max(y))
Cropped = gray[topx:bottomx+1, topy:bottomy+1]
cv2.imwrite("/home/pi/Desktop/Riconoscimento Targa/Da eliminare.jpg", Cropped)
text = pytesseract.image_to_string(Cropped, config='--psm 11 -l ita')
return text

Unable to clip and save the ROI/bounding box in opencv python

Im trying to save only the rectangular ROI region from a video file into images. But the entire image is getting saved with the RED rectangular ROI box on it. What am I doing wrong here ?
I tried saving rect_img but thats giving error "!_img.empty() in function 'imwrite'" ,
and not saving any images at all.
The upper_left and bottom_right coordinates are for a 1920 X 1080p video, you wil have to adjust is as per your video resolution.
import cv2
from matplotlib import pyplot as plt
import imutils
import numpy as np
import pytesseract
cam_capture = cv2.VideoCapture('1080_EDIT.webm')
upper_left = (1400, 700)
bottom_right = (700, 1000)
ctr=1 #filename counter
while True:
_, image_frame = cam_capture.read()
ctr+=1
#Rectangle marker
r = cv2.rectangle(image_frame, upper_left, bottom_right, (100, 50, 200), 5)
rect_img = image_frame[upper_left[1] : bottom_right[1], upper_left[0] : bottom_right[0]]
cv2.imwrite("rect"+str(ctr)+".jpg",r)
#print (rect_img)
#img=cv2.imread(rect_img)
gray = cv2.cvtColor(r, cv2.COLOR_BGR2GRAY)
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
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(r, [screenCnt], -1, (0, 0, 255), 3)
cv2.imshow("image", image_frame)
if cv2.waitKey(1) % 256 == 27 :
break
cam_capture.release()
cv2.destroyAllWindows()
Solved it by
roi=r[700:1000,700:1400]
cv2.imwrite("rect"+str(ctr)+".jpg",roi)

How to crop multiple ROI in image using Python and OpenCV

I have an image that converted from PDF to PNG. The converted image contains several keywords that I wanted to extracted using OCR Tesseract.
Right now, I need to determine the ROI manually to crop the selected ROI. Since I have more than 5 ROI's to be applied, what would be the most efficient way to apply the ROI instead of doing it by try and error to find the exact location?
Below is the code:
def cropped(self, event):
#1st ROI
y = 20
x = 405
h = 230
w = 425
#2nd ROI
y1 = 30
x1 = 305
h1 = 330
w1 = 525
#open the converted image
image = cv2.imread("Output.png")
#perform image cropping
crop_image = image[x:w, y:h]
crop_image1 = image[x1:w1, y1:h1]
#save the cropped image
cv2.imwrite("Cropped.png", crop_image)
cv2.imwrite("Cropped1.png", crop_image1)
#open the cropped image and pass to the OCR engine
im = cv2.imread("Cropped.png")
im1 = cv2.imread("Cropped1.png")
## Do the text extraction here
you can use mouse event to select multiple ROI and crop based on the location
#!/usr/bin/env python3
import argparse
import cv2
import numpy as np
from PIL import Image
import os
drawing = False # true if mouse is pressed
ix,iy = -1,-1
refPt = []
img = ""
clone = ""
ROIRegion = []
# mouse callback function
def draw_rectangle(event,x,y,flags,param):
global ix,iy,drawing,img,clone,refPt, ROIRegion
if event == cv2.EVENT_LBUTTONDOWN:
drawing = True
ix,iy = x,y
refPt = [(x, y)]
ROIRegion.append(refPt)
#clone = img.copy()
elif event == cv2.EVENT_MOUSEMOVE:
if drawing == True:
img = clone.copy()
cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),3)
a=x
b=y
if a != x | b != y:
cv2.rectangle(img,(ix,iy),(x,y),(0,0,0),-1)
elif event == cv2.EVENT_LBUTTONUP:
drawing = False
refPt.append((x,y))
img = clone.copy()
cv2.rectangle(img, (ix,iy),(x,y), (0, 255, 0), 2)
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True, help="Path to the image")
args = vars(ap.parse_args())
# load the image, clone it, and setup the mouse callback function
img = cv2.imread(args["image"])
img = np.array(img)
clone = img.copy()
cv2.namedWindow('image')
cv2.setMouseCallback('image',draw_rectangle)
while(1):
cv2.imshow('image',img)
k = cv2.waitKey(1) & 0xFF
if k == ord("r"):
del ROIRegion[-1]
del refPt[-1]
img = clone.copy()
elif k == 27:
break
#Do your cropping here
for region in range(len(ROIRegion)):
cv2.rectangle(img, ROIRegion[region][0],ROIRegion[region][1], (0, 255, 0), 2)
roi = clone[ROIRegion[region][0][1]:ROIRegion[region][1][1], ROIRegion[region][0][0]:ROIRegion[region][1][0]]
roi = cv2.cvtColor(roi, cv2.COLOR_BGR2RGB)
Here is one way in Python/OpenCV.
Read the input
Threshold on box outline color
Apply morphology to ensure closed
Get the external contours
Loop over each contour, get its bounding box, crop the region in the input and write the output
Input:
import cv2
import numpy as np
# read image
img = cv2.imread('text_boxes.jpg')
# threshold on box outline color
lowerBound = (80,120,100)
upperBound = (160,200,180)
thresh = cv2.inRange(img, lowerBound, upperBound)
# apply morphology to ensure regions are filled and remove extraneous noise
kernel = np.ones((3,3), np.uint8)
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
# get contours
contours = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
# get bounding boxes
i = 1
for cntr in contours:
# get bounding boxes
x,y,w,h = cv2.boundingRect(cntr)
crop = img[y:y+h, x:x+w]
cv2.imwrite("text_boxes_crop_{0}.png".format(i), crop)
i = i + 1
# save threshold
cv2.imwrite("text_boxes_thresh.png",thresh)
# show thresh and result
cv2.imshow("thresh", thresh)
cv2.waitKey(0)
cv2.destroyAllWindows()
Threshold image:
Cropped Images:

Categories