如何只记录屏幕的特定选定区域



我有一个Python程序来拍摄桌面屏幕的选定区域。

该程序通过光标获取所选区域的坐标。

然后裁剪图像并显示图像。

但现在我正在制作一个屏幕记录器,我想使用所选区域的坐标来记录特定的屏幕区域。

这是我的区域选择代码;

import tkinter as tk
from tkinter import *
from tkinter import ttk ,FLAT
from PIL import Image, ImageTk, ImageGrab, ImageEnhance
import cv2
import numpy as np
import threading
VIDEO_SIZE = (800,420)
f = ImageGrab.grab()  
a, b = f.size
filename="test.avi"
fourcc = cv2.VideoWriter_fourcc(*'H264')
frame_rate = 10
out = cv2.VideoWriter(filename, fourcc, frame_rate,(a, b))
root = tk.Tk()
root.resizable(0, 0)
root.title('Screen Recorder')
root.geometry('+260+70')
x1 = y1 = x2 = y2 = 0
def show_image(image):
win = tk.Toplevel()
win.image = ImageTk.PhotoImage(image)
tk.Label(win, image=win.image).pack()
win.grab_set()
win.wait_window(win)
def area_sel():
x1 = y1 = x2 = y2 = 0
roi_image = None
def on_mouse_down(event):
nonlocal x1, y1
x1, y1 = event.x, event.y
canvas.create_rectangle(x1, y1, x1, y1, outline='red', tag='roi')
def on_mouse_move(event):
nonlocal roi_image, x2, y2
x2, y2 = event.x, event.y
canvas.delete('roi-image') 
roi_image = image.crop((x1, y1, x2, y2)) 
canvas.image = ImageTk.PhotoImage(roi_image)
canvas.create_image(x1, y1, image=canvas.image, tag=('roi-image'), anchor='nw')
canvas.coords('roi', x1, y1, x2, y2)
canvas.lift('roi') 
root.withdraw()  
image = ImageGrab.grab()  
bgimage = ImageEnhance.Brightness(image).enhance(0.3)  
win = tk.Toplevel()
win.attributes('-fullscreen', 1)
win.attributes('-topmost', 1)
canvas = tk.Canvas(win, highlightthickness=0)
canvas.pack(fill='both', expand=1)
tkimage = ImageTk.PhotoImage(bgimage)
canvas.create_image(0, 0, image=tkimage, anchor='nw', tag='images')
win.bind('<ButtonPress-1>', on_mouse_down)
win.bind('<B1-Motion>', on_mouse_move)
win.bind('<ButtonRelease-1>', lambda e: win.destroy())
win.focus_force()
win.grab_set()
win.wait_window(win)
root.deiconify()  

if roi_image:
start_recording() #calling main function to record screen

def recording_screen():
global recording
recording = True
while recording:
img = ImageGrab.grab(bbox=(x1, y1, x2, y2))
frame = np.array(img)
sc = np.array(img)
sc = cv2.resize(sc, VIDEO_SIZE)
tkimage.paste(Image.fromarray(sc))
frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
out.write(frame)
def start_recording():
if not out.isOpened():
out.open(filename, fourcc, frame_rate,(a, b))
threading.Thread(target=recording_screen, daemon=True).start()
def stop_recording():
global recording
recording = False
out.release()

tkimage = ImageTk.PhotoImage(Image.new('RGB', VIDEO_SIZE, (0,0,0)))
w, h = VIDEO_SIZE
vbox = tk.Label(root, image=tkimage, width=w, height=h, bg='black')
vbox.pack(pady=10,padx=25)
frame = tk.Frame(root)
frame.pack()
sel_area = ttk.Button(frame, text='select area to Record', width=30, command=area_sel)
sel_area.grid(row=0, column=0)
stp_rec = ttk.Button(frame, text='Stop Recording', width=30, command=stop_recording)
stp_rec.grid(row=0, column=1)
root.mainloop()

显示错误

sc = cv2.resize (sc, VIDEO_SIZE)
TypeError: Expected Ptr<cv:: UMat> for argument '%s'

编辑:自我回答后,该问题已被编辑。

您对VideoWriter.open()的调用缺少参数。

OpenCV文档为指定了以下参数

retval = cv.VideoWriter.open(filename, fourcc, fps, frameSize[, isColor] )

如果您的out.isOpened()返回False。这意味着您的VideoWriter初始化失败,您需要指定参数。

out.open(filename, fourcc, frame_rate,(a, b))

您更新的代码有几个问题:

