Python Opencv, don't put circle on the video - python

I wrote the following script with OpenCV
import cv2
import numpy as np
cap = cv2.VideoCapture(0)
ix, iy = -1, -1
def draw_circle(event, x, y, flags, param):
global ix
global iy
ix,iy = x,y
if event == cv2.EVENT_LBUTTONDOWN:
cv2.circle(img, (200, 399), 10, (0, 255, 255), -1)
print("Text Put")
elif event == cv2.EVENT_LBUTTONUP:
print("EVENT_LBUTTONUP")
elif event == cv2.EVENT_RBUTTONDOWN:
print("Appuyé Droite")
elif event == cv2.EVENT_RBUTTONUP:
print("EVENT_RBUTTONUP")
elif event == cv2.EVENT_MOUSEMOVE:
print("Move on", x, y)
while(1):
ret, img = cap.read()
cv2.setMouseCallback('image', draw_circle)
cv2.imshow('image', img)
if cv2.waitKey(20) & 0xFF == 27:
break
cv2.destroyAllWindows()
But when I do a right button click, no circle appears on the display. What is wrong with my code ?

This code snippet may help you get started:
import cv2
import numpy as np
cap = cv2.VideoCapture(0)
ix, iy = -1,-1
def mouseCallback(event,x,y,flags,param):
global ix
global iy
if event == cv2.EVENT_LBUTTONDOWN:
ix = x # saves the position of the last click
iy = y
elif event == cv2.EVENT_LBUTTONUP:
print("EVENT_LBUTTONUP")
elif event == cv2.EVENT_RBUTTONDOWN:
print("Appuyé Droite")
elif event == cv2.EVENT_RBUTTONUP:
print("EVENT_RBUTTONUP")
def draw_circle_onscreen(frame, x,y):
cv2.circle(frame, (x,y), 10,(0, 0, 255),-1)
cv2.namedWindow('frame')
cv2.setMouseCallback('frame',mouseCallback) # mouse callback has to be set only once
while(1):
ret, img = cap.read()
draw_circle_onscreen(img,ix,iy) # draws circle on screen
cv2.imshow('frame',img)
if cv2.waitKey(20) & 0xFF == 27:
break
cv2.destroyAllWindows()

Related

Multiple overlapping rectangle being drawn over an image when using cv2 to draw using mouse

