Python - Video Karelerini Ayıklama ve Kaydetme


135

Bu yüzden bu öğreticiyi takip ettim ama hiçbir şey yapmıyor gibi görünüyor. Basitçe hiçbir şey. Birkaç saniye bekler ve programı kapatır. Bu kod ile ilgili yanlışlık nedir?

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

Ayrıca yorumlarda bunun kareleri 1000 ile sınırladığını söylüyor? Neden?

DÜZENLEME: success = TrueÖnce yapmayı denedim ama bu yardımcı olmadı. Yalnızca 0 baytlık bir görüntü oluşturdu.


1
Değeri nedir success?
101

2
Nedir değeri ? Tipi boolean olabilir, ama öyle Trueya False?
That1Guy

1
Evet, ama ne sizin değeri? Yanlış olabilir ve bu durumda programınız "birkaç saniye bekleyip kapanır". Başka bir deyişle, bir print successyere ekleyin .
101

1
Zorlamak mantıklı değil success; yanlışsa, bu, video okumasının bir nedenle başarısız olduğu anlamına gelir. Önce biraz çalışmalısın.
101

1
Okumanız başarısız oluyor. Eğitimde anlatıldığı gibi python ve ffmpeg ile opencv oluşturdunuz mu? brew install opencv --python27 --ffmpegPython'un farklı bir sürümünü kullanıyorsanız kendi sürümünüze değiştirmeniz gerekecektir.
matem çanı

Yanıtlar:


228

Gönderen burada bu indirmek videoyu biz test için aynı video dosyası var bu yüzden. Bu mp4 dosyasının python kodunuzla aynı dizinde olduğundan emin olun. Sonra da python yorumlayıcısını aynı dizinden çalıştırdığınızdan emin olun.

Ardından kodu değiştirin, waitKeyzaman kaybına neden olan bir pencere olmadan da klavye olaylarını yakalayamaz. Ayrıca success, kareleri başarılı bir şekilde okuduğundan emin olmak için değeri yazdırıyoruz .

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

Bu nasıl gidiyor?


4
Bu boş bir jpeg dosyasını kaydeder ve döndürürRead a new frame: False

3
Bu, opencv'nin videoyu okuyamayacağı anlamına gelir. Büyük olasılıkla ffmpeg'e erişemiyor. hangi işletim sistemini kullanıyorsun?
itfaiye


3
Google'a özel opencv sürümünüz için talimatlar verin ve ffmpeg ve opencv-python'un Windows üzerinde nasıl çalıştığını tam olarak izleyin.
itfaiye

3
Bu yüzden uyumluluk sorunumu çözmek için bu soruyu kullandım . DLL'yi opencv_ffmpeg300.dll olarak yeniden adlandırmak zorunda kaldım (OpenCV2'nin Python kurulumu 3.0.0 idi). Python dizinime (C: \ Python27) yerleştirdim. Ffmpeg veya opencv'nin windows sürümünü yüklememe gerek yoktu, ancak OpenCV ile birlikte gelen o DLL'ye ihtiyacım vardı, ancak bundan sonra OpenCV'nin geri kalanını sildim. Her neyse, bunu bir cevap olarak seçeceğim, ancak bunu okuyan herkes bu ESSENTIAL DLL hakkında bilgi sahibi olmalı.

37

Bu soruyu genişletmek için (ve @ user2700065 tarafından yanıtlanarak) biraz farklı durumlar için, herhangi biri her kareyi çıkarmak istemiyor ancak her saniyede bir kare çıkarmak istiyorsa. Yani 1 dakikalık bir video 60 kare (görüntü) verecektir.

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)

Ben kullanıyorum opencv-2.4.9böylece yerine, cv2.CAP_PROP_POS_MSECI kullanmak zorundacv2.cv.CAP_PROP_POS_MSEC
Pratik Kumar

1
Çerçevelerin her 5 saniyede olmasını istersem kodu nasıl değiştirebilirim?
Soumya Boral

1
@SoumyaBoralcount = count + 5
Bhushan Babar

@BhushanBabar cv2.imwrite(), döngüden cv2.imread()önce aradığınızdan beri döngünün başında olmamalı mı?
mLstudent33

@ mLstudent33 üzgünüm, anlamadım, lütfen detaylandırın.
Bhushan Babar

12

Bu, @ GShocked'dan python 3.x için önceki yanıttan bir değişiklik, yoruma gönderirdim, ancak yeterli itibarım yok

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

