I am trying to make a screen recorder using python opencv along with the mss library.
I can not get it to record a video. Whenever I stop the application - the file size becomes static such as sizes as for example 6kB - depending on the codec I used.
I have read that the capture must be the same size as the screen resolution which it is - but it still does not record.
I have also tried to use various codecs such as *'MP4V' but whatever I try - it does not save a proper recording.
I am using a MAC with a m1 processor if that matters.
import numpy as np
import cv2
import glob
from moviepy.editor import VideoFileClip
from mss import mss
from PIL import Image
import time
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('outpute.avi', fourcc, 60, (2560,1600))
with mss() as sct:
# Part of the screen to capture
monitor = {"top": 0, "left": 0, "width": 2560, "height": 1600}
while "Screen capturing":
last_time = time.time()
# Get raw pixels from the screen, save it to a Numpy array
img = np.array(sct.grab(monitor))
# Display the picture
cv2.imshow("OpenCV/Numpy normal", img)
# Write the image
out.write(img)
print("fps: {}".format(1 / (time.time() - last_time)))
# Press "q" to quit
if cv2.waitKey(25) & 0xFF == ord("q"):
cv2.destroyAllWindows()
break
this tutorial is working, good luck!
After debugging I noticed that monitor values has to be divided by 2 in order to work. No idea why this is the case - but I debugged it and saw that this was the case.
I also realized that I had to convert from BGR to RGB before I am writing it to a video file. Otherwise it won't work.
I also changed the format, but it was not part of the problem I do not believe.
Here is the working code
import numpy as np
import cv2
import glob
from moviepy.editor import VideoFileClip
from mss import mss
from PIL import Image
import time
import pyautogui
SCREEN_SIZE = tuple((2880,1800))
fourcc = cv2.VideoWriter_fourcc(*'MP4V')
out = cv2.VideoWriter('output.mp4', fourcc, 60, (SCREEN_SIZE))
with mss() as sct:
# Part of the screen to capture
monitor = {"top": 0, "left": 0, "width": 1440, "height": 900}
while True:
last_time = time.time()
img = np.array(sct.grab(monitor))
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
out.write(img)
print("fps: {}".format(1 / (time.time() - last_time)))
if cv2.waitKey(2) & 0xFF == ord("q"):
cv2.destroyAllWindows()
break
(Ignore the extra libraries I added)
Related
I am trying to screenshot using mss library add display it using below code but getting same error every time.
Is there a fix for this error
TypeError: Expected Ptr<cv::UMat> for argument 'mat'
** I am using this in Macos not windows
import cv2 as cv
import numpy as np
import os
from time import time
from mss import mss
os.chdir(os.path.dirname(os.path.abspath(__file__)))
loop_time = time()
with mss() as sct:
while (True):
monitor_1 = sct.monitors[1] # Identify the display to capture
screenshot = sct.grab(monitor_1)
cv.imshow('result', screenshot)
print('FPS {}',format(1 / (time() - loop_time)))
loop_time = time()
if cv.waitKey(1) == ord('q'):
cv.destroyAllWindows()
break
print('done')
You have to convert "screenshot" to cv::UMat :
import time
import cv2
import mss
import numpy
with mss.mss() as sct:
# Part of the screen to capture
monitor = {"top": 40, "left": 0, "width": 800, "height": 640}
while "Screen capturing":
last_time = time.time()
# Get raw pixels from the screen, save it to a Numpy array
img = numpy.array(sct.grab(monitor))
# Display the picture
cv2.imshow("OpenCV/Numpy normal", img)
# Display the picture in grayscale
# cv2.imshow('OpenCV/Numpy grayscale',
# cv2.cvtColor(img, cv2.COLOR_BGRA2GRAY))
print("fps: {}".format(1 / (time.time() - last_time)))
# Press "q" to quit
if cv2.waitKey(25) & 0xFF == ord("q"):
cv2.destroyAllWindows()
break
This is example from here
I have written a code to record the screen recorder using python but when i see the output then i found that its fps is very low .Is there any better code than mine to increase the fps of the screen recorder.
If yes then please reply.
Here is mine code:-
import cv2
import numpy as np
import pyautogui
import datetime
# display screen resolution, get it from your OS settings
SCREEN_SIZE = (1366, 768)
# define the codec
fourcc = cv2.VideoWriter_fourcc(*"XVID")
# create the video write object
now = datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
out = cv2.VideoWriter("screen recorder"+now+".avi", fourcc, 5.0, (SCREEN_SIZE))
while True:
img = pyautogui.screenshot()
frame = np.array(img)
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
out.write(frame)
cv2.imshow("screenshot", frame)
# if the user clicks q, it exits
if cv2.waitKey(1) == ord("q"):
break
cv2.destroyAllWindows()
out.release()
img = pyautogui.screenshot(region=(0, 0, 300, 400))
The third parameter to the cv2.VideoWriter constructor is the frame rate (https://docs.opencv.org/3.4/dd/d9e/classcv_1_1VideoWriter.html#ac3478f6257454209fa99249cc03a5c59). Currently, you have it set to 5.0. For example, for 30 fps, instantiate the VideoWriter with:
out = cv2.VideoWriter("screen recorder"+now+".avi", fourcc, 30.0, (SCREEN_SIZE))
EDIT: In order to also read in images at the correct framerate, we can pause the while loop using the waitKey function. We can re-write the OP's code like so:
import cv2
import numpy as np
import pyautogui
import datetime
import time
# display screen resolution, get it from your OS settings
SCREEN_SIZE = (1366, 768)
FRAME_RATE = 30.0 # desired frame-rate
# define the codec
fourcc = cv2.VideoWriter_fourcc(*"XVID")
# create the video write object
now = datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
out = cv2.VideoWriter("screen recorder"+now+".avi", fourcc, FRAME_RATE, (SCREEN_SIZE))
while True:
st = time.time() # collect start time
img = pyautogui.screenshot()
frame = np.array(img)
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
out.write(frame)
cv2.imshow("screenshot", frame)
en = time.time() # collect end time
# calculate time to wait before next frame:
delay = max(0, (1 / FRAME_RATE - (en - st)) * 1000)
# if the user clicks q, it exits
if cv2.waitKey(delay) == ord("q"):
break
cv2.destroyAllWindows()
out.release()
img = pyautogui.screenshot(region=(0, 0, 300, 400))
Note: If collecting the frames is too slow (requires more than 1 / FRAMERATE seconds), then you may want to reduce the frame rate or the resolution.
It takes a stream generated by an RTSP protocol and process it using a machine learning algorithm but it doesn't work well the algorithm is slow on processing frames so am trying to save the stream into a small videos but I get a very small frame rate 1FPS and when I try to save 1 min it give me only 15 s am using an IP camera hikvision here is the code am using.
import time
import cv2
import numpy as np
import cv2
import imutils
from imutils.object_detection import non_max_suppression
import datetime
import numpy as np
import cv2 as cv
capture_duration = 60
for i in range(1,4):
cap = cv2.VideoCapture("rtsp://admin:admin123#192.168.1.2:554/cam/realmonitor?channel=1&subtype=0")
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH) )
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT) )
size = (width, height)
fourcc = cv2.VideoWriter_fourcc(*'XVID')
name=( str(i)+'.mp4')
out = cv2.VideoWriter(name, fourcc, 10.0, size)
start_time = time.time()
while(int(time.time() - start_time) < capture_duration):
_, frame = cap.read()
#cv2.imshow('Recording...', frame)
out.write(frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
out.release()
cv2.destroyAllWindows()
I am trying to capture the screen and show the images continuously using opencv-python. But for some reason the images are not stacking on top of each others like normally. Please look at the source code and the screenshot below. I am on ubuntu 18.04. Thanks!!
import time
import cv2
import mss
import numpy as np
with mss.mss() as sct:
# Part of the screen to capture
monitor = {"top": 40, "left": 0, "width": 800, "height": 640}
while True:
last_time = time.time()
# Get raw pixels from the screen, save it to a Numpy array
img = np.array(sct.grab(monitor))
# Display the picture
cv2.imshow('frame', img)
print("fps: {}".format(1 / (time.time() - last_time)))
# Press "q" to quit
if cv2.waitKey(1) & 0xFF == ord("q"):
cv2.destroyAllWindows()
break
How do I use python, mss, and opencv to capture my computer screen and save it as an array of images to form a movie? I am converting to gray-scale so it can be a 3 dimensional array. I would like to store each 2d screen shot in a 3d array for viewing and processing. I am having a hard time constructing an array that saves the sequence of screen shots as well as plays back the sequence of screen shots in cv2.
Thanks a lot
import time
import numpy as np
import cv2
import mss
from PIL import Image
with mss.mss() as sct:
fps_list=[]
matrix_list = []
monitor = {'top':40, 'left':0, 'width':800, 'height':640}
timer = 0
while timer <100:
last_time = time.time()
#get raw pizels from screen and save to numpy array
img = np.array(sct.grab(monitor))
img=cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#Save img data as matrix
matrix_list[timer,:,:] = img
#Display Image
cv2.imshow('Normal', img)
fps = 1/ (time.time()-last_time)
fps_list.append(fps)
#press q to quit
timer += 1
if cv2.waitKey(25) & 0xFF == ord('q'):
cv2.destroyAllWindows()
break
#calculate fps
fps_list = np.asarray(fps_list)
print(np.average(fps_list))
#playback image movie from screencapture
t=0
while t < 100:
cv.imshow('Playback',img_matrix[t])
t += 1
A clue perhaps, save screenshots into a list and replay them later (you will have to adapt the sleep time):
import time
import cv2
import mss
import numpy
with mss.mss() as sct:
monitor = {'top': 40, 'left': 0, 'width': 800, 'height': 640}
img_matrix = []
for _ in range(100):
# Get raw pizels from screen and save to numpy array
img = numpy.array(sct.grab(monitor))
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Save img data as matrix
img_matrix.append(img)
# Display Image
cv2.imshow('Normal', img)
# Press q to quit
if cv2.waitKey(25) & 0xFF == ord('q'):
cv2.destroyAllWindows()
break
# Playback image movie from screencapture
for img in img_matrix:
cv2.imshow('Playback', img)
# Press q to quit
if cv2.waitKey(25) & 0xFF == ord('q'):
cv2.destroyAllWindows()
break
use collections.OrderedDict() to saves the sequence
import collections
....
fps_list= collections.OrderedDict()
...
fps_list[timer] = fps