I was trying to draw rectangles using mouse over an image, using openCV package in python. When ever I drew a rectangle, I got multiple rectangles overlapping one another, instead of a single rectangle. Like the below image
Here is my code. Please tell me where I went wrong and what needs to be corrected, so that I get only 1 rectangle.
import cv2
import numpy as np
drawing = False
ix,iy = -1, -1
img = cv2.imread('drawing_over_image/dog.jpg')
def draw(event, x, y, flags, params):
global ix, iy, drawing
if event == cv2.EVENT_LBUTTONDOWN:
ix,iy = x,y
drawing = True
elif event == cv2.EVENT_MOUSEMOVE:
if drawing:
if ix < x and iy < y:
cv2.rectangle(img=img, pt1=(ix,iy), pt2=(x,y), color=[255,0,0], thickness=1)
elif event == cv2.EVENT_LBUTTONUP:
drawing = False
cv2.rectangle(img=img, pt1=(ix,iy), pt2=(x,y), color=[255,0,0], thickness=1)
if __name__ == "__main__":
while True:
cv2.imshow(winname='image', mat=img)
cv2.setMouseCallback('image', draw)
if cv2.waitKey(1) == 27:
cv2.destroyAllWindows()
break
Its drawing multiple rectangles because you are drawing rectangles on every mouse move after user is pressing on the button. Instead you should draw whenever the event is done namely when the user release the left button. I fixed your code and add a basic ref image for you to see your rectangle when you are drawing. Hope it helps!
import cv2
import numpy as np
drawing = False
ix,iy = -1, -1
img = cv2.imread('drawing_over_image/dog.jpg')
refimg = img.copy()
def draw(event, x, y, flags, params):
global ix, iy, drawing
if event == cv2.EVENT_LBUTTONDOWN:
ix,iy = x,y
drawing = True
elif event == cv2.EVENT_MOUSEMOVE:
if drawing:
if ix < x and iy < y:
cv2.rectangle(img=refimg, pt1=(ix,iy), pt2=(x,y), color=[255,0,0], thickness=1)
elif event == cv2.EVENT_LBUTTONUP:
drawing = False
if ix < x and iy < y:
cv2.rectangle(img=img, pt1=(ix,iy), pt2=(x,y), color=[255,0,0], thickness=1)
if __name__ == "__main__":
while True:
cv2.imshow(winname='image', mat=refimg)
cv2.setMouseCallback('image', draw)
refimg = img.copy()
if cv2.waitKey(1) & 0xFF == 27:
cv2.destroyAllWindows()
break
Output:
You have two options:
use cv.selectROI()
do it all by hand
with selectROI()
rect = cv.selectROI("image", img, False)
cv.destroyWindow("image")
print(rect) # (x,y,w,h) or (0,0,0,0)
by hand
keep the original image
while dragging, from the event handler, draw on a copy, imshow() that
handle mousedown, mousemove, mouseup
call separate completion and cancelation functions to make it neat
sel1 = None # first point
sel2 = None # second point
def on_mouse(event, x, y, flags, params):
global sel1, sel2
if event == cv2.EVENT_LBUTTONDOWN:
sel1 = (x,y)
sel2 = None
elif event == cv2.EVENT_RBUTTONDOWN:
cancel_selection()
elif event == cv2.EVENT_MOUSEMOVE:
if sel1 is not None:
canvas = img.copy()
cv2.rectangle(canvas, sel1, (x,y), color=[255,0,0], thickness=2)
cv2.imshow("image", canvas)
elif event == cv2.EVENT_LBUTTONUP:
if sel1 is not None:
sel2 = (x,y)
selection_done(sel1, sel2)
sel1 = sel2 = None
def cancel_selection():
global sel1
sel1 = None
# restore display
cv2.imshow("image", img)
def selection_done(pt1, pt2):
# draw on the source image?
cv2.rectangle(img, pt1, pt2, color=[255,255,0], thickness=2)
cv2.imshow("image", img)
if __name__ == "__main__":
cv2.imshow('image', img)
cv2.setMouseCallback('image', on_mouse)
while True:
key = cv2.waitKey()
if key == 27: # ESC cancels ongoing selection, or exits the window
if sel1 is None:
break
else:
cancel_selection()
cv2.destroyAllWindows()

how to select circle automatically on image with mouse and crop it using python with open cv

I want to select a circular part of an image automatically using the mouse and then crop and save it, how can I do that using open cv
Here is the following code for cropping images using a mouse.
import cv2
cropping = False
x_start, y_start, x_end, y_end = 0, 0, 0, 0
image = cv2.imread('normal_face1624.jpg')
oriImage = image.copy()
def mouse_crop(event, x, y, flags, param):
global x_start, y_start, x_end, y_end, cropping
if event == cv2.EVENT_LBUTTONDOWN:
x_start, y_start, x_end, y_end = x, y, x, y
cropping = True
# Mouse is Moving
elif event == cv2.EVENT_MOUSEMOVE:
if cropping == True:
x_end, y_end = x, y
# if the left mouse button was released
elif event == cv2.EVENT_LBUTTONUP:
# record the ending (x, y) coordinates
x_end, y_end = x, y
cropping = False # cropping is finished
refPoint = [(x_start, y_start), (x_end, y_end)]
if len(refPoint) == 2: #when two points were found
roi = oriImage[refPoint[0][1]:refPoint[1][1], refPoint[0][0]:refPoint[1][0]]
cv2.imwrite('crop_image.png', roi)
cv2.imshow("Cropped", roi)
cv2.namedWindow("image")
cv2.setMouseCallback("image", mouse_crop)
while True:
i = image.copy()
if not cropping:
cv2.imshow("image", image)
elif cropping:
cv2.rectangle(i, (x_start, y_start), (x_end, y_end), (255, 0, 0), 2)
cv2.imshow("image", i)
if cv2.waitKey(1) == ord('q'):
break
# close all open windows
cv2.destroyAllWindows()

OpenCV object detecting and save videofile

I want to object detect and save the video, but the video saved only 6kb or 0kb and it can't be play
If there is no this line
x, y, width, height, area = stats[index]
it will be saved
Do you know why And is there a solution?
import cv2
import time
import numpy as np
cap = cv2.VideoCapture("rtsp://admin:admin#128.1.1.110:554")
width = int(cap.get(3))
height = int(cap.get(4))
fcc = cv2.VideoWriter_fourcc(*'XVID')
recording = False
fgbg = cv2.createBackgroundSubtractorMOG2(varThreshold=200, detectShadows=0)
while(1):
ret, frame = cap.read()
hms = time.strftime('%H_%M_%S', time.localtime())
fgmask = fgbg.apply(frame)
nlabels, labels, stats, centroids = cv2.connectedComponentsWithStats(fgmask)
for index, centroid in enumerate(centroids):
if stats[index][0] == 0 and stats[index][1] == 0:
continue
if np.any(np.isnan(centroid)):
continue
x, y, width, height, area = stats[index]
centerX, centerY = int(centroid[0]), int(centroid[1])
if area > 200:
cv2.circle(frame, (centerX, centerY), 1, (0, 255, 0), 2)
cv2.rectangle(frame, (x, y), (x + width, y + height), (0, 0, 255))
cv2.putText(frame, str(area), (centerX, y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 255))
cv2.imshow('frame', frame)
k = cv2.waitKey(1) & 0xff
if k == ord('r') and recording is False:
path = 'test_' + str(hms) + '.avi'
print('recording start')
writer = cv2.VideoWriter(path, fcc, 30.0, (width, height))
recording = True
if recording:
writer.write(frame)
if k == ord('e'):
print('recording end')
recording = False
writer.release()
cap.release()
cv2.destroyAllWindows()
I think this will solve your problem
# importing the module
import cv2
import numpy as np
# reading the vedio
source = cv2.VideoCapture(0) // add your URL insed of "0"
# We need to set resolutions.
# so, convert them from float to integer.
frame_width = int(source.get(3))
frame_height = int(source.get(4))
recording = False
fcc = cv2.VideoWriter_fourcc(*'XVID')
size = (frame_width, frame_height)
fgbg = cv2.createBackgroundSubtractorMOG2(varThreshold=200, detectShadows=0)
result = cv2.VideoWriter('output.avi', fcc, 30, size)
# running the loop
while True:
# extracting the frames
ret, frame = source.read()
fgmask = fgbg.apply(frame)
nlabels, labels, stats, centroids = cv2.connectedComponentsWithStats(fgmask)
for index, centroid in enumerate(centroids):
if stats[index][0] == 0 and stats[index][1] == 0:
continue
if np.any(np.isnan(centroid)):
continue
x, y, width, height, area = stats[index]
centerX, centerY = int(centroid[0]), int(centroid[1])
if area > 200:
cv2.circle(frame, (centerX, centerY), 1, (0, 255, 0), 2)
cv2.rectangle(frame, (x, y), (x + width, y + height), (0, 0, 255))
cv2.putText(frame, str(area), (centerX, y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 255))
# displaying the video
cv2.imshow("Live", frame)
k = cv2.waitKey(1) & 0xff
if k == ord('r') and recording is False:
print('recording start')
recording = True
if recording:
result.write(frame)
if k == ord('e'):
print('recording end')
recording = False
result.release()
# closing the window
cv2.destroyAllWindows()
source.release()
But unfortunately, I can not hms with the output file name.
That can try your self
If helpful this for you give 👍
Actually, you need to delete some codes.
cv2.imshow('MultiTracker', frame)
# quit on ESC button
if cv2.waitKey(1) & 0xFF == 27: # Esc pressed
break
# k = cv2.waitKey(1) & 0xff
#if k == ord('r') and recording is False:
# print('recording start')
# recording = True
#if recording:
result.write(frame)
#if k == ord('e'):
# print('recording end')
# recording = False
# result.release()
result.release()
cv2.destroyAllWindows()
cap.release()
it works for me, the reason why it is 6kb is you start write but not append frame to output avi file.

Click mouse and draw fixed rectangle at mouse position in Video (python_opencv)

So during my webcam/video I would like to when I click my mouse, a rectangle is drawn at the mouse position, and the rectangle size is fixed ex. 80 X 80. In my current code, the rectangle follows the mouse but the size is always different. I want a fixed size exactly at the mouse position when I Click on a frame in the video.
Here is my code.
import os
import numpy as np
import cv2
from PIL import Image
import re
print('kaishi')
flag=0
drawing = False
point1 = ()
point2 = ()
ref_point = []
xvalues=[];
yvalues=[];
ref_point = []
cx=0;
cy=0;
def mouse_drawing(event, x, y, flags, params):
global point1, point2,
drawing,ref_point2,flag,refPt,cropping,cx,cy
if event == cv2.EVENT_LBUTTONDOWN:
drawing = True
point1 = (x, y)
xvalues.append(x)
yvalues.append(y)
cx =x;
cy=y;
elif event == cv2.EVENT_MOUSEMOVE:
if drawing is True:
point2 = (x, y)
elif event == cv2.EVENT_LBUTTONUP:
flag+=1;
print('finished square')
cap = cv2.VideoCapture(0)
cv2.namedWindow("Frame")
cv2.setMouseCallback("Frame", mouse_drawing)
while True:
_, frame = cap.read()
if point1 and point2 :
cv2.rectangle(frame,(200,cy),(cx,128),(0,0,255),0)
print(cx,cy)
flag=0;
cv2.imshow("Frame", frame)
key = cv2.waitKey(25)
if key== 13:
print('done')
elif key == 27:
break
cap.release()
cv2.destroyAllWindows()
The problem is that you fixed a point of the rectangle and the other point follows the mouse. In your code it would be here:
cv2.rectangle(frame,(200,cy),(cx,128),(0,0,255),0)
Now, it will depend how the rectangle will be, is the point where you click the top left point? if it is then it should be something like:
cv2.rectangle(frame,(cx,cy),(cx + 80, cy +80),(0,0,255),0)
This example will be for a 80 x 80 rectangle.... In your code this will happen when you click.
However, your code has a lot of unused code... I would do something like this:
import numpy as np
import cv2
drawing = False
point = (0,0)
def mouse_drawing(event, x, y, flags, params):
global point, drawing
if event == cv2.EVENT_LBUTTONDOWN:
drawing = True
point= (x, y)
cap = cv2.VideoCapture(0)
cv2.namedWindow("Frame")
cv2.setMouseCallback("Frame", mouse_drawing)
while True:
_, frame = cap.read()
if drawing :
cv2.rectangle(frame,point,(point[0]+80, point[1]+80),(0,0,255),0)
cv2.imshow("Frame", frame)
key = cv2.waitKey(25)
if key== 13:
print('done')
elif key == 27:
break
cap.release()
cv2.destroyAllWindows()
If you want the rectangle to follow your mouse after you clicked and to stop following after you release the button, change in the code I supplied before the mouse_drawing function like this:
def mouse_drawing(event, x, y, flags, params):
global point, drawing
if event == cv2.EVENT_LBUTTONDOWN:
drawing = True
point = (x, y)
elif event == cv2.EVENT_MOUSEMOVE:
if drawing is True:
point = (x, y)
elif event == cv2.EVENT_LBUTTONUP:
drawing = False
point = (x, y)

Dynamically draw circle using mouse in openCV

I have been trying to make an OpenCV-Py program to draw rectangle, line, and circle on mouse click and drag. I could successfully do it for line and rectangle but the code for the circle is wrong and I need help with that.
import numpy as np
import cv2 as cv
import math
drawing = False # true if mouse is pressed
ix,iy = -1,-1
# mouse callback function
def draw_circle(event,x,y,flags,param):
global ix,iy,drawing
if event == cv.EVENT_LBUTTONDOWN:
drawing = True
ix,iy = x,y
elif event == cv.EVENT_MOUSEMOVE:
if drawing == True:
k = cv.waitKey(33)
if k == ord('r'):
cv.rectangle(img,(ix,iy),(x,y),(0,255,0),-1)
elif k==ord('c'):
cv.circle(img,int(((ix+x)/2,(iy+y)/2)),int(math.sqrt( ((ix-x)**2)+((iy-y)**2) )),(0,0,255),-1)
elif k== ord('l'):
cv.line(img,(ix,iy),(x,y),(255,0,0),5)
elif event == cv.EVENT_LBUTTONUP:
drawing = False
img = np.zeros((512,512,3), np.uint8)
cv.namedWindow('image')
cv.setMouseCallback('image',draw_circle)
while(1):
cv.imshow('image',img)
k = cv.waitKey(1) & 0xFF
if k == 27:
break
cv.destroyAllWindows()
ERROR: Traceback (most recent call last):
File "mouse.py", line 19, in draw_circle
cv.circle(img,int(((ix+x)/2,(iy+y)/2)),int(math.sqrt( ((ix-x)**2)+((iy-y)**2) )),(0,0,255),-1)
TypeError: int() argument must be a string, a bytes-like object or a number, not 'tuple'
To dynamically draw a circle with OpenCV,
import numpy as np
import cv2
import math
drawing = False # true if mouse is pressed
ix,iy = -1,-1
# Create a function based on a CV2 Event (Left button click)
def draw_circle(event,x,y,flags,param):
global ix,iy,drawing
if event == cv2.EVENT_LBUTTONDOWN:
drawing = True
# we take note of where that mouse was located
ix,iy = x,y
elif event == cv2.EVENT_MOUSEMOVE:
drawing == True
elif event == cv2.EVENT_LBUTTONUP:
radius = int(math.sqrt( ((ix-x)**2)+((iy-y)**2)))
cv2.circle(img,(ix,iy),radius,(0,0,255), thickness=1)
drawing = False
# Create a black image
img = np.zeros((512,512,3), np.uint8)
# This names the window so we can reference it
cv2.namedWindow('image')
# Connects the mouse button to our callback function
cv2.setMouseCallback('image',draw_circle)
while(1):
cv2.imshow('image',img)
# EXPLANATION FOR THIS LINE OF CODE:
# https://stackoverflow.com/questions/35372700/whats-0xff-for-in-cv2-waitkey1/39201163
k = cv2.waitKey(1) & 0xFF
if k == 27:
break
# Once script is done, its usually good practice to call this line
# It closes all windows (just in case you have multiple windows called)
cv2.destroyAllWindows()
This is how to draw the circle dynamically.
As you drag the mouse you can see the size of the circle dynamically change.
import math
import numpy as np
import cv2 as cv
cv.namedWindow('image', cv.WND_PROP_ASPECT_RATIO)
drawing = False # true if mouse is pressed
# Coordinate
x1, y1, x2, y2 = -1, -1, -1, -1
def run():
img = cv.imread(f'image/python.png')
cv.imshow('image', img)
# Create a layer to draw circle. The layer has the same dimension of image
layer = np.zeros((img.shape[0], img.shape[1], 3), dtype="uint8")
# mouse callback function
def draw_circle(event, x, y, flags, param):
global x1, y1, x2, y2, drawing
# Manage different button state
if event == cv.EVENT_LBUTTONDOWN:
drawing = True
x1, y1 = x, y
elif event == cv.EVENT_MOUSEMOVE:
if drawing == True:
# Fill all value to 0 to clean layer
layer.fill(0)
cv.circle(layer, (x1, y1),calc_radius(x1, y1, x, y), (255, 0, 0), 1)
# Create a mask of shape
img2gray = cv.cvtColor(layer, cv.COLOR_BGR2GRAY)
ret, mask = cv.threshold(img2gray, 0, 255, cv.THRESH_BINARY)
# Create a copy of original image
_img = img.copy()
# Set the value of mask to 0, to avoid color overlap problems
_img[np.where(mask)] = 0
cv.imshow('image', np.where(layer == 0, _img, layer))
elif event == cv.EVENT_LBUTTONUP:
drawing = False
layer.fill(0)
cv.circle(layer, (x1, y1), calc_radius(x1, y1, x, y), (255, 0, 0), 1)
# Create a mask of shape
img2gray = cv.cvtColor(layer, cv.COLOR_BGR2GRAY)
ret, mask = cv.threshold(img2gray, 0, 255, cv.THRESH_BINARY)
_img = img.copy()
# Set the value of mask to 0, to avoid color overlap problems
_img[np.where(mask)] = 0
# Merge two array using Numpy where function
cv.imshow('image', np.where(layer == 0, _img, layer))
# Assig callback
cv.setMouseCallback('image', draw_circle)
# Service function to calculate radius (Pythagorean theorem)
def calc_radius(x1, y1, x2, y2):
delta_x = abs(x2 - x1)
delta_y = abs(y2 - y1)
return int(math.sqrt((delta_x**2)+(delta_y**2)))
while True:
k = cv.waitKey(1)
if k == ord("c"): # c to terminate a program
cv.destroyAllWindows()
break
if __name__ == '__main__':
run()

Categories