1( 输出视频的帧大小CCD_ 5与捕获图像大小VIDEO_SIZE不匹配

f = ImageGrab.grab()
a, b = f.size
...
out = cv2.VideoWriter(filename, fourcc, frame_rate, (a,b))

只需删除f = ImageGrab.grab()a, b = f.size,并在`out=cv2中使用VIDEO_SIZE。VideoWriter(…,VIDEO_SIZE(:

out = cv2.VideoWriter(filename, fourcc, frame_rate, VIDEO_SIZE)

2( 在全局空间中添加了x1 = y1 = x2 = y2 = 0,但不更新它们。因此,在捕获过程中,会捕获零大小的图像并调整其大小,这会导致问题中提到的错误。删除全局声明行,并将x1, y1, x2, y2传递给start_recording()recording_screen()函数。

以下是修改后的代码:

import tkinter as tk
from tkinter import *
from tkinter import ttk ,FLAT
from PIL import Image, ImageTk, ImageGrab, ImageEnhance
import cv2
import numpy as np
import threading
VIDEO_SIZE = (800,420)
#f = ImageGrab.grab() ### not necessary
#a, b = f.size        ### not necessary
filename="test.avi"
fourcc = cv2.VideoWriter_fourcc(*'H264')
frame_rate = 10
out = cv2.VideoWriter(filename, fourcc, frame_rate, VIDEO_SIZE) # use VIDEO_SIZE
root = tk.Tk()
root.resizable(0, 0)
root.title('Screen Recorder')
root.geometry('+260+70')
#x1 = y1 = x2 = y2 = 0  # not necessary
def show_image(image):
win = tk.Toplevel()
win.image = ImageTk.PhotoImage(image)
tk.Label(win, image=win.image).pack()
win.grab_set()
win.wait_window(win)
def area_sel():
x1 = y1 = x2 = y2 = 0
roi_image = None
def on_mouse_down(event):
nonlocal x1, y1
x1, y1 = event.x, event.y
canvas.create_rectangle(x1, y1, x1, y1, outline='red', tag='roi')
def on_mouse_move(event):
nonlocal roi_image, x2, y2
x2, y2 = event.x, event.y
canvas.delete('roi-image') 
roi_image = image.crop((x1, y1, x2, y2)) 
canvas.image = ImageTk.PhotoImage(roi_image)
canvas.create_image(x1, y1, image=canvas.image, tag=('roi-image'), anchor='nw')
canvas.coords('roi', x1, y1, x2, y2)
canvas.lift('roi') 
root.withdraw()  
image = ImageGrab.grab()  
bgimage = ImageEnhance.Brightness(image).enhance(0.3)  
win = tk.Toplevel()
win.attributes('-fullscreen', 1)
win.attributes('-topmost', 1)
canvas = tk.Canvas(win, highlightthickness=0)
canvas.pack(fill='both', expand=1)
tkimage = ImageTk.PhotoImage(bgimage)
canvas.create_image(0, 0, image=tkimage, anchor='nw', tag='images')
win.bind('<ButtonPress-1>', on_mouse_down)
win.bind('<B1-Motion>', on_mouse_move)
win.bind('<ButtonRelease-1>', lambda e: win.destroy())
win.focus_force()
win.grab_set()
win.wait_window(win)
root.deiconify()  
if roi_image:
start_recording((x1, y1, x2, y2)) #calling main function to record screen

def recording_screen(x1, y1, x2, y2):
global recording
recording = True
while recording:
img = ImageGrab.grab(bbox=(x1, y1, x2, y2))
#frame = np.array(img) # not necessary
sc = np.array(img)
sc = cv2.resize(sc, VIDEO_SIZE)
tkimage.paste(Image.fromarray(sc))
frame = cv2.cvtColor(sc, cv2.COLOR_RGB2BGR)
out.write(frame)
def start_recording(region):
''' not necessary
if not out.isOpened():
out.open(filename, fourcc, frame_rate, VIDEO_SIZE)
'''
threading.Thread(target=recording_screen, args=region, daemon=True).start()
def stop_recording():
global recording
recording = False
out.release()

tkimage = ImageTk.PhotoImage(Image.new('RGB', VIDEO_SIZE, (0,0,0)))
w, h = VIDEO_SIZE
vbox = tk.Label(root, image=tkimage, width=w, height=h, bg='black')
vbox.pack(pady=10,padx=25)
frame = tk.Frame(root)
frame.pack()
sel_area = ttk.Button(frame, text='select area to Record', width=30, command=area_sel)
sel_area.grid(row=0, column=0)
stp_rec = ttk.Button(frame, text='Stop Recording', width=30, command=stop_recording)
stp_rec.grid(row=0, column=1)
root.mainloop()

最新更新