Python - Trích xuất và lưu khung video


132

Vì vậy, tôi đã làm theo hướng dẫn này nhưng dường như nó không làm gì cả. Đơn giản là không có gì. Nó đợi vài giây và đóng chương trình. Có gì sai với mã này?

import cv2
vidcap = cv2.VideoCapture('Compton.mp4')
success,image = vidcap.read()
count = 0
success = True
while success:
  success,image = vidcap.read()
  cv2.imwrite("frame%d.jpg" % count, image)     # save frame as JPEG file
  if cv2.waitKey(10) == 27:                     # exit if Escape is hit
      break
  count += 1

Ngoài ra, trong các ý kiến ​​nói rằng điều này giới hạn các khung hình đến 1000? Tại sao?

EDIT: Tôi đã thử làm success = Truetrước nhưng điều đó không có ích. Nó chỉ tạo ra một hình ảnh là 0 byte.


1
Giá trị của successcái gì?
101

2
Là gì giá trị ? Các loại có thể là boolean, nhưng nó là Truehay False?
That1Guy

1
Vâng, nhưng giá trị của bạn là gì? Nó có thể sai trong trường hợp chương trình của bạn chỉ đơn giản là "chờ vài giây và đóng lại". Nói cách khác, thêm một print successnơi nào đó.
101

1
Nó không có ý nghĩa để ép buộc success; nếu nó sai thì điều đó có nghĩa là việc đọc video đã thất bại vì một số lý do. Bạn cần có được bit đó làm việc đầu tiên.
101

1
Readh của bạn đang thất bại. Bạn đã xây dựng opencv với python và ffmpeg như được hướng dẫn trong hướng dẫn chưa? brew install opencv --python27 --ffmpegnếu bạn đang sử dụng một phiên bản Python khác, bạn sẽ cần thay đổi nó thành phiên bản của bạn.

Câu trả lời:


225

Từ đây tải xuống video này để chúng tôi có cùng một tệp video cho thử nghiệm. Đảm bảo có tệp mp4 đó trong cùng thư mục mã python của bạn. Sau đó, hãy đảm bảo chạy trình thông dịch python từ cùng thư mục.

Sau đó sửa đổi mã, bỏ đi waitKeyviệc lãng phí thời gian mà không có cửa sổ, nó không thể ghi lại các sự kiện bàn phím. Ngoài ra, chúng tôi in successgiá trị để đảm bảo rằng nó đọc các khung thành công.

import cv2
vidcap = cv2.VideoCapture('big_buck_bunny_720p_5mb.mp4')
success,image = vidcap.read()
count = 0
while success:
  cv2.imwrite("frame%d.jpg" % count, image)     # save frame as JPEG file      
  success,image = vidcap.read()
  print('Read a new frame: ', success)
  count += 1

Làm thế nào mà đi?


4
Điều này tiết kiệm một file jpeg trống rỗng, và nó sẽ trả vềRead a new frame: False

3
Điều đó có nghĩa là opencv không thể đọc video. Nhiều khả năng nó không thể truy cập ffmpeg. bạn đang sử dụng hệ điều hành nào?
cuộc thi cứu hỏa


3
Google hướng dẫn cho phiên bản opencv cụ thể của bạn và làm theo chính xác về cách để ffmpeg và opencv-python hoạt động trên Windows.
cuộc thi cứu hỏa

3
Vì vậy, tôi đã sử dụng câu hỏi này để giải quyết vấn đề của tôi với tính tương thích. Tôi đã phải đổi tên DLL thành opencv_ffmpeg300.dll (vì cài đặt Python của OpenCV2 là 3.0.0). Tôi đã đặt nó vào thư mục Python của tôi (C: \ Python27). Tôi không cần cài đặt phiên bản windows của ffmpeg hay opencv, nhưng tôi cần DLL đó đi kèm với OpenCV, nhưng tôi đã xóa phần còn lại của OpenCV sau đó. Nhưng dù sao, tôi sẽ chọn đây là một câu trả lời, nhưng bất cứ ai đọc nó đều phải biết về DLL ESSENTIAL này.

