how to delete objects in image using opencv - python

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()

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.

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:

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:

Python3 Tracking movement with opencv2

So, I've downloaded this source code from http://www.pyimagesearch.com/2015/05/25/basic-motion-detection-and-tracking-with-python-and-opencv/
:
# import the necessary packages
import argparse
import datetime
import imutils
import time
import cv2
# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-v", "--video", help="path to the video file")
ap.add_argument("-a", "--min-area", type=int, default=500,
help="minimum area size")
args = vars(ap.parse_args())
# if the video argument is None, then we are reading from webcam
if args.get("video", None) is None:
camera = cv2.VideoCapture(0)
time.sleep(0.25)
# otherwise, we are reading from a video file
else:
camera = cv2.VideoCapture(args["video"])
# initialize the first frame in the video stream
firstFrame = None
# loop over the frames of the video
while True:
# grab the current frame and initialize the occupied/unoccupied
# text
(grabbed, frame) = camera.read()
text = "Unoccupied"
# if the frame could not be grabbed, then we have reached the end
# of the video
if not grabbed:
break
# resize the frame, convert it to grayscale, and blur it
frame = imutils.resize(frame, width=500)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (21, 21), 0)
# if the first frame is None, initialize it
if firstFrame is None:
firstFrame = gray
continue
# compute the absolute difference between the current frame and
# first frame
frameDelta = cv2.absdiff(firstFrame, gray)
thresh = cv2.threshold(frameDelta, 25, 255, cv2.THRESH_BINARY)[1]
# dilate the thresholded image to fill in holes, then find contours
# on thresholded image
thresh = cv2.dilate(thresh, None, iterations=2)
(cnts, _) = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
# loop over the contours
for c in cnts:
# if the contour is too small, ignore it
if cv2.contourArea(c) < args["min_area"]:
continue
# compute the bounding box for the contour, draw it on the frame,
# and update the text
(x, y, w, h) = cv2.boundingRect(c)
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
text = "Occupied"
But when I run it, it gives me this error:
Traceback (most recent call last):
File "/Users/luistripa/Downloads/basic-motion-detection/motion_detector.py", line 57, in <module>
cv2.CHAIN_APPROX_SIMPLE)
ValueError: too many values to unpack (expected 2)
Can anyone help me fix this?
try adding [-2:] behind
(cnts, _) = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)[-2:]

Categories