i am new to opencv -python.
I want to draw a rectangle in a live stream video captured from my webcam. While drawing the rectangle,the video must freeze. I am successful in drawing a rectangle on a image,but i don't know how to do the same on a live video using opencv and python . Please help..
This is a code that I'm using to draw a rectange in videos.
The code works like that:
click on video and the script save the start point
click again and the script save the end point and draw the rectangle
click again to start drawing another retangle
import numpy as np
import cv2
rect = (0,0,0,0)
startPoint = False
endPoint = False
def on_mouse(event,x,y,flags,params):
global rect,startPoint,endPoint
# get mouse click
if event == cv2.EVENT_LBUTTONDOWN:
if startPoint == True and endPoint == True:
startPoint = False
endPoint = False
rect = (0, 0, 0, 0)
if startPoint == False:
rect = (x, y, 0, 0)
startPoint = True
elif endPoint == False:
rect = (rect[0], rect[1], x, y)
endPoint = True
cap = cv2.VideoCapture('../videos/sample.avi')
waitTime = 50
#Reading the first frame
(grabbed, frame) = cap.read()
while(cap.isOpened()):
(grabbed, frame) = cap.read()
cv2.namedWindow('frame')
cv2.setMouseCallback('frame', on_mouse)
#drawing rectangle
if startPoint == True and endPoint == True:
cv2.rectangle(frame, (rect[0], rect[1]), (rect[2], rect[3]), (255, 0, 255), 2)
cv2.imshow('frame',frame)
key = cv2.waitKey(waitTime)
if key == 27:
break
cap.release()
cv2.destroyAllWindows()
Related
I am trying to write some code, where I want to save some images from the webcam on python using opencv and then I want to open each image, and on each image using a bounding box select a region of interest(ROI) that will be cropped out and save this cropped image in a new folder. For this, I am using the cv2.setMouseCallback and drawing a rectangle on each image. My code works, but the cropped images that are stored are very strange.
import cv2
# Opens the inbuilt camera of laptop to capture video.
cap = cv2.VideoCapture(0)
i = 0
training_images = []
def draw_bounding_box(click, x, y, flag_param, parameters):
global x_pt, y_pt, drawing, top_left_point, bottom_right_point, image
if click == cv2.EVENT_LBUTTONDOWN:
drawing = True
print("drawing="+str(drawing))
x_pt, y_pt = x, y
print("x_pt="+str(x_pt))
elif click == cv2.EVENT_MOUSEMOVE:
if drawing:
top_left_point, bottom_right_point = (x_pt,y_pt), (x,y)
image[y_pt:y, x_pt:x] = 255 - image[y_pt:y, x_pt:x]
cv2.rectangle(image, top_left_point, bottom_right_point, (0,255,0), 2)
elif click == cv2.EVENT_LBUTTONUP:
drawing = False
top_left_point, bottom_right_point = (x_pt,y_pt), (x,y)
copy[y_pt:y, x_pt:x] = 255 - copy[y_pt:y, x_pt:x]
cv2.rectangle(image, top_left_point, bottom_right_point, (0,255,0), 2)
bounding_box = (x_pt, y_pt, x-x_pt, y-y_pt)
cropped_im = image[y_pt:y,x_pt:x]
training_images.append(cropped_im)
if len(cropped_im)>0:
cv2.imshow("cropped",cropped_im)
cv2.imwrite('C:/Downloads/testingPictures/Frame'+str(i)+'.jpg',cropped_im)
cv2.waitKey(3000)
else:
print("could not save")
if __name__ == '__main__':
drawing = False
while(cap.isOpened() and i<10):
ret, frame = cap.read()
# This condition prevents from infinite looping
# incase video ends.
if ret == False:
break
# Save Frame by Frame into disk using imwrite method
cv2.imwrite('C:/Downloads/testingPictures/Frame'+str(i)+'.jpg', frame)
i += 1
print(i)
while(i>=1):
image = cv2.imread('C:/Users/shrut/Downloads/testingPictures/Frame'+str(i-1)+'.jpg')
copy = image.copy()
i = i-1
s = len(training_images)
cv2.namedWindow('Frame')
cv2.imshow('Frame', copy)
cv2.setMouseCallback('Frame', draw_bounding_box)
s_curr = len(training_images)
k = cv2.waitKey(5000) & 0xFF
if k == 27:
break
cv2.destroyAllWindows()
print(i)
print(len(training_images))
This is what the saved "cropped images" look like
(https://i.stack.imgur.com/KUrEs.jpg)
It looks like multiple bounding boxes superposed on the image. How can I avoid this and get the area from the image instead?
so i'm using opencv and i want to make a sort of selection tool but the problem is can't make the rectangle transparent. here's the code:
import numpy as np
import cv2 as cv
drawing = False
def draw_rec(event,x,y,flags,param):
global ix,iy,drawing
if event == cv.EVENT_LBUTTONDOWN:
drawing = True
ix,iy = x,y
elif event == cv.EVENT_LBUTTONUP:
drawing = False
cv.rectangle(img,(ix,iy),(x,y),(0,0,0),-1)
elif event == cv.EVENT_MOUSEMOVE:
if drawing == True:
cv.rectangle(img, (ix, iy), (x, y), (0, 255, 0), 5)
img = cv.imread('baboon.jpg', -1)
cv.namedWindow('image')
cv.setMouseCallback('image',draw_rec)
while(1):
cv.imshow('image',img)
k = cv.waitKey(1) & 0xFF
if k == 27:
break
cv.destroyAllWindows()
The first mistake in the code is:
elif event == cv.EVENT_LBUTTONUP:
drawing = False
cv.rectangle(img,(ix,iy),(x,y),(0,0,0),-1)
The -1 parameter means to fill the rectangle. source If we change -1 to 1:
From my point of view, the result is not satisfactory. The multiple rectangle display is caused by the mouse_movement.
elif event == cv.EVENT_MOUSEMOVE:
if drawing == True:
cv.rectangle(img, (ix, iy), (x, y), (0, 255, 0), 5)
Each time the mouse moves, the rectangle will be drawn. I think it is better if we draw when the mouse movement finishes:
Code:
import numpy as np
import cv2 as cv
drawing = False
def draw_rec(event,x,y,flags,param):
global ix,iy,drawing
if event == cv.EVENT_LBUTTONDOWN:
drawing = True
ix,iy = x,y
elif event == cv.EVENT_LBUTTONUP:
drawing = False
cv.rectangle(img,(ix,iy),(x,y),(0,255,0),5)
img = cv.imread('27BR1.jpg', -1)
cv.namedWindow('image')
cv.setMouseCallback('image',draw_rec)
while(1):
cv.imshow('image',img)
k = cv.waitKey(1) & 0xFF
if k == 27:
break
cv.destroyAllWindows()
I need to selec a ROI (region of interest), or work area, on a live video from my webcam and take a snapshot of ONLY this work area or ROI, but I can't found how to do this.
In this page https://www.learnopencv.com/how-to-select-a-bounding-box-roi-in-opencv-cpp-python/ have a code for draw a ROI but only with images, not a live video.
import cv2
cam = cv2.VideoCapture(0)
cam.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
cam.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)
cv2.namedWindow("test")
img_counter = 0
while True:
ret, frame = cam.read()
cv2.imshow("test", frame)
if not ret:
break
k = cv2.waitKey(1)
if k % 256 == 27:
# ESC pressed
print("Escape hit, closing...")
break
elif k % 256 == 32:
# SPACE pressed
img_name = "opencv_frame_{}.png".format(img_counter)
cv2.imwrite(img_name, frame)
print("{} written!".format(img_name))
img_counter += 1
cam.release()
cv2.destroyAllWindows()
This code take a snapshot with space key but not draw a ROI area.
Thanks in advance!
Here's a widget to select static ROIs from a video frame. Essentially the idea is to use cv2.setMouseCallback() and event handlers to detect if the mouse has been clicked or released. For this implementation, you can extract coordinates by holding down the left mouse button and dragging to select the desired ROI. You can reset the ROI using the right mouse button. To use the widget, press c to pause the video and start cropping. Then you are free to select the ROI. Once you have selected your ROI, press c again to crop the desired section. To resume the video, press r.
import cv2
class staticROI(object):
def __init__(self):
self.capture = cv2.VideoCapture('fedex.mp4')
# Bounding box reference points and boolean if we are extracting coordinates
self.image_coordinates = []
self.extract = False
self.selected_ROI = False
self.update()
def update(self):
while True:
if self.capture.isOpened():
# Read frame
(self.status, self.frame) = self.capture.read()
cv2.imshow('image', self.frame)
key = cv2.waitKey(2)
# Crop image
if key == ord('c'):
self.clone = self.frame.copy()
cv2.namedWindow('image')
cv2.setMouseCallback('image', self.extract_coordinates)
while True:
key = cv2.waitKey(2)
cv2.imshow('image', self.clone)
# Crop and display cropped image
if key == ord('c'):
self.crop_ROI()
self.show_cropped_ROI()
# Resume video
if key == ord('r'):
break
# Close program with keyboard 'q'
if key == ord('q'):
cv2.destroyAllWindows()
exit(1)
else:
pass
def extract_coordinates(self, event, x, y, flags, parameters):
# Record starting (x,y) coordinates on left mouse button click
if event == cv2.EVENT_LBUTTONDOWN:
self.image_coordinates = [(x,y)]
self.extract = True
# Record ending (x,y) coordintes on left mouse bottom release
elif event == cv2.EVENT_LBUTTONUP:
self.image_coordinates.append((x,y))
self.extract = False
self.selected_ROI = True
# Draw rectangle around ROI
cv2.rectangle(self.clone, self.image_coordinates[0], self.image_coordinates[1], (0,255,0), 2)
# Clear drawing boxes on right mouse button click
elif event == cv2.EVENT_RBUTTONDOWN:
self.clone = self.frame.copy()
self.selected_ROI = False
def crop_ROI(self):
if self.selected_ROI:
self.cropped_image = self.frame.copy()
x1 = self.image_coordinates[0][0]
y1 = self.image_coordinates[0][1]
x2 = self.image_coordinates[1][0]
y2 = self.image_coordinates[1][1]
self.cropped_image = self.cropped_image[y1:y2, x1:x2]
print('Cropped image: {} {}'.format(self.image_coordinates[0], self.image_coordinates[1]))
else:
print('Select ROI to crop before cropping')
def show_cropped_ROI(self):
cv2.imshow('cropped image', self.cropped_image)
if __name__ == '__main__':
static_ROI = staticROI()
I am having problems understanding regions of interest in opencv. I have some code that does a simple background subtraction from my first_frame. I am also able to draw a rectangle with my mouse_draw_rect function.
Now, I would like the background subtraction to only happen inside the rectangle that I draw because I would like to speed up the algorithm processing. I know I have to set some sort of Region of Interest but I tried it all yesterday and today and nothing that I have tried from tutorials have worked. Can someone help guide me through this process please?
EDIT: attempted to fix code
import numpy as np
import cv2
import matplotlib.pyplot as plt
cap = cv2.VideoCapture(0)
_, first_frame = cap.read()
def mouse_draw_rect(event, x, y, flags, params):
global point1, point2, drawing, first_frame, x1, x2, y1, y2
if event == cv2.EVENT_LBUTTONDOWN:
if drawing is False:
drawing = True
point1 = (x, y)
x1 = (x)
y1 = (y)
else:
drawing = False
elif event == cv2.EVENT_MOUSEMOVE:
if drawing is True:
point2 = (x, y)
x2 = (x)
y2 = (y)
elif event == cv2.EVENT_MBUTTONDOWN:
first_frame = frame
drawing = False
point1 = ()
point2 = ()
x1 = ()
x2 = ()
y1 = ()
y2 = ()
cv2.namedWindow('Original')
cv2.setMouseCallback("Original", mouse_draw_rect)
while True:
ret, frame = cap.read( )
if point1 and point2:
cv2.rectangle(frame, point1, point2, (0, 0, 0),5)
difference = cv2.absdiff(first_frame[y1:y2, x1:x2], frame[y1:y2, x1:x2])
difference = cv2.GaussianBlur(difference, (3, 3), 0)
_, difference = cv2.threshold(difference, 18, 255, cv2.THRESH_BINARY)
cv2.imshow('first frame (1)', first_frame)
cv2.imshow('Original', frame)
cv2.imshow('difference', difference)
key = cv2.waitKey(30) & 0xff
if key == 27:
break
cap.release()
cv2.destroyAllWindows()
The main problem is with the ROI selection event and how it is being called currently. The current implementation is not dynamic which means we are unable to visualize what ROI we are trying to select. Also, we have started processing before even selecting the ROI.
The proper way to select the ROI is that once we have captured the first frame, register the mouse click event and visualize the frame indefinitely with imshow and waitKey(n) until some specific key is pressed. Alternatively, we may be able to achieve the same effect without the infinite loop by using waitKey(0) (Not tested).
At this stage, we should be able to draw the desired ROI rectangle. The key factor here is the execution must be halted either by using an infinite loop or waitKey(0). Just registering the event is not enough. After ROI selection is done, then proceed with the rest of the code.
Some recommendations are as follows:
Avoid the usage of global variables where possible
Create separate window for ROI selection and discard it afterwards
Create separate functions for each individual task
Following is the complete code demonstrating correct usage of mouse click event to select the ROI for video processing:
import numpy as np
import cv2
import matplotlib.pyplot as plt
ORIGINAL_WINDOW_TITLE = 'Original'
FIRST_FRAME_WINDOW_TITLE = 'First Frame'
DIFFERENCE_WINDOW_TITLE = 'Difference'
canvas = None
drawing = False # true if mouse is pressed
#Retrieve first frame
def initialize_camera(cap):
_, frame = cap.read()
return frame
# mouse callback function
def mouse_draw_rect(event,x,y,flags, params):
global drawing, canvas
if drawing:
canvas = params[0].copy()
if event == cv2.EVENT_LBUTTONDOWN:
drawing = True
params.append((x,y)) #Save first point
elif event == cv2.EVENT_MOUSEMOVE:
if drawing:
cv2.rectangle(canvas, params[1],(x,y),(0,255,0),2)
elif event == cv2.EVENT_LBUTTONUP:
drawing = False
params.append((x,y)) #Save second point
cv2.rectangle(canvas,params[1],params[2],(0,255,0),2)
def select_roi(frame):
global canvas
canvas = frame.copy()
params = [frame]
ROI_SELECTION_WINDOW = 'Select ROI'
cv2.namedWindow(ROI_SELECTION_WINDOW)
cv2.setMouseCallback(ROI_SELECTION_WINDOW, mouse_draw_rect, params)
roi_selected = False
while True:
cv2.imshow(ROI_SELECTION_WINDOW, canvas)
key = cv2.waitKey(10)
#Press Enter to break the loop
if key == 13:
break;
cv2.destroyWindow(ROI_SELECTION_WINDOW)
roi_selected = (3 == len(params))
if roi_selected:
p1 = params[1]
p2 = params[2]
if (p1[0] == p2[0]) and (p1[1] == p2[1]):
roi_selected = False
#Use whole frame if ROI has not been selected
if not roi_selected:
print('ROI Not Selected. Using Full Frame')
p1 = (0,0)
p2 = (frame.shape[1] - 1, frame.shape[0] -1)
return roi_selected, p1, p2
if __name__ == '__main__':
cap = cv2.VideoCapture(0)
#Grab first frame
first_frame = initialize_camera(cap)
#Select ROI for processing. Hit Enter after drawing the rectangle to finalize selection
roi_selected, point1, point2 = select_roi(first_frame)
#Grab ROI of first frame
first_frame_roi = first_frame[point1[1]:point2[1], point1[0]:point2[0], :]
#An empty image of full size just for visualization of difference
difference_image_canvas = np.zeros_like(first_frame)
while cap.isOpened():
ret, frame = cap.read()
if ret:
#ROI of current frame
roi = frame[point1[1]:point2[1], point1[0]:point2[0], :]
difference = cv2.absdiff(first_frame_roi, roi)
difference = cv2.GaussianBlur(difference, (3, 3), 0)
_, difference = cv2.threshold(difference, 18, 255, cv2.THRESH_BINARY)
#Overlay computed difference image onto the whole image for visualization
difference_image_canvas[point1[1]:point2[1], point1[0]:point2[0], :] = difference.copy()
cv2.imshow(FIRST_FRAME_WINDOW_TITLE, first_frame)
cv2.imshow(ORIGINAL_WINDOW_TITLE, frame)
cv2.imshow(DIFFERENCE_WINDOW_TITLE, difference_image_canvas)
key = cv2.waitKey(30) & 0xff
if key == 27:
break
else:
break
cap.release()
cv2.destroyAllWindows()
Pro Tip:
Sometimes, when a camera is initialized, it takes some time to warm-up depending upon the ambient light present in the room. You may consider skipping a few initial frames to let the camera settle from the initialization phase. It can be done by defining the initialize_camera function in the above code as follows:
def initialize_camera(cap):
for i in range(0,60): #Skip first 60 frames
_, frame = cap.read()
return frame
Simply crop by the area in the rectangle you have drawn.
Instead of
difference = cv2.absdiff(first_frame, frame)
use
difference = cv2.absdiff(first_frame[y1:y2, x1:x2], frame[y1:y2, x1:x2])
On each frame you can create a subimage using subimage = image[y1:y2,x1:x2] And then use the subimage for processing.
A quick and dirty implementation in you code:
Replace
elif event == cv2.EVENT_MOUSEMOVE:
with
elif event == cv2.EVENT_LBUTTONUP:
And add the subimage:
if point1 and point2:
cv2.rectangle(frame, point1, point2, (0, 0, 0),5)
subimg = frame[point1[1]:point2[1],point1[0]:point2[0]]
cv2.imshow("Subimage",subimg)
AM doing a project on selected object tracking as part of it i have to detect orb feature in a selected square region a video using opencv and python.but this code doesn't work.please help me and thanks in advance
import numpy as np
import cv2
rect = (0,0,0,0)
startPoint = False
endPoint = False
def on_mouse(event,x,y,flags,params):
global rect,startPoint,endPoint
# get mouse click
if event == cv2.EVENT_LBUTTONDOWN:
if startPoint == True and endPoint == True:
startPoint = False
endPoint = False
rect = (0, 0, 0, 0)
if startPoint == False:
rect = (x, y, 0, 0)
startPoint = True
elif endPoint == False:
rect = (rect[0], rect[1], x, y)
endPoint = True
cap = cv2.VideoCapture('demo.mp4')
waitTime = 50
#Reading the first frame
(grabbed, frame) = cap.read()
#taking frames one by one
while(cap.isOpened()):
(grabbed, frame) = cap.read()
cv2.namedWindow('frame')
cv2.setMouseCallback('frame', on_mouse)
gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
orb = cv2.ORB_create()
kp = orb.detect(gray,None)
img2=frame.copy()
frame=cv2.drawKeypoints(gray,kp,img2,color=(0,255,0),flags=0)
cv2.imshow('frame', img2)
#waitkey
if cv2.waitKey(10)==27:
break
cv2.imshow('Video', img2)
cap.release()
cv2.destroyAllWindows()