37

Để mở rộng câu hỏi này (& trả lời bởi @ user2700065) cho các trường hợp hơi khác nhau, nếu bất kỳ ai không muốn trích xuất mọi khung hình nhưng muốn trích xuất khung hình mỗi giây. Vì vậy, video dài 1 phút sẽ cho 60 khung hình (hình ảnh).

import sys
import argparse

import cv2
print(cv2.__version__)

def extractImages(pathIn, pathOut):
    count = 0
    vidcap = cv2.VideoCapture(pathIn)
    success,image = vidcap.read()
    success = True
    while success:
        vidcap.set(cv2.CAP_PROP_POS_MSEC,(count*1000))    # added this line 
        success,image = vidcap.read()
        print ('Read a new frame: ', success)
        cv2.imwrite( pathOut + "\\frame%d.jpg" % count, image)     # save frame as JPEG file
        count = count + 1

if __name__=="__main__":
    a = argparse.ArgumentParser()
    a.add_argument("--pathIn", help="path to video")
    a.add_argument("--pathOut", help="path to images")
    args = a.parse_args()
    print(args)
    extractImages(args.pathIn, args.pathOut)

Tôi đang sử dụng opencv-2.4.9, vì vậy thay vì cv2.CAP_PROP_POS_MSECtôi phải sử dụngcv2.cv.CAP_PROP_POS_MSEC
Pratik Kumar

1
Làm cách nào để thay đổi mã nếu tôi muốn khung hình cứ sau 5 giây?
Soumya Boral

1
@SoumyaBoralcount = count + 5
Bhushan Babar

@BhushanBabar không nên có một cv2.imwrite()đầu ở vòng lặp kể từ khi bạn gọi cv2.imread()trước vòng lặp?
mLstudent33

@ mLstudent33 xin lỗi, đừng hiểu bạn, xin hãy giải thích.
Bhushan Babar

12

Đây là một chỉnh sửa từ câu trả lời trước cho python 3.x từ @GShocked, tôi sẽ đăng nó lên bình luận, nhưng không đủ danh tiếng

import sys
import argparse

import cv2
print(cv2.__version__)

def extractImages(pathIn, pathOut):
    vidcap = cv2.VideoCapture(pathIn)
    success,image = vidcap.read()
    count = 0
    success = True
    while success:
      success,image = vidcap.read()
      print ('Read a new frame: ', success)
      cv2.imwrite( pathOut + "\\frame%d.jpg" % count, image)     # save frame as JPEG file
      count += 1

if __name__=="__main__":
    print("aba")
    a = argparse.ArgumentParser()
    a.add_argument("--pathIn", help="path to video")
    a.add_argument("--pathOut", help="path to images")
    args = a.parse_args()
    print(args)
    extractImages(args.pathIn, args.pathOut)

11

Đây là Chức năng sẽ chuyển đổi hầu hết các định dạng video thành số khung hình có trong video. Nó hoạt động Python3vớiOpenCV 3+

import cv2
import time
import os

def video_to_frames(input_loc, output_loc):
    """Function to extract frames from input video file
    and save them as separate frames in an output directory.
    Args:
        input_loc: Input video file.
        output_loc: Output directory to save the frames.
    Returns:
        None
    """
    try:
        os.mkdir(output_loc)
    except OSError:
        pass
    # Log the time
    time_start = time.time()
    # Start capturing the feed
    cap = cv2.VideoCapture(input_loc)
    # Find the number of frames
    video_length = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) - 1
    print ("Number of frames: ", video_length)
    count = 0
    print ("Converting video..\n")
    # Start converting the video
    while cap.isOpened():
        # Extract the frame
        ret, frame = cap.read()
        # Write the results back to output location.
        cv2.imwrite(output_loc + "/%#05d.jpg" % (count+1), frame)
        count = count + 1
        # If there are no more frames left
        if (count > (video_length-1)):
            # Log the time again
            time_end = time.time()
            # Release the feed
            cap.release()
            # Print stats
            print ("Done extracting frames.\n%d frames extracted" % count)
            print ("It took %d seconds forconversion." % (time_end-time_start))
            break

