So , basically I want to design an app that record the screen not by capturing the screen as below
import datetime
from PIL import ImageGrab
import numpy as np
import cv2
time_stamp = datetime.datetime.now().strftime('%Y-%m-%d %H-%M-%S')
file_name = f'{time_stamp}.mp4'
fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')
captured_video = cv2.VideoWriter(file_name, fourcc, 20.0, (630, 330))
while True:
img = ImageGrab.grab(bbox=(0, 0, 630, 330))
img_np = np.array(img)
img_final = cv2.cvtColor(img_np, cv2.COLOR_BGR2RGB)
cv2.imshow("Screen Recorder", img_final)
captured_video.write(img_final)
if cv2.waitKey(10) == ord('q'):
break
It give the screen capturing but I need to record a specific process
Like
I want to record the screen output of
process 31328
Nothing else. Means while recording the screen the pop ups or any mini windows or any floating window opened during the recording would not capture in our screen recorder.
I am thinking that the Linux will throw the output on screen like
We print ('hello'). We should grab that output before it reaches on screen and record it. Is it possible?
Related
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)
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.
When I try to capture a video screenshot of my screen in a region suddenly the .avi output file becomes a 7kb.
The is no error, so I do not know how to fix this
The output video is fine before selecting the region.
how can i fix this problem?
import cv2
import numpy as np
import pyautogui
# display screen resolution, get it from your OS settings
import tkinter as tk
from PIL.Image import Image
root = tk.Tk()
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
SCREEN_SIZE = (screen_width, screen_height)
fourcc = cv2.VideoWriter_fourcc(*"XVID")
# create the video write object
out = cv2.VideoWriter("output.avi", fourcc, 20.0, (SCREEN_SIZE))
while True:
# make a screenshot
img = pyautogui.screenshot(region=(350, 800, 500, 150))
# convert these pixels to a proper numpy array to work with OpenCV
frame = np.array(img)
# convert colors from BGR to RGB
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# write the frame
out.write(frame)
# show the frame
cv2.imshow("screenshot", frame)
# if the user clicks q, it exits
if cv2.waitKey(1) == ord("q"):
break
# make sure everything is closed when exited
cv2.destroyAllWindows()
out.release()
I am making a screen recorder that records the screen of the desktop. However, when I record the screen, the mouse pointer (cursor) is not visible in the recording.
Is there any way I can show the mouse pointer in my recording?
This is my current code:
import cv2
import numpy as np
import pyautogui
import datetime
date = datetime.datetime.now()
SCREEN_SIZE = (1366, 768)
framerate = 12
fourcc = cv2.VideoWriter_fourcc(*'XVID')
filename = 'E:/project/videos/rec_%s%s%s%s%s%s.avi' % (date.year, date.month, date.day, date.hour, date.minute, date.second)
out = cv2.VideoWriter(filename, fourcc,framerate, 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 cv2.waitKey(1) == ord("q"):
break
cv2.destroyAllWindows()
out.release()
I don't think it's possible with that approach - but am always happy to be corrected and learn something new. I know of a couple of workarounds.
The first is to continue to use pyautogui and to call its mouseposition() function and paste/draw your own synthetic mouse pointer onto the grab. I did that with OpenCV's fillPoly() function:
#!/usr/bin/env python3
import cv2
import numpy as np
import pyautogui
import datetime
# X and Y coordinates of mouse pointer
Xs = [0,8,6,14,12,4,2,0]
Ys = [0,2,4,12,14,6,8,0]
while True:
img = pyautogui.screenshot()
mouseX,mouseY = pyautogui.position()
mouseX *= 2
mouseY *= 2
frame = np.array(img)
frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
# Synthesize mouse pointer
Xthis = [4*x+mouseX for x in Xs]
Ythis = [4*y+mouseY for y in Ys]
points = list(zip(Xthis,Ythis))
points = np.array(points, 'int32')
cv2.fillPoly(frame,[points],color=[255,255,255])
# Make it a bit smaller for display
frame = cv2.resize(frame,(960,540))
cv2.imshow('Title', frame)
if cv2.waitKey(1) == ord("q"):
break
cv2.destroyAllWindows()
out.release()
The second is to use ffmpeg which can capture the mouse - you can either run ffmpeg in place of your current app, or pipe the output from ffmpeg into your app through a pipe and continue to process it as you are now. That might look like this:
#!/usr/bin/env python3
# ffmpeg -y -pix_fmt bgr0 -f avfoundation -r 20 -t 10 -i 1 -vf scale=w=3840:h=2160 -f rawvideo /dev/null
import sys
import cv2
import time
import subprocess
import numpy as np
w,h = 3840, 2160
def ffmpegGrab():
"""Generator to read frames from ffmpeg subprocess"""
cmd = [
'ffmpeg',
'-pix_fmt', 'bgr0',
'-f', 'avfoundation',
'-capture_cursor', '1',
'-capture_mouse_clicks', '1',
'-r', '20',
'-i', '1',
'-vf','scale=w=3840:h=2160',
'-f', 'rawvideo',
'pipe:1'
]
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
while True:
frame = proc.stdout.read(w*h*4)
yield np.frombuffer(frame, dtype=np.uint8).reshape((h,w,4))
# Get frame generator
gen = ffmpegGrab()
# Get start time
start = time.time()
# Read video frames from ffmpeg in loop
nFrames = 0
while True:
# Read next frame from ffmpeg
frame = next(gen)
nFrames += 1
frame = cv2.resize(frame,(960,540))
cv2.imshow('screenshot', frame)
if cv2.waitKey(1) == ord("q"):
break
fps = nFrames/(time.time()-start)
print(f'FPS: {fps}')
cv2.destroyAllWindows()
out.release()
Note that pyautogui takes around 600ms to capture one frame on my Mac, whereas the ffmpeg above achieves around 20fps, or 50ms per frame.
Keywords: Python. image processing, ffmpeg, pyautogui, screen-grab, screen-capture, screengrab, screencapture, fps. speed, prime.
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