您好,登錄后才能下訂單哦!
這篇文章跟大家分析一下“基于Python+OpenCV如何制作屏幕錄制工具”。內容詳細易懂,對“基于Python+OpenCV如何制作屏幕錄制工具”感興趣的朋友可以跟著小編的思路慢慢深入來閱讀一下,希望閱讀后能夠對大家有所幫助。下面跟著小編一起深入學習“基于Python+OpenCV如何制作屏幕錄制工具”的知識吧。
windows 10
python 3.7
屏幕錄制可以簡單地理解為將屏幕快照以動圖的形式播放,這里我選用PIL下的ImageGrab來截取屏幕畫面,首先
pip install Pillow
之后需要將截取到的快照數組合成為視頻,使用cv2模塊
pip install opencv-python
ImageGrab類不能直接存儲為視頻,使用numpy模塊進行數組化,再通過cv2.COLOR_BGR2RGB轉換為cv2色彩通道。
pip install numpy
屏幕錄制主要代碼:
import numpy as np from PIL import ImageGrab import cv2 im = ImageGrab.grab() width, high = im.size # 獲取屏幕的寬和高 fourcc = cv2.VideoWriter_fourcc(*'I420') # 設置視頻編碼格式 fps = 15 # 設置幀率 video = cv2.VideoWriter('test.avi', fourcc, fps, (width, high)) while True: # 開始錄制 im = ImageGrab.grab() im_cv = cv2.cvtColor(np.array(im), cv2.COLOR_BGR2RGB) # 圖像寫入 video.write(im_cv) if xx: # 當某某條件滿足中斷循環 break video.release() # 釋放緩存,持久化視頻
測試運行可以保存屏幕快照為視頻,但操作起來不優雅,也不利于后續的操作。
封裝成類,繼承線程父類,方便使用鍵盤來控制視頻錄制的結束。
from threading import Thread class ScreenshotVideo(Thread): def __init__(self): """初始化參數""" super().__init__()
詳細代碼將在文末給出。
實際操作中視頻錄制在不同電腦中會出現不一樣的幀率,導致視頻播放或快或慢,需要根據不同的電腦計算出相應的最優fps值。
def video_best_fps(self, path): """獲取電腦錄制視頻的最優幀率""" video = cv2.VideoCapture(path) # 讀取視頻 fps = video.get(cv2.CAP_PROP_FPS) # 獲取當前視頻的幀率 count = video.get(cv2.CAP_PROP_FRAME_COUNT) # 獲取視頻幀數,即該視頻有多少幅畫面 self.best_fps = int(fps * ((int(count) / fps) / self.spend_time)) # 計算播放時間與錄制時間對比得到最優幀率 video.release()
再調整幀率參數進行錄制視頻就減弱了視頻播放太快或者太慢。也可以給視頻增加幀數從而延長播放時間,這里我采用一種很簡單的方法增加視頻幀,僅供參考。
from numba import jit # 使用numpy計算相鄰兩幀圖像且更接近于后一幀的圖像 # 調用jit方法加速數組計算 @jit(nopython=True) def average_n(x, y): """Numpy計算趨近值""" return ((x + y + y) // 3).astype(x.dtype)
該方法僅針對于設置的fps比最優fps要高時,處理后的視頻觀感,視頻還是較為急促,但是細節幀增多,所以播放時長會比未處理前的要長,略有殘影。
在視頻錄制中,并不知道視頻何時結束,所以用while循環包裹錄制代碼,但也不可能讓代碼無休止的運行下去,在此使用監聽鍵盤模塊來中斷錄制代碼的運行。
from pynput import keyboard # pip install pynput def hotkey(self): """熱鍵監聽""" with keyboard.Listener(on_press=self.on_press) as listener: listener.join() def on_press(self, key): try: if key.char == 't': # 錄屏結束,保存視頻 self.flag = True elif key.char == 'k': # 錄屏中止,刪除文件 self.flag = True self.kill = True except Exception as e: print(e)
按下鍵盤“T”鍵時,結束錄制,保存視頻。“K”鍵則是停止錄制,刪除緩存文件。
視頻編碼格式應該為('a', 'v', 'c', '1'),文件后綴為'.mp4',在錄制前先去https://github.com/cisco/openh364/releases下下載對應平臺的dll.bz2文件,將壓縮包解壓放在項目文件夾下。再運行代碼,成功會出現一行編碼說明:
OpenH264 Video Codec provided by Cisco Systems, Inc.
本文實現的源碼如下:
import time from PIL import ImageGrab import cv2 from pathlib import Path import numpy as np from numba import jit from pynput import keyboard from threading import Thread @jit(nopython=True) def average_n(x, y): """Numpy計算趨近值""" return ((x + y + y) // 3).astype(x.dtype) class ScreenshotVideo(Thread): def __init__(self, width, high, path='', fps=15): """初始化參數""" super().__init__() self.save_file = path self.best_fps = fps self.fps = fps self.width = width self.high = high self.spend_time = 1 self.flag = False self.kill = False self.video = None def __call__(self, path): """重載視頻路徑,便于類的二次調用""" self.save_file = Path(path) self.video = self.init_videowriter(self.save_file) @staticmethod def screenshot(): """靜態方法,屏幕截圖,并轉換為np.array數組""" return np.array(ImageGrab.grab()) @staticmethod def get_fourcc(name): """視頻編碼字典""" fourcc_maps = {'.avi': 'I420', '.m4v': 'mp4v', '.mp4': 'avc1', '.ogv': 'THEO', '.flv': 'FLV1', } return fourcc_maps.get(name) def init_videowriter(self, path): """獲取視頻編碼并新建視頻文件""" if not path: raise Exception('視頻路徑未設置,請設置\nvideo = ScreenshotVideo(fps,width,high)\nvideo = video(video_path)') path = Path(path) if isinstance(path, str) else path fourcc = cv2.VideoWriter_fourcc(*self.get_fourcc(path.suffix)) return cv2.VideoWriter(path.as_posix(), fourcc, self.fps, (self.width, self.high)) def video_record_doing(self, img): """將BGR數組轉換為RGB數組""" im_cv = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) self.video.write(im_cv) def video_record_end(self): """錄制結束,根據條件判斷文件是否保存""" self.video.release() cv2.destroyAllWindows() if self.save_file and self.kill: Path(self.save_file).unlink() def video_best_fps(self, path): """獲取電腦錄制視頻的最優幀率""" video = cv2.VideoCapture(path) fps = video.get(cv2.CAP_PROP_FPS) count = video.get(cv2.CAP_PROP_FRAME_COUNT) self.best_fps = int(fps * ((int(count) / fps) / self.spend_time)) video.release() def pre_video_record(self): """預錄制,以獲取最佳fps值""" self.video = self.init_videowriter('test.mp4') start_time = time.time() for _ in range(10): im = self.screenshot() self.video_record_doing(im) self.spend_time = round(time.time() - start_time, 4) self.video_record_end() time.sleep(2) self.video_best_fps('test.mp4') Path('test.mp4').unlink() def insert_frame_array(self, frame_list): """Numpy增強截圖信息""" fps_n = round(self.fps / self.best_fps) if fps_n <= 0: return frame_list times = int(np.log2(fps_n)) # 倍率 for _ in range(times): frame_list2 = map(average_n, [frame_list[0]] + frame_list[:-1], frame_list) frame_list = [[x, y] for x, y in zip(frame_list2, frame_list)] frame_list = [j for i in frame_list for j in i] return frame_list def frame2video_run(self): """使用opencv將連續型截圖轉換為視頻""" self.video = self.init_videowriter(self.save_file) start_time = time.time() frame_list = [] while True: frame_list.append(self.screenshot()) if self.flag: break self.spend_time = round(time.time() - start_time, 4) if not self.kill: # 視頻錄制不被終止將逐幀處理圖像 frame_list = self.insert_frame_array(frame_list) for im in frame_list: self.video_record_doing(im) self.video_record_end() def hotkey(self): """熱鍵監聽""" with keyboard.Listener(on_press=self.on_press) as listener: listener.join() def on_press(self, key): try: if key.char == 't': # 錄屏結束,保存視頻 self.flag = True elif key.char == 'k': # 錄屏中止,刪除文件 self.flag = True self.kill = True except Exception as e: print(e) def run(self): # 運行函數 # 設置守護線程 Thread(target=self.hotkey, daemon=True).start() # 運行截圖函數 self.frame2video_run() screen = ImageGrab.grab() width, high = screen.size video = ScreenshotVideo(width, high, fps=60) video.pre_video_record() # 預錄制獲取最優fps video('test1.mp4') video.run()
關于基于Python+OpenCV如何制作屏幕錄制工具就分享到這里啦,希望上述內容能夠讓大家有所提升。如果想要學習更多知識,請大家多多留意小編的更新。謝謝大家關注一下億速云網站!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。