Python - การแยกและบันทึกวิดีโอเฟรม


135

ฉันได้ทำตามบทช่วยสอนนี้แล้วแต่ดูเหมือนจะไม่ได้ทำอะไรเลย ไม่มีอะไรเลย รอสองสามวินาทีและปิดโปรแกรม รหัสนี้มีอะไรผิดปกติ

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

นอกจากนี้ในความคิดเห็นยังระบุว่าสิ่งนี้ จำกัด เฟรมไว้ที่ 1,000? ทำไม?

แก้ไข: ฉันพยายามทำsuccess = Trueก่อน แต่ก็ไม่ได้ผล สร้างเพียงภาพเดียวที่มีขนาด 0 ไบต์


1
มูลค่าของsuccessอะไร?
101

2
อะไรคือสิ่งที่คุ้มค่า ? ประเภทอาจจะเป็นแบบบูล แต่มันเป็นTrueหรือFalse?
That1Guy

1
ใช่ แต่คุณค่าของคุณคืออะไร? อาจเป็นเท็จซึ่งในกรณีนี้โปรแกรมของคุณจะ "รอสักครู่แล้วปิด" กล่าวอีกนัยหนึ่งคือเพิ่มprint successที่ไหนสักแห่ง
101

1
มันไม่ได้ทำให้รู้สึกถึงแรงsuccess; หากเป็นเท็จแสดงว่าการอ่านวิดีโอล้มเหลวด้วยเหตุผลบางประการ คุณต้องให้บิตนั้นทำงานก่อน
101

1
Readh ของคุณล้มเหลว คุณสร้าง opencv ด้วย python และ ffmpeg ตามคำแนะนำในบทช่วยสอนหรือไม่? brew install opencv --python27 --ffmpegหากคุณใช้ Python เวอร์ชันอื่นคุณจะต้องเปลี่ยนเป็นเวอร์ชันของคุณ
Knells

คำตอบ:


228

จากที่นี่ดาวน์โหลดวิดีโอนี้เพื่อให้เรามีไฟล์วิดีโอเดียวกันสำหรับการทดสอบ ตรวจสอบให้แน่ใจว่ามีไฟล์ mp4 นั้นอยู่ในไดเร็กทอรีเดียวกันกับรหัส python ของคุณ จากนั้นตรวจสอบให้แน่ใจว่าได้รัน python interpreter จากไดเร็กทอรีเดียวกัน

จากนั้นแก้ไขโค้ดทิ้งwaitKeyที่เสียเวลาโดยไม่มีหน้าต่างก็ไม่สามารถจับภาพเหตุการณ์บนคีย์บอร์ดได้ นอกจากนี้เรายังพิมพ์successค่าเพื่อให้แน่ใจว่าอ่านเฟรมสำเร็จ

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

ว่าไปอย่างไร?


4
สิ่งนี้บันทึกไฟล์ jpeg ที่ว่างเปล่าและจะส่งคืนRead a new frame: False

3
นั่นหมายความว่า opencv ไม่สามารถอ่านวิดีโอได้ เป็นไปได้มากว่ามันไม่สามารถเข้าถึง ffmpeg คุณใช้ระบบปฏิบัติการอะไร
เพลิง

1
ดูที่นี้: kronoskoders.logdown.com/posts/…
fireant

3
Google คำแนะนำสำหรับ opencv เวอร์ชันเฉพาะของคุณและปฏิบัติตามอย่างแม่นยำเกี่ยวกับวิธีการทำให้ ffmpeg และ opencv-python ทำงานบน Windows
พนักงานดับ

3
ฉันจึงใช้คำถามนี้เพื่อแก้ปัญหาเกี่ยวกับความเข้ากันได้ ฉันต้องเปลี่ยนชื่อ DLL เป็น opencv_ffmpeg300.dll (เนื่องจากการติดตั้ง Python ของ OpenCV2 คือ 3.0.0) ฉันวางไว้ในไดเรกทอรี Python ของฉัน (C: \ Python27) ฉันไม่จำเป็นต้องติดตั้ง ffmpeg หรือ opencv เวอร์ชัน windows แต่ฉันต้องการ DLL ที่มาพร้อมกับ OpenCV แต่ฉันลบ OpenCV ส่วนที่เหลือหลังจากนั้น อย่างไรก็ตามฉันจะเลือกสิ่งนี้เป็นคำตอบ แต่ทุกคนที่อ่านสิ่งนี้จะต้องรู้เกี่ยวกับ DLL ที่สำคัญนี้

37

หากต้องการขยายคำถามนี้ (& ตอบโดย @ user2700065) สำหรับกรณีที่แตกต่างกันเล็กน้อยหากใครไม่ต้องการแยกทุกเฟรม แต่ต้องการแยกเฟรมทุก ๆ หนึ่งวินาที ดังนั้นวิดีโอ 1 นาทีจะให้ 60 เฟรม (ภาพ)

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)

ฉันกำลังใช้opencv-2.4.9ดังนั้นแทนที่จะcv2.CAP_PROP_POS_MSECต้องใช้cv2.cv.CAP_PROP_POS_MSEC
Pratik Kumar

1
จะเปลี่ยนรหัสได้อย่างไรถ้าต้องการเฟรมทุกๆ 5 วินาที?
Soumya Boral

1
@SoumyaBoralcount = count + 5
Bhushan Babar

@BhushanBabar ไม่ควรมีcv2.imwrite()ที่จุดเริ่มต้นของการวนซ้ำตั้งแต่คุณเรียกcv2.imread()ก่อนวง?
mLstudent33

@ mLstudent33 ขออภัยไม่เข้าใจโปรดอธิบายให้ละเอียด
Bhushan Babar

