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

Python 如何仅记录屏幕的特定选定区域,python,opencv,tkinter,python-imaging-library,Python,Opencv,Tkinter,Python Imaging Library,我有一个Python程序,可以对桌面屏幕的选定区域进行屏幕截图 该程序通过光标获取选定区域的坐标 然后裁剪图像并显示图像 但是现在我正在制作一个屏幕记录器,我想用所选区域的坐标来记录特定的屏幕区域 这是我的区域选择代码 import tkinter as tk from tkinter import * from tkinter import ttk ,FLAT from PIL import Image, ImageTk, ImageGrab, ImageEnhance import cv2

我有一个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()
将tkinter作为tk导入
从tkinter进口*
从tkinter导入ttk,平面
从PIL导入图像、ImageTk、ImageGrab、ImageEnhance
进口cv2
将numpy作为np导入
导入线程
视频大小=(800420)
f=ImageGrab.grab()
a、 b=f.尺寸
filename=“test.avi”
fourcc=cv2.VideoWriter_fourcc(*“H264”)
帧速率=10
out=cv2.VideoWriter(文件名,fourcc,帧速率,(a,b))
root=tk.tk()
根目录。可调整大小(0,0)
root.title('屏幕记录器')
根几何体('+260+70')
x1=y1=x2=y2=0
def显示_图像(图像):
win=tk.Toplevel()
win.image=ImageTk.PhotoImage(图像)
标签(win,image=win.image).pack()
赢,抢一套
win.等待窗口(win)
def区域_sel():
x1=y1=x2=y2=0
roi\u图像=无
鼠标按下时的def(事件):
非局部x1,y1
x1,y1=事件x,事件y
画布。创建_矩形(x1,y1,x1,y1,outline='red',tag='roi')
鼠标移动时的def(事件):
非局部roi_图像,x2,y2
x2,y2=事件x,事件y
canvas.delete('roi-image')
roi_image=image.crop((x1,y1,x2,y2))
canvas.image=ImageTk.PhotoImage(roi\u图像)
canvas.create_image(x1,y1,image=canvas.image,tag=('roi-image'),anchor='nw'))
画布坐标('roi',x1,y1,x2,y2)
canvas.lift('roi')
root.draw()
image=ImageGrab.grab()
bgimage=ImageEnhance.亮度(图像).enhance(0.3)
win=tk.Toplevel()
win.attributes('-fullscreen',1)
win.attributes('-toppost',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(“”,lambda e:win.destroy())
赢,集中力量
赢,抢一套
win.等待窗口(win)
root.deiconify()
如果是roi_图像:
开始录制()#调用main函数录制屏幕
def录制屏幕():
全局记录
录音=真
录制时:
img=ImageGrab.grab(bbox=(x1,y1,x2,y2))
帧=np.数组(img)
sc=np.数组(img)
sc=cv2。调整大小(sc,视频大小)
粘贴(Image.fromarray(sc))
frame=cv2.CVT颜色(frame,cv2.COLOR_RGB2BGR)
输出。写入(帧)
def start_录制():
如果不在外,则为。IsOpen():
打开(文件名,fourcc,帧速率,(a,b))
threading.Thread(target=recording\u screen,daemon=True).start()
def停止_录制():
全局记录
录音=假
out.release()
tkimage=ImageTk.PhotoImage(Image.new('RGB',视频大小,(0,0,0)))
w、 h=视频大小
vbox=tk.Label(根,图像=tkimage,宽度=w,高度=h,bg='black')
vbox.pack(pady=10,padx=25)
frame=tk.frame(根)
frame.pack()
sel_area=ttk.按钮(框,text='select area to Record',width=30,command=area_sel)
选择面积网格(行=0,列=0)
stp_rec=ttk.按钮(帧,文本='停止录制',宽度=30,命令=停止录制)
stp记录网格(行=0,列=1)
root.mainloop()
显示错误

sc=cv2.resize(sc,视频大小)
TypeError:参数“%s”应为Ptr

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

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

out.open(filename, fourcc, frame_rate,(a, b))
OpenCV文档指定了以下参数

retval = cv.VideoWriter.open(filename, fourcc, fps, frameSize[, isColor] )
如果您的
out.isOpened()
返回
False
。这意味着您的
VideoWriter
初始化失败,您需要指定参数

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

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

1) 输出视频的帧大小
(a,b)
与捕获图像大小
视频大小

f = ImageGrab.grab()
a, b = f.size
...
out = cv2.VideoWriter(filename, fourcc, frame_rate, (a,b))
只需删除
f=ImageGrab.grab()
a,b=f.size
并使用
VIDEO\u size
in`out=cv2.VideoWriter(…,VIDEO\u size):

2) 在全局空间中添加了
x1=y1=x2=y2=0
,但不更新它们。因此,在捕获过程中,将捕获零大小的图像并调整其大小,这会导致问题中提到的错误。删除全局声明行,并将
x1、y1、x2、y2
传递给
start\u recording()
recording\u 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()
将tkinter作为tk导入
从tkinter进口*
从tkinter导入ttk,平面
从PIL导入图像、ImageTk、ImageGrab、ImageEnhance
进口cv2
将numpy作为np导入
导入线程
视频大小=(800420)
#f=ImageGrab.grab()不需要
#a、 b=f.尺寸不需要
filename=“test.avi”
fourcc=cv2.VideoWriter_fourcc(*“H264”)
帧速率=10
out=cv2.VideoWriter(文件名、fourcc、帧速率、视频大小)#使用视频大小
root=tk.tk()
根目录。可调整大小(0,0)
root.title('屏幕记录器')
根几何体('+260+70')
#x1=y1=x2=y2=0#不需要
def显示_图像(图像):
win=tk.Toplevel()
win.image=ImageTk.PhotoImage(图像)
标签(win,image=win.image).pack()
赢,抢一套
win.等待窗口(win)
def区域_sel():
x1=y1=x2=y2=0
roi\u图像=无
鼠标按下时的def(事件):
非局部x1,y1
x1,y1=事件x,事件y
画布。创建_矩形(x1,y1,x1,y1,outline='red',tag='roi')
鼠标移动时的def(事件):
非局部roi_图像,x2,y2
x2,y2=事件x,事件y
canvas.delete('roi-image')
roi_image=image.crop((x1,y1,x2,y2))
canvas.image=ImageTk.PhotoImage(roi\u图像)
画布。创建_图像(x1、y1、imag
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()