Bu, video formatlarının çoğunu videoda bulunan kare sayısına dönüştüren İşlevdir. O çalışır Python3ileOpenCV 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)

Bu destekler .mtsve normal dosyalar gibi .mp4ve .avi. .mtsDosyalar üzerinde denendi ve test edildi . Tıkır tıkır çalışıyor.


8

Çerçevelerin videoya nasıl dönüştürüleceğine dair birçok araştırmadan sonra, bu işlevi yarattım, bunun yardımcı olacağını umuyorum. Bunun için opencv'ye ihtiyacımız var:

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 değerini (saniyedeki kare sayısı), girdi klasörü yolunu ve çıktı klasörü yolunu kendi yerel konumlarınıza göre değiştirin


files.sort (key = lambda x: int (x [5: -4])) YUKARIDAKİ ÇİZGİ EKLEMEK, kareleri dizeye göre değil sayıya göre sıralamanıza yardımcı olur örn: başlangıçta frame1.jpg ardından frame10.jpg geldi frame2.jpg değil, yukarıdaki satır dosyaları içindeki sayılara göre sıralar.
Puja Sharma

3
Soru videodan kareye idi
Santhosh Dhaipule Chandrakanth

videoyu benim için herhangi bir nedenle kaydetmemek
Raksha

7

Önceki cevaplar ilk çerçeveyi kaybetti. Ve resimleri bir klasörde saklamak güzel olacak.

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

Bu arada, çerçeve oranını VLC ile kontrol edebilirsiniz . Windows -> medya bilgileri -> codec ayrıntılarına gidin


Çıkarma sırasında kare hızını artırmanın bir yolu var mı?
Pratik Khadloya

Hayır. Bir video çekildiğinde kare hızı sabitlenir. Bundan daha fazlasını çıkaramazsınız.
Yuchao Jiang

Ne harika bir cevap. Benim için mükemmel çalıştı. Koddaki döngüyü, yalnızca belirli bir aralıktaki kare 120-160 gibi kareleri alacak şekilde ayarlamanın bir yolu olabilir mi? Teşekkürler!
Bowen Liu,

Ayıklamak istediğiniz kareleri belirtmek için değişken sayımını kullanabilirsiniz.
Yuchao Jiang

Videodan çıkarmak istersem, videonun başından video sonuna kadar zaman içinde eşit uzaklıkta konumlandırılmış 15 kare diyelim ki ne yapmalıyım? Kullanmam gerektiğini öğrendim cv.CAP_PROP_POS_AVI_RATIOama nasıl yapacağımı bilmiyorum. tnx
NeStack

7

Bu kod, videodan kareleri çıkarır ve kareleri .jpg formatında kaydeder

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'u Anaconda'nın Spyder yazılımı aracılığıyla kullanıyorum. Bu iş parçacığının sorusunda @Gshocked tarafından listelenen orijinal kodu kullanarak, kod çalışmaz (python mp4 dosyasını okumaz). Bu yüzden OpenCV 3.2'yi indirdim ve "opencv_ffmpeg320.dll" ve "opencv_ffmpeg320_64.dll" yi "bin" klasöründen kopyaladım. Bu dll dosyalarının ikisini de Anaconda'nın "Dlls" klasörüne yapıştırdım.

Anaconda'nın bir de "pckgs" klasörü var ... İndirdiğim "OpenCV 3.2" klasörünün tamamını kopyalayıp Anaconda "pckgs" klasörüne yapıştırdım.

Son olarak, Anaconda'nın bir "bin" alt klasörü olan bir "Kitaplık" klasörü vardır. "Opencv_ffmpeg320.dll" ve "opencv_ffmpeg320_64.dll" dosyalarını bu klasöre yapıştırdım.

Spyder'ı kapatıp yeniden başlattıktan sonra kod çalıştı. Üç yöntemden hangisinin işe yaradığından emin değilim ve geri dönüp çözemeyecek kadar tembelim. Ama öyle çalışıyor, şerefe!


4

Bu işlev 1 fps ile videodan görüntüleri çıkarır, EK OLARAK son kareyi tanımlar ve ayrıca okumayı durdurur:

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

Aşağıdaki komut dosyası, klasördeki tüm videoların her yarım saniyesinde bir kare çıkaracaktır. (Python 3.7'de çalışır)

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)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.