12

นี่เป็นการปรับแต่งจากคำตอบก่อนหน้าสำหรับ python 3.x จาก @GShocked ฉันจะโพสต์ลงในความคิดเห็น แต่ไม่มีชื่อเสียงเพียงพอ

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

นี่คือฟังก์ชันที่จะแปลงรูปแบบวิดีโอส่วนใหญ่เป็นจำนวนเฟรมที่มีอยู่ในวิดีโอ ใช้งานได้Python3กับOpenCV 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)

รองรับ.mtsและไฟล์ปกติเช่น.mp4และ.avi. พยายามและทดสอบกับ.mtsไฟล์ ทำงานเหมือน Charm


8

หลังจากการวิจัยมากมายเกี่ยวกับวิธีการแปลงเฟรมเป็นวิดีโอฉันได้สร้างฟังก์ชั่นนี้หวังว่าจะช่วยได้ เราต้องการ opencv สำหรับสิ่งนี้:

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)

เปลี่ยนค่าของ fps (เฟรมต่อวินาที) พา ธ โฟลเดอร์อินพุตและพา ธ โฟลเดอร์เอาต์พุตตามตำแหน่งในเครื่องของคุณเอง


files.sort (key = lambda x: int (x [5: -4])) การเพิ่มบรรทัดด้านบนซึ่งช่วยในการจัดเรียงเฟรมตามจำนวนและไม่ใช่สตริงเช่นเริ่มต้น frame1.jpg ตามด้วย frame10.jpg ไม่ใช่ frame2.jpg บรรทัดด้านบนจะจัดเรียงไฟล์ตามตัวเลขในนั้น
Puja Sharma

3
คำถามมาจากวิดีโอสู่เฟรม
Santhosh Dhaipule Chandrakanth

ไม่บันทึกวิดีโอให้ฉันด้วยเหตุผลบางประการ
Raksha

7

คำตอบก่อนหน้านี้ทำให้เฟรมแรกหายไป และจะเป็นการดีที่จะเก็บภาพไว้ในโฟลเดอร์

# 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))

โดยวิธีนี้คุณสามารถตรวจสอบframe rat e ด้วย VLC ไปที่ windows -> ข้อมูลสื่อ -> รายละเอียดตัวแปลงสัญญาณ


มีวิธีเพิ่มอัตราเฟรมขณะสกัดหรือไม่?
Pratik Khadloya

ไม่เมื่อสร้างวิดีโออัตราเฟรมจะคงที่ คุณไม่สามารถแยกได้มากกว่านั้น
Yuchao Jiang

ช่างเป็นคำตอบที่น่าทึ่ง ทำงานได้อย่างสมบูรณ์แบบสำหรับฉัน จะมีวิธีปรับแต่งลูปในโค้ดเพื่อให้ได้เฟรมจากบางช่วงเช่นเฟรม 120-160 หรือไม่? ขอบคุณ!
Bowen Liu

คุณสามารถใช้การนับตัวแปรเพื่อระบุเฟรมที่คุณต้องการแยก
Yuchao Jiang

ฉันต้องทำอย่างไรหากต้องการดึงข้อมูลจากวิดีโอสมมติว่า 15 เฟรมที่วางตำแหน่งในระยะเวลาเท่ากันตั้งแต่วิดีโอเริ่มต้นไปจนถึงสิ้นสุดวิดีโอ ฉันพบว่าฉันต้องใช้cv.CAP_PROP_POS_AVI_RATIOแต่ฉันไม่รู้วิธี tnx
NeStack

7

รหัสนี้แยกเฟรมออกจากวิดีโอและบันทึกเฟรมในรูปแบบ. 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

ฉันใช้ Python ผ่านซอฟต์แวร์ Spyder ของ Anaconda การใช้รหัสเดิมที่ระบุไว้ในคำถามของเธรดนี้โดย @Gshocked รหัสจะไม่ทำงาน (python จะไม่อ่านไฟล์ mp4) ดังนั้นฉันจึงดาวน์โหลด OpenCV 3.2 และคัดลอก "opencv_ffmpeg320.dll" และ "opencv_ffmpeg320_64.dll" จากโฟลเดอร์ "bin" ฉันวางไฟล์ dll ทั้งสองไฟล์ลงในโฟลเดอร์ "Dlls" ของ Anaconda

Anaconda ยังมีโฟลเดอร์ "pckgs" ... ฉันคัดลอกและวางโฟลเดอร์ "OpenCV 3.2" ทั้งหมดที่ดาวน์โหลดไปยังโฟลเดอร์ "pckgs" ของ Anaconda

ในที่สุด Anaconda ก็มีโฟลเดอร์ "Library" ซึ่งมีโฟลเดอร์ย่อย "bin" ฉันวางไฟล์ "opencv_ffmpeg320.dll" และ "opencv_ffmpeg320_64.dll" ลงในโฟลเดอร์นั้น

หลังจากปิดและรีสตาร์ท Spyder รหัสจะทำงาน ฉันไม่แน่ใจว่าวิธีใดในสามวิธีนี้ใช้ได้ผลและฉันขี้เกียจเกินไปที่จะย้อนกลับไปคิดออก แต่มันได้ผลไชโย!


4

ฟังก์ชั่นนี้จะดึงภาพจากวิดีโอด้วย 1 fps โดยในส่วนเพิ่มเติมจะระบุเฟรมสุดท้ายและหยุดอ่านด้วย:

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

สคริปต์ต่อไปนี้จะแยกเฟรมทุกๆครึ่งวินาทีของวิดีโอทั้งหมดในโฟลเดอร์ (ทำงานบน 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)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.