【OpenCV+pyqt5】視頻抽幀相關操作


【OpenCV+pyqt5】視頻抽幀相關操作

  • 本文利用OpenCV對視頻進行讀取,並進行抽幀,可指定時間段和抽幀間隔
  • 對視頻進行裁剪,裁剪設定時間段內的視頻
  • 對指定文件夾下的圖像進行視頻轉換

pyqt5搭建界面

界面功能簡介

  • 界面比較簡單,左側顯示視頻,右側提供操作按鈕
  • 視頻下方有進度條(暫時不能調整進度),和后面的時間
  • 右側操作區有三個功能切換,右下方顯示操作進度條

功能測試

  • 視頻抽幀有全部抽幀和時間段抽幀
  • 視頻裁剪根據時間段進行裁剪
  • 圖片轉換成視頻,遍歷文件夾下的所有圖片,根據幀率合成指定視頻名稱
  • 以上三種功能測試均通過

OpenCV功能詳解

讀取視頻並顯示視頻信息

  • 利用cap = cv2.VideoCapture(video_name)進行指定視頻文件的讀取
def _open_video_(self):
    self.video_name = os.path.split(self.video_path_name)[-1]
    if self.video_name.split('.')[-1]not in ['mp4','avi','h264']:
        loggingdata('video name error, {}'.format(self.video_path_name))
        return -1
    self.frame_now = 0
    self.cap       = cv2.VideoCapture(self.video_path_name)
    self.frame_num = int(self.cap.get(7))
    self.FPS       = int(self.cap.get(5))
    self.frame_w   = int(self.cap.get(3))
    self.frame_h   = int(self.cap.get(4))
  • 通過以下命令獲取視頻信息
cap.get(0)	CV_CAP_PROP_POS_MSEC      視頻文件的當前位置(播放)以毫秒為單位
cap.get(1)	CV_CAP_PROP_POS_FRAMES    基於以0開始的被捕獲或解碼的幀索引
cap.get(2)	CV_CAP_PROP_POS_AVI_RATIO 視頻文件的相對位置(播放):0 = 電影開始,1 = 影片的結尾。
cap.get(3)	CV_CAP_PROP_FRAME_WIDTH   在視頻流的幀的寬度
cap.get(4)	CV_CAP_PROP_FRAME_HEIGHT  在視頻流的幀的高度
cap.get(5)	CV_CAP_PROP_FPS           幀速率
cap.get(6)	CV_CAP_PROP_FOURCC        編解碼的4字-字符代碼
cap.get(7)	CV_CAP_PROP_FRAME_COUNT   視頻文件中的幀數

時間轉換函數

  • 通過界面輸入時間00:00:15轉換成秒,【注】這里默認輸入多組時間段
def _time2second(self,start_end_time):
     將輸入的時間轉換成秒 ['00:10:40','00:10:47'] - > [600,900]
  second_time = []
  for span_time in start_end_time:
      start_time = span_time[0].split(':')
      print(start_time)
      start_time = int(start_time[0])*3600 + int(start_time[1])*60 + int(start_time[2])
      end_time = span_time[1].split(':')
      end_time = int(end_time[0])*3600 + int(end_time[1])*60 + int(end_time[2])
      # print(end_time)
      if end_time < start_time:
          return -1
      second_time.append([start_time,end_time])
  return second_time

根據獲得的視頻進行抽幀

  • 抽幀的邏輯是:循環讀取視頻,當前幀如果在指定范圍內,則進行保存,超過范圍則退出;顯然這種方式再截取較長視頻的尾部會很慢。
  • 另外一種邏輯就是利用cap.set(cv2.CAP_PROP_POS_FRAMES,start_frame)指定讀取位置,這種方式較快
  • 但實驗發現.h264利用第二種不能實現定位,每次還是從視頻起點開始讀,所以本例采用前者進行抽幀;
def video2frame(self,method = 0,frame_span = 1,ex_frame_time = [0,10]):
    # 1. 視頻抽幀
    # method = 0 整體抽幀 method = 1 時間段抽幀
    loggingdata('---------------start video2frame---------------------')
    self._open_video_()
    ex_frame_time = [x*self.FPS for x in ex_frame_time] if method == 1 else [0,self.frame_num]
    while True:
        if method == 1 and self.frame_now >= ex_frame_time[1]:
            loggingdata('video2frame save picture number is {},save frame form {} to {}'.format(
                ex_frame_time[1],ex_frame_time[0],self.frame_now))
            break
        success, origin_img = self.cap.read()
        if not success or len(origin_img) < 2:
            break
        self.frame_now +=1
        if self.frame_now%frame_span != 0:
            continue
        if self.frame_now < ex_frame_time[1] and self.frame_now >= ex_frame_time[0]:
            cv2.imwrite(os.path.join(self.img_save_path,self.video_name.split('.')[0])+"_%.6d.jpg"%self.frame_now,origin_img)
    loggingdata('==============save image stop==================')

視頻裁剪

  • 裁剪邏輯:繼承抽幀邏輯,將符合裁剪區域內的圖像寫入cut_video中,幀率默認原視頻,名稱在原名稱上增加裁剪起始幀
def cut_video(self,save_fps = 20,cut_frame_time = [0,10]):
    self._open_video_()
    save_fps = self.FPS
    cut_frame_time = [x*self.FPS for x in cut_frame_time]
    cut_video = cv2.VideoWriter(os.path.join(self.cut_video_save_path,self.video_name.split('.')[0])+\
        '_'+str(cut_frame_time[0]) + '.mp4', cv2.VideoWriter_fourcc('M','P','E','G'), save_fps, (self.frame_w,self.frame_h))
    while self.frame_now < cut_frame_time[1]:
        success, origin_img = self.cap.read()
        if not success or len(origin_img) < 2 or self.frame_now >= cut_frame_time[1]:
            break
        self.frame_now +=1
        # print(self.frame_now)
        if self.frame_now > cut_frame_time[0] and self.frame_now < cut_frame_time[1]:
            cut_video.write(origin_img)
    print('cut end')
    cut_video.release()

圖片轉視頻

  • 和視頻裁剪類似,只是將前半段的視頻讀取替換成圖片
def img2video(self,save_fps = 20):
  img_h = 0
  img_w = 0
  for img_name in os.listdir(self.img_files):
      if img_name.split('.')[-1] not in ['bmp','jpg','jpeg','png']:
          continue
      tmp_img = cv2.imread(os.path.join(self.img_files,img_name))
      img_h = tmp_img.shape[0]
      img_w = tmp_img.shape[1]
      break
  img2video = cv2.VideoWriter(self.video_save_path, cv2.VideoWriter_fourcc('M','P','E','G'), save_fps, (img_w,img_h))
  for img_name in os.listdir(self.img_files):
      if img_name.split('.')[-1] not in ['bmp','jpg','jpeg','png']:
          continue
      tmp_img = cv2.imread(os.path.join(self.img_files,img_name))
      img2video.write(tmp_img)
  img2video.release()

暫存問題

    1. 讀取h264時獲取的視頻總幀數出現異常-192153584101141,導致不能正常顯示視頻進度條與處理進度
    1. 圖片轉視頻,后續需要優化,將遍歷圖片顯示在界面

https://www.cnblogs.com/wangxiaobei2019/p/14784678.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM