Opencv rotate camera mode - python

I want to rotate the camera view by 90 degree clockwise with an interrupt button. But the button's state goes back to it's default state when I click once and unpress the button. As a result, on clicking the button, the camera rotates for an instance and then goes back to the default mode in the while loop. How to solve this issue?
Here is my snippet:
import cv2
cap = cv2. VideoCapture(0)
while True:
ret, frame = cap.read()
cv2.imshow('null', frame)
if (button):
frame = cv2.rotate(frame, cv2.ROTATE_90_CLOCKWISE)
cv2.imshow('null', frame)
if cv2.waitKey(5) & 0xFF == 27:
break
cap.release()
Any help would be appreciated.

You should use extra variable - rotate = False - to keep this state
rotate = False
while True:
ret, frame = cap.read()
# without imshow()
if button_a.is_pressed():
rotate = True
if rotate:
frame = cv2.rotate(frame, cv2.ROTATE_90_CLOCKWISE)
# outside `if`
cv2.imshow('null', frame)
This way it changes rotate from False to True but never from True to False
EDIT:
If next press should rotate another 90 degrees (to 180) then it would need more complex code. It would check if is_pressed() in previous loop was False and in current loop is True - to run it only once when button is pressed long time.
Something like this.
I used normal space to test it.
import cv2
cap = cv2.VideoCapture(0)
rotate = 0
is_pressed = False
previous = False
current = False
while True:
ret, frame = cap.read()
# without imshow()
current = is_pressed
if (previous is False) and (current is True):
rotate = (rotate + 90) % 360
print(rotate)
previous = current
if rotate == 90:
frame = cv2.rotate(frame, cv2.ROTATE_90_CLOCKWISE)
elif rotate == 180:
frame = cv2.rotate(frame, cv2.ROTATE_180)
elif rotate == 270:
frame = cv2.rotate(frame, cv2.ROTATE_90_COUNTERCLOCKWISE)
# outside `if`
cv2.imshow('null', frame)
key = cv2.waitKey(40) & 0xff
if key == 27:
break
is_pressed = (key == 32)
cv2.destroyAllWindows()
cap.release()

import cv2
cap = cv2. VideoCapture(0)
button_is_pressed = false;
while True:
ret, frame = cap.read()
if (button):
button_is_pressed = not button_is_pressed
if(button_is_pressed)
frame = cv2.rotate(frame, cv2.ROTATE_90_CLOCKWISE)
cv2.imshow('null', frame)
cap.release()
I would try something like this, when you press the button it changes the state of variable button_is_pressed, while still unchanged it keeps rotating image.

Related

Why does the cropped video not get saved?

Here, I have a code that takes a video as input and let the user draw a ROI. Later the cropped video will be displayed. This code was originally taken from I would like to define a Region of Interest in a video and only process that area.
I have provided the code below.
Question: I would like to save the cropped video in .mp4 format. The video output shows only a 1kb file. Can you go through the code and suggest a solution?
NB: I went through answer provided at OpenCV video not getting saved. Still I have failed to figure out the error.
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
#here, it is the copy of the first frame.
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))
print(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(r'E:\cardiovascular\brad1low.mp4')
#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]]
print(f'first frame roi is {first_frame_roi}')
#An empty image of full size just for visualization of difference
difference_image_canvas = np.zeros_like(first_frame)
out = cv2.VideoWriter(r'E:\cardiovascular\filename2.mp4', cv2.VideoWriter_fourcc(*'MP4V'), int(cap.get(cv2.CAP_PROP_FRAME_COUNT)), (int(first_frame_roi.shape[0]), (int(first_frame_roi.shape[1]))))
while cap.isOpened():
ret, frame = cap.read()
if ret:
#ROI of current frame
roi = frame[point1[1]:point2[1], point1[0]:point2[0]]
print(f'roi is {roi}')
cv2.imshow(DIFFERENCE_WINDOW_TITLE, roi)
out.write(roi)
key = cv2.waitKey(30) & 0xff
if key == 27:
break
else:
break
cap.release()
out.release()
cv2.destroyAllWindows()

How to correctly display OpenCv Portrait mode in Full screen?

I am trying to corectly show Landscape and Portrait mode with OpenCv in Python.
I am using a small 2.8" TFT screen with a resolution of 240 x 320 attached to a micro computer that is running Debian buster.
The webcam I am using has the following supported resolutions:
640x480 352x288 320x240 176x144 160x120
With the cv2.WND_PROP_FULLSCREEN the screen starts with grey edges at top and bottom.
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
cv2.namedWindow('default', cv2.WND_PROP_FULLSCREEN)
cv2.setWindowProperty('default', cv2.WND_PROP_FULLSCREEN,
cv2.WINDOW_FULLSCREEN)
while True:
ret, frame = cap.read()
if viewMode == "normal":
cv2.imshow("default", frame)
Then I rotate it with cv2.ROTATE_90_CLOCKWISE to get the Landscape mode.
elif viewMode == "landscape":
frame = cv2.rotate(frame, cv2.ROTATE_90_CLOCKWISE)
cv2.imshow("default", frame)
It works fine with proper scaling without stretching in both X and Y axes.
To get the Portrait mode in full screen, I use cv2.WINDOW_FREERATIO. But it streches in Y axis and the display is not good.
elif viewMode == "portrait":
cv2.namedWindow('freeratio', cv2.WINDOW_FREERATIO)
cv2.setWindowProperty(
'freeratio', cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)
cv2.imshow("freeratio", frame)
What is the correct way to show Portrait mode in this case without streching and maintaining proper scaling in both axes?
Here's my full code below:
import cv2
# viewMode = "normal"
# viewMode = "landscape"
viewMode = "portrait"
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
cv2.namedWindow('default', cv2.WND_PROP_FULLSCREEN)
cv2.setWindowProperty('default', cv2.WND_PROP_FULLSCREEN,
cv2.WINDOW_FULLSCREEN)
while True:
ret, frame = cap.read()
if viewMode == "normal":
cv2.imshow("default", frame)
elif viewMode == "landscape":
frame = cv2.rotate(frame, cv2.ROTATE_90_CLOCKWISE)
cv2.imshow("default", frame)
elif viewMode == "portrait":
cv2.namedWindow('freeratio', cv2.WINDOW_FREERATIO)
cv2.setWindowProperty(
'freeratio', cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)
cv2.imshow("freeratio", frame)
if cv2.waitKey(5) & 0xFF == 27:
break
cap.release()
Note: I have tried most suggestions I found on other similar posts/threads but to no avail. Resizing/cropping or manually setting the resolution does not help. It either gives me the greyed borders on topand bottom or streched out. Could it be any setting in the webcam/Debian that's causing the issue?
Any help/suggestions is appreciated.

How to capture video and save from webcam on click or pressing any key from keyboard using OpenCV

I want to capture and save a video from my webcam in a way that when I press any key (enter, space etc) from keyboard then code should start save the video from current frame and when I press same key from keyboard then code should stop to save the video. This is my code currently:
import cv2
cap = cv2.VideoCapture(0)
if (cap.isOpened() == False):
print("Unable to read camera feed")
frame_width = int(cap.get(3))
frame_height = int(cap.get(4))
out = cv2.VideoWriter('output.avi',cv2.VideoWriter_fourcc('M','J','P','G'), 10, (frame_width,frame_height))
while(True):
ret, frame = cap.read()
k = cv2.waitKey(1)
if ret == True:
cv2.imshow('frame',frame)
# press space key to start recording
if k%256 == 32:
out.write(frame)
# press q key to close the program
elif k & 0xFF == ord('q'):
break
else:
break
cap.release()
out.release()
cv2.destroyAllWindows()
My current code is capturing only one (current frame) when I press space key. I need help to solve this problem.
Here is the same question but it is for images, it can't solve for videos.
Also is there a better way to capture and save video which can solve my problem?
The problem is that the code you wrote only calls the function out.write(frame) when you press the space key.
This should solve the issue:
create some sentinel variable at the beginning of your code. let's say record = False
And then inside your loop, make this change:
if k%256 == 32:
record = True
if record:
out.write(frame)
So this is how your code will look like:
import cv2
record = False
cap = cv2.VideoCapture(0)
if (cap.isOpened() == False):
print("Unable to read camera feed")
frame_width = int(cap.get(3))
frame_height = int(cap.get(4))
out = cv2.VideoWriter('output.avi',cv2.VideoWriter_fourcc('M','J','P','G'), 10, (frame_width,frame_height))
while(True):
ret, frame = cap.read()
k = cv2.waitKey(1)
if ret == True:
cv2.imshow('frame',frame)
# press space key to start recording
if k%256 == 32:
record = True
if record:
out.write(frame)
# press q key to close the program
if k & 0xFF == ord('q'):
break
else:
break
cap.release()
out.release()
cv2.destroyAllWindows()

Opencv python crashes after certain time

In my code after certain time (depend of the PC or OS) crashes. The error displayed is
libpng warning: Image width is zero in IHDR
libpng warning: Image height is zero in IHDR
libpng error: Invalid IHDR data
My code draw ROI on a video from webcam and take a snapshot. The ROI is deleted after 5-10 minutes (I'm not sure why, this is the error) and the picture saved not have dimensions then the error above is displayed but I'm not find the error. The instructions are, press "c" to stop the video and draw a ROI, press again "c" to take the picture, press "r" to resume the video, and repeat if you need another pictures.
I tested the code in Windows 10 and raspbian on a raspberry and the time is not the same but on both the program crashes. This is my code:
import cv2
# python PSI_Camera_test.py
class staticROI(object):
def __init__(self):
self.capture = cv2.VideoCapture(0)
self.capture.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
self.capture.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)
# Bounding box reference points and boolean if we are extracting coordinates
self.image_coordinates = []
self.extract = False
self.selected_ROI = False
self.img_counter = 0
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()
img_name = "Images\opencv_frame_{}.png".format(
self.img_counter)
cv2.imwrite(img_name, self.cropped_image)
print("{} written!".format(img_name))
self.img_counter += 1
# Resume video
if key == ord('r'):
break
# Close program with keyboard 'esp'
if key % 256 == 27:
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')
# python PSI_Camera_test.py
if __name__ == '__main__':
static_ROI = staticROI()
Thanks in advance!

How can I zoom my webcam in Open CV Python?

I want my webcam to be zoomed in open cv python and I don't know how. Can anyone help me with my problem?
import cv2
video = cv2.VideoCapture(0)
while True:
check, frame = video.read()
cv2.imshow('Video', frame)
key = cv2.waitKey(1)
if key == 27:
break
video.release()
cv2.destroyAllWindows
You can use this solution. It makes the job -> croping + zoom + array up and array down.
import cv2
def show_webcam(mirror=False):
scale=10
cam = cv2.VideoCapture(0)
while True:
ret_val, image = cam.read()
if mirror:
image = cv2.flip(image, 1)
#get the webcam size
height, width, channels = image.shape
#prepare the crop
centerX,centerY=int(height/2),int(width/2)
radiusX,radiusY= int(scale*height/100),int(scale*width/100)
minX,maxX=centerX-radiusX,centerX+radiusX
minY,maxY=centerY-radiusY,centerY+radiusY
cropped = image[minX:maxX, minY:maxY]
resized_cropped = cv2.resize(cropped, (width, height))
cv2.imshow('my webcam', resized_cropped)
if cv2.waitKey(1) == 27:
break # esc to quit
#add + or - 5 % to zoom
if cv2.waitKey(1) == 0:
scale += 5 # +5
if cv2.waitKey(1) == 1:
scale = 5 # +5
cv2.destroyAllWindows()
def main():
show_webcam(mirror=True)
if __name__ == '__main__':
main()
Zooming is simply increasing image size . Just increase image size by converting frame to image using PIL and then resize function.
Sample code
import tkinter
import cv2
from PIL import Image,ImageTk
root = tkinter.Tk()
root.geometry("1000x500+200+0")
w = 1000
h = 630
capture = tkinter.Canvas(root, bd=2, bg="blue", height=h, width=w)
capture.grid(column = 0, row = 0)
video = None
frame = None
img=None
show=None
begin = False
def start_capture(event):
global begin,frame,img,root,show,capture,video
video = cv2.VideoCapture(0)
begin = True
while begin:
check, frame = video.read()
img = Image.fromarray(frame)
w,h = img.size
img = img.resize((w*2,h*2))
show = ImageTk.PhotoImage(img)
capture.create_image(0,0,anchor=tkinter.NW,image=show)
root.update()
def stop_capture(event):
global video,begin
begin = False
video.release()
start = tkinter.Button(root, text='Start')
start.grid(column = 0, row = 2)
start.bind('<Button-1>', start_capture)
stop = tkinter.Button(root, text='Stop')
stop.grid(column = 1, row = 2)
stop.bind('<Button-1>', stop_capture)
root.mainloop()
I am not sure if this is useful now to add this point. (Hope this helps for all the noobs in opencv at least)
I suffered a lot at this: cropped = image[minX:maxX, minY:maxY] Crop was somehow out of the interested area.
After researching a lot, I found out that the problem was with the syntax.
Actually it should have been : cropped = image[minY:maxY , minX:maxX]
because openCV crop syntax should be like this?..
Anyways, thanks to Amara BOUDIB & JDS for the sample codes!

Categories