Python: 从视频中截取屏幕截图

7

这个想法是,用户应该能够从本地加载视频,并告诉程序每5秒或30秒从视频中截取一张屏幕截图。有没有任何库可以帮助我完成这个任务?如何进行下一步操作的任何想法都会很有帮助。


OpenCV - 你可以使用 video_capture 捕获视频,然后逐帧处理它(例如保存你想要截屏的那一帧)。 - Grzegorz Skibinski
7个回答

7
使用以下命令安装opencv-python(这是Python的非官方预构建OpenCV包):
pip install opencv-python
# Importing all necessary libraries
import cv2
import os
import time

# Read the video from specified path
cam = cv2.VideoCapture("C:/Users/User/Desktop/videoplayback.mp4")

try:

    # creating a folder named data
    if not os.path.exists('data'):
        os.makedirs('data')

    # if not created then raise error
except OSError:
    print('Error: Creating directory of data')

# frame
currentframe = 0

while (True):
    time.sleep(5) # take schreenshot every 5 seconds
    # reading from frame
    ret, frame = cam.read()

    if ret:
        # if video is still left continue creating images
        name = './data/frame' + str(currentframe) + '.jpg'
        print('Creating...' + name)

        # writing the extracted images
        cv2.imwrite(name, frame)

        # increasing counter so that it will
        # show how many frames are created
        currentframe += 1
    else:
        break

# Release all space and windows once done
cam.release()
cv2.destroyAllWindows()

谢谢回答。是否也可以定义在视频的第30秒、第40秒和第55秒拍摄截图? - asdfkjasdfjk
6
time.sleep(5) 这部分只是让脚本运行变慢,并不影响截屏的间隔时间。 - Louie Lee

5
上面的答案部分正确,但在这里使用time.sleep根本没有帮助,反而会使进程变慢。然而,如果您想在视频的某个时间点拍摄屏幕截图,您需要了解每次执行“ret, frame = cam.read()”时,它会读取视频的下一帧。视频中的每秒都有一定数量的帧,这取决于视频。您可以使用以下代码获取该数字:
  frame_per_second = cam.get(cv2.CAP_PROP_FPS) 

所以,如果你需要截取第三秒的截图,你可以按照上面的答案保持迭代不变,只需添加


  if currentframe == (3*frame_per_second):  
      cv2.imwrite(name, frame)

这将会在第3秒拍摄第一帧的截图。


我相信你的条件实际上是不正确的。它应该长这样:if currentframe % (frame_per_second*3) == 0: - Batata

2
#ncica & Data_sniffer solution remake
import cv2
import os
import time

step = 10
frames_count = 3
cam = cv2.VideoCapture('video/example.MP4')

currentframe = 0
frame_per_second = cam.get(cv2.CAP_PROP_FPS) 
frames_captured = 0

while (True):
    ret, frame = cam.read()
    if ret:
        if currentframe > (step*frame_per_second):  
            currentframe = 0
            name = 'photo/frame' + str(frames_captured) + '.jpg'
            print(name)
            cv2.imwrite(name, frame)            
            frames_captured+=1
            if frames_captured>frames_count-1:
                ret = False
        currentframe += 1           
    if ret==False:
        break
cam.release()
cv2.destroyAllWindows()

2
#a generic function incorporating all the comments mentioned above.

def get_frames(inputFile,outputFolder,step,count):

  '''
  Input:
    inputFile - name of the input file with directoy
    outputFolder - name and path of the folder to save the results
    step - time lapse between each step (in seconds)
    count - number of screenshots
  Output:
    'count' number of screenshots that are 'step' seconds apart created from video 'inputFile' and stored in folder 'outputFolder'
  Function Call:
    get_frames("test.mp4", 'data', 10, 10)
  '''

  #initializing local variables
  step = step
  frames_count = count

  currentframe = 0
  frames_captured = 0

  #creating a folder
  try:  
      # creating a folder named data 
      if not os.path.exists(outputFolder): 
          os.makedirs(outputFolder) 
    
  #if not created then raise error 
  except OSError: 
      print ('Error! Could not create a directory') 
  
  #reading the video from specified path 
  cam = cv2.VideoCapture(inputFile) 

  #reading the number of frames at that particular second
  frame_per_second = cam.get(cv2.CAP_PROP_FPS)

  while (True):
      ret, frame = cam.read()
      if ret:
          if currentframe > (step*frame_per_second):  
              currentframe = 0
              #saving the frames (screenshots)
              name = './data/frame' + str(frames_captured) + '.jpg'
              print ('Creating...' + name) 
              
              cv2.imwrite(name, frame)       
              frames_captured+=1
              
              #breaking the loop when count achieved
              if frames_captured > frames_count-1:
                ret = False
          currentframe += 1           
      if ret == False:
          break
  
  #Releasing all space and windows once done
  cam.release()
  cv2.destroyAllWindows()

0

修改了 @ncica 的代码并注意到它运行良好。

import cv2
import os
import time

cam = cv2.VideoCapture("/path/to/videoIn.mp4")

try:
    if not os.path.exists('data'):
        os.makedirs('data')

except OSError:
    print('Error: Creating directory of data')

intvl = 2 #interval in second(s)

fps= int(cam.get(cv2.CAP_PROP_FPS))
print("fps : " ,fps)

currentframe = 0
while (True):
    ret, frame = cam.read()
    if ret:
        if(currentframe % (fps*intvl) == 0):
            name = './data/frame' + str(currentframe) + '.jpg'
            print('Creating...' + name)
            cv2.imwrite(name, frame)
        currentframe += 1
    else:
        break

cam.release()
cv2.destroyAllWindows()

技巧在于逐帧循环。因此,我们在这里捕获所需的帧并将其写入磁盘作为快照图像文件。例如:如果您想要每两秒拍摄一次快照,则intvl必须为2。

0

提供的解决方案在多种情况下对我无效。

cv2.CAP_PROP_FPS中的FPS是一个浮点值,根据此属性,我的testvid.mp4的FPS速率为23.976023976023978

当循环遍历current_frame / fps % 3时,由于这个浮点值,我们几乎总会有剩余。同样适用于(3*frame_per_second),导致我们的imwrite永远不会被执行。

我通过使用相同的计算方法,但存储余数并进行比较来解决了这个问题:

    current_frame = 0
    fps_calculator_previous = 0
    while (True):
        ret, frame = cam.read()

        if ret:
            # Still got video left.
            file_name = f"./data_generation/out/{_fn}-{current_frame}.jpg"


            fps_calculator = (current_frame / fps) % every_x_sec
            if(fps_calculator - fps_calculator_previous < 0):
                print("Found a frame to write!")
                cv2.imwrite(file_name, frame)
            fps_calculator_previous = fps_calculator

            current_frame += 1
        else:
            break

对我来说,这似乎适用于任何值的cv2.CAP_PROP_FPS以及every_x_sec

我的视频长18分7秒,当every_x_sec设置为3时,我从中捕获了362个独特的帧。


0
补充data_sniffer的答案。建议在检查时使用round(Math函数)来计算frame_per_second,因为如果帧速率是一个小数,则会进入无限循环。

1
嗨,如果这不是对问题的直接回答,最好将其作为评论而不是新答案。 - ArianJM
1
我没有足够的声望来做那件事,但我仍然想把它发布出去。 - Amogh Wagh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接