if __name__=="__main__":

    input_loc = '/path/to/video/00009.MTS'
    output_loc = '/path/to/output/frames/'
    video_to_frames(input_loc, output_loc)

Nó hỗ trợ .mtsvà các tập tin bình thường như .mp4.avi. Đã thử và thử nghiệm trên .mtscác tập tin. Hoạt động như một Bùa chú.


8

Sau rất nhiều nghiên cứu về cách chuyển đổi khung hình thành video, tôi đã tạo ra chức năng này hy vọng điều này sẽ giúp ích. Chúng tôi yêu cầu opencv cho việc này:

import cv2
import numpy as np
import os

def frames_to_video(inputpath,outputpath,fps):
   image_array = []
   files = [f for f in os.listdir(inputpath) if isfile(join(inputpath, f))]
   files.sort(key = lambda x: int(x[5:-4]))
   for i in range(len(files)):
       img = cv2.imread(inputpath + files[i])
       size =  (img.shape[1],img.shape[0])
       img = cv2.resize(img,size)
       image_array.append(img)
   fourcc = cv2.VideoWriter_fourcc('D', 'I', 'V', 'X')
   out = cv2.VideoWriter(outputpath,fourcc, fps, size)
   for i in range(len(image_array)):
       out.write(image_array[i])
   out.release()


inputpath = 'folder path'
outpath =  'video file path/video.mp4'
fps = 29
frames_to_video(inputpath,outpath,fps)

thay đổi giá trị của khung hình / giây (khung hình trên giây), đường dẫn thư mục đầu vào và đường dẫn thư mục đầu ra theo vị trí cục bộ của riêng bạn


files.sort (key = lambda x: int (x [5: -4])) THÊM LINE LINE giúp sắp xếp các khung theo số và không phải chuỗi, ví dụ: ban đầu frame1.jpg được theo sau bởi frame10.jpg không phải frame2.jpg, dòng trên sắp xếp các tệp theo các số trong đó.
Puja Sharma

3
Câu hỏi được chuyển từ video sang khung hình
Santhosh Dhaipule Chandrakanth 30/11/18

không lưu video cho tôi vì một số lý do
Raksha

7

Các câu trả lời trước đã mất khung đầu tiên. Và sẽ thật tuyệt khi lưu trữ những hình ảnh trong một thư mục.

# create a folder to store extracted images
import os
folder = 'test'  
os.mkdir(folder)
# use opencv to do the job
import cv2
print(cv2.__version__)  # my version is 3.1.0
vidcap = cv2.VideoCapture('test_video.mp4')
count = 0
while True:
    success,image = vidcap.read()
    if not success:
        break
    cv2.imwrite(os.path.join(folder,"frame{:d}.jpg".format(count)), image)     # save frame as JPEG file
    count += 1
print("{} images are extacted in {}.".format(count,folder))

Nhân tiện, bạn có thể kiểm tra khung chuột e bằng VLC. Chuyển đến windows -> thông tin phương tiện -> chi tiết codec


Có cách nào để tăng tốc độ khung hình trong khi trích xuất không?
Pratik Khadloya

Không. Khi video được tạo, tốc độ khung hình được cố định. Bạn không thể trích xuất nhiều hơn thế.
Yuchao Jiang

Thật là một câu trả lời tuyệt vời. Làm việc hoàn hảo cho tôi. Có cách nào để điều chỉnh vòng lặp trong mã để tôi chỉ nhận được các khung từ một phạm vi nhất định, như khung 120 - 160 không? Cảm ơn!
Bowen Liu

Bạn có thể sử dụng số lượng biến để chỉ định các khung bạn muốn trích xuất.
Yuchao Jiang

Tôi phải làm gì nếu tôi muốn trích xuất từ ​​video, giả sử 15 khung hình được định vị một cách đồng đều theo thời gian từ đầu video đến cuối video? Tôi phát hiện ra mình phải sử dụng cv.CAP_PROP_POS_AVI_RATIO, nhưng tôi không biết làm thế nào. tnx
NeStack

7

Mã này trích xuất các khung từ video và lưu các khung ở dạng .jpg

import cv2
import numpy as np
import os

# set video file path of input video with name and extension
vid = cv2.VideoCapture('VideoPath')


if not os.path.exists('images'):
    os.makedirs('images')

#for frame identity
index = 0
while(True):
    # Extract images
    ret, frame = vid.read()
    # end of frames
    if not ret: 
        break
    # Saves images
    name = './images/frame' + str(index) + '.jpg'
    print ('Creating...' + name)
    cv2.imwrite(name, frame)

    # next frame
    index += 1

4

Tôi đang sử dụng Python thông qua phần mềm Spyder của Anaconda. Sử dụng mã gốc được liệt kê trong câu hỏi của chủ đề này bởi @Gshocked, mã không hoạt động (python sẽ không đọc tệp mp4). Vì vậy, tôi đã tải xuống OpenCV 3.2 và sao chép "opencv_ffmpeg320.dll" và "opencv_ffmpeg320_64.dll" từ thư mục "bin". Tôi đã dán cả hai tập tin dll này vào thư mục "dll" của Anaconda.

Anaconda cũng có thư mục "pckgs" ... Tôi đã sao chép và dán toàn bộ thư mục "OpenCV 3.2" mà tôi đã tải xuống thư mục "pckgs" của Anaconda.

Cuối cùng, Anaconda có một thư mục "Thư viện" có thư mục con "bin". Tôi đã dán các tệp "opencv_ffmpeg320.dll" và "opencv_ffmpeg320_64.dll" vào thư mục đó.

Sau khi đóng và khởi động lại Spyder, mã đã hoạt động. Tôi không chắc phương pháp nào trong ba phương pháp này hiệu quả và tôi quá lười để quay lại và tìm ra nó. Nhưng nó hoạt động như vậy, chúc mừng!


4

Hàm này trích xuất hình ảnh từ video với 1 khung hình / giây, VÀO THÊM, nó xác định khung hình cuối cùng và cũng dừng đọc:

import cv2
import numpy as np

def extract_image_one_fps(video_source_path):

    vidcap = cv2.VideoCapture(video_source_path)
    count = 0
    success = True
    while success:
      vidcap.set(cv2.CAP_PROP_POS_MSEC,(count*1000))      
      success,image = vidcap.read()

      ## Stop when last frame is identified
      image_last = cv2.imread("frame{}.png".format(count-1))
      if np.array_equal(image,image_last):
          break

      cv2.imwrite("frame%d.png" % count, image)     # save frame as PNG file
      print '{}.sec reading a new frame: {} '.format(count,success)
      count += 1

0

Tập lệnh sau sẽ trích xuất các khung hình mỗi nửa giây của tất cả các video trong thư mục. (Hoạt động trên python 3.7)

import cv2
import os
listing = os.listdir(r'D:/Images/AllVideos')
count=1
for vid in listing:
    vid = r"D:/Images/AllVideos/"+vid
    vidcap = cv2.VideoCapture(vid)
    def getFrame(sec):
        vidcap.set(cv2.CAP_PROP_POS_MSEC,sec*1000)
        hasFrames,image = vidcap.read()
        if hasFrames:
            cv2.imwrite("D:/Images/Frames/image"+str(count)+".jpg", image) # Save frame as JPG file
        return hasFrames
    sec = 0
    frameRate = 0.5 # Change this number to 1 for each 1 second
    
    success = getFrame(sec)
    while success:
        count = count + 1
        sec = sec + frameRate
        sec = round(sec, 2)
        success = getFrame(sec)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.