openCV - 2

在這個章節我們將介紹如何運用樹莓派所外接的攝影機,包括如何擷取相片、如何錄影、如何將錄影的資料寫到檔案當中。也介紹如何從檔案當中讀取影片,再將影片分析,例如從影片中篩選出變動程度大於門檻值的區域。
  1. 從攝影機擷取一張影像

  2. cap = cv2.VideoCapture(0)
    ret, frame = cap.read()
    import cv2
    # 選擇第1隻攝影機
    cap = cv2.VideoCapture(0)
    # 從攝影機擷取一張影像
    ret, frame = cap.read()
    # 在圖片上畫一條紅色的對角線,寬度為 5 px
    cv2.line(frame, (0, 0), (255, 255), (0, 255, 255), 5)
    # 寫入圖檔
    cv2.imwrite("oc01.png", frame)
    # 釋放攝影機
    cap.release()
    cv2.destroyAllWindows()
    
  3. 設定/取得擷取影像的尺寸大小

  4. import cv2
    cap = cv2.VideoCapture(0)
    # 設定擷取影像的尺寸大小
    # 800x600, 1024x768, 1280x720(HD720), 1920x1080(HD1080)
    cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
    cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)
    
    def decode_fourcc(v):
      v = int(v)
        return "".join([chr((v >> 8 * i) & 0xFF) for i in range(4)])
    
        # 取得影像的尺寸大小
        w = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
        h = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
        print("Image Size: %d x %d" % (w, h))
        # 取得 Codec 名稱
        fourcc = cap.get(cv2.CAP_PROP_FOURCC)
        codec = decode_fourcc(fourcc)
        print("Codec: " + codec)
        cap.release()
    
    Image Size: 1280 x 720
    Codec: YUYV
    



  5. 開啟影片檔案並且播放

  6. import cv2
    # 開啟影片檔案
    cap = cv2.VideoCapture('firework.mp4')
    # 以迴圈從影片檔案讀取影格,並顯示出來
    while(cap.isOpened()):
        ret, frame = cap.read()
        # 從檔案輸入的影格可以imshow直接顯示
        if(ret): 
            cv2.imshow('frame',frame)
        else: break
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    print('cap done')
    cv2.destroyAllWindows()
    cap.release()
    



  7. 從檔案讀進一個影片,再將影片改為灰階後另存為一個新的影片檔案

  8. import cv2
    cap = cv2.VideoCapture('firework.mp4')
    # 取得影像的尺寸大小
    w = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
    h = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
    # 記得長寬要先改成整數
    print(type(w)); w=int(w); h=int(h)
    print("Image Size: %d x %d" % (w, h))
    # 使用 XVID 編碼
    fourcc = cv2.VideoWriter_fourcc(*'XVID')
    # FPS 值為 20.0,解析度為 w x h
    # 要寫成灰階輸出的檔案必須在長寬(w,h)之後加個零 ,0)
    out = cv2.VideoWriter('oc04d.avi', fourcc, 20.0, (w,h),0)
    while(cap.isOpened()):
      ret, frame = cap.read()
      if ret == True:
        # 轉為灰階並寫入
        frame2 = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        out.write(frame2)
        #cv2.imshow('frame',frame2)
        if cv2.waitKey(1) & 0xFF == ord('q'):
          break
      else:
        break
    # 釋放所有資源
    cap.release()
    out.release()
    cv2.destroyAllWindows()
    



  9. 從影片檔案轉換為圖片檔案-1

  10. import cv2
    vid='FULL15'
    fn=vid+'.mp4'
    cap = cv2.VideoCapture(fn)
    NF=0
    while True:
        ret,frame = cap.read()
        NF+=1
        if(ret): 
            cv2.imshow('frame',frame)
            fw=vid+'_'+str(NF).zfill(3)+'.png'
            cv2.imwrite(fw,frame)
            print(NF,fw)
        else: break
        if cv2.waitKey(1) & 0xFF == ord('q'): break
    print('cap done')
    cv2.destroyAllWindows()
    cap.release()
    



  11. 從影片檔案轉換為圖片檔案-2

  12. import cv2
    import time
    mp4='FULL15'
    sec=23
    dir=mp4+'/FULL15_'
    fn=mp4+'.mp4'
    cap = cv2.VideoCapture(fn)
    fps = cap.get(cv2.CAP_PROP_FPS)
    size = (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)),
            int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
    length = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
    print(fn,': fps=',fps,' size=',size,' sec=',sec,' length=',length)
    fps=int(length/sec); spf=round(sec/length,3)
    ds=0.1; SR=int(ds/spf)
    print( length,'estimated from total length, FR=',fps,' spf=',spf,' SR=',SR)
    
    def FR(cap):
        # Number of frames to capture
        num_frames = 120;
        print("Capturing {0} frames".format(num_frames))
        start = time.time()
        for i in range(0, num_frames) :
            ret, frame = cap.read()
        end = time.time()
        seconds = end - start
        print ("Time taken : {0} seconds".format(seconds))
        fps  = num_frames / seconds
        print("Estimated from 120 frames, fps= : {0}".format(fps))
    FR(cap)
    NR=0; NF=0
    while(cap.isOpened()):
        ret, frame = cap.read()        
        NR+=1
        if(ret): 
            cv2.imshow('frame',frame)
            if(NR%SR==0):
                NF+=1
                cv2.imwrite(dir+str(NF).zfill(3)+".jpg",frame)
                print('NR=',NR,' NF=',NF)
        else: break
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    print('cap done')
    cv2.destroyAllWindows()
    cap.release()
    



  13. 從攝影機擷取影像/video影片儲存寫入檔案

  14. import cv2
    cap = cv2.VideoCapture(0)
    # 設定擷取影像的尺寸大小
    cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
    cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 360)
    # 使用 XVID 編碼
    fourcc = cv2.VideoWriter_fourcc(*'XVID')
    # 建立 VideoWriter 物件,輸出影片至 output.avi
    # FPS 值為 20.0,解析度為 640x360
    out = cv2.VideoWriter('oc04.avi', fourcc, 20.0, (640, 360))
    t=0
    while(t<400 and cap.isOpened()):
      #if(t%100 == 0): print(t)
      ret, frame = cap.read()
      t+=1
      if ret == True:
        # 寫入影格
        out.write(frame)
        #cv2.imshow('frame',frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
          break
      else:
        break
    # 釋放所有資源
    cap.release()
    out.release()
    cv2.destroyAllWindows()
    



  15. OOpenCV/從攝影機擷取影像/儲存寫入video影片到檔案

    • imread("file")
    import cv2
    import time
    cap = cv2.VideoCapture(0)
    # 設定擷取影像的尺寸大小
    cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
    cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 360)
    # 使用 XVID 編碼
    fourcc = cv2.VideoWriter_fourcc(*'XVID')
    # 建立 VideoWriter 物件,輸出影片至 output.avi
    # FPS 值為 20.0,解析度為 640x360
    out = cv2.VideoWriter('output2.avi', fourcc, 20.0, (640, 360))
    t=0
    while(t<400 and cap.isOpened()):
      ret, frame = cap.read()
      if ret == True:
        # 寫入影格
        #print('t=',t,ret)
        out.write(frame)
        #cv2.imshow('frame',frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
          break
      else:
        break
      t+=1
    # 釋放所有資源
    cap.release()
    out.release()
    cv2.destroyAllWindows()
    
     
    



  16. 從檔案中讀取影片再做後續處理,例如彩色轉換成為灰階




  17. 快速篩選監視器影像

  18. import cv2
    cap = cv2.VideoCapture('firework-2.mp4')
    while(cap.isOpened()):
      ret, frame = cap.read()
      frame2=cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
      cv2.imshow('frame',frame2)
      if cv2.waitKey(1) & 0xFF == ord('q'):
        break
    cap.release()
    cv2.destroyAllWindows()
    
    
    
    import cv2
    import numpy as np
    import os
    
    # 影片檔案
    videoFile = "op4B.avi"
    # 輸出目錄
    outputFolder = "my_output"
    # 自動建立目錄
    if not os.path.exists(outputFolder):
      os.makedirs(outputFolder)
    # 開啟影片檔
    cap = cv2.VideoCapture(videoFile)
    # 取得畫面尺寸
    width = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
    height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
    # 計算畫面面積
    area = width * height
    # 初始化平均畫面
    ret, frame = cap.read()
    avg = cv2.blur(frame, (4, 4))
    avg_float = np.float32(avg)
    # 輸出圖檔用的計數器
    outputCounter = 0
    while(cap.isOpened()):
      # 讀取一幅影格
      ret, frame = cap.read()
      # 若讀取至影片結尾,則跳出
      if ret == False:
        break
      # 模糊處理
      blur = cv2.blur(frame, (4, 4))
      # 計算目前影格與平均影像的差異值
      diff = cv2.absdiff(avg, blur)
      # 將圖片轉為灰階
      gray = cv2.cvtColor(diff, cv2.COLOR_BGR2GRAY)
      # 篩選出變動程度大於門檻值的區域
      ret, thresh = cv2.threshold(gray, 25, 255, cv2.THRESH_BINARY)
      # 使用型態轉換函數去除雜訊
      kernel = np.ones((5, 5), np.uint8)
      thresh = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)
      thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=2)
      # 產生等高線
      cntImg, cnts, _ = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
      hasMotion = False
      for c in cnts:
        # 忽略太小的區域
        if cv2.contourArea(c) < 2500:
          continue
        hasMotion = True
        # 計算等高線的外框範圍
        (x, y, w, h) = cv2.boundingRect(c)
        # 畫出外框
        cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
      if hasMotion:
        # 儲存有變動的影像
        cv2.imwrite("%s/output_%04d.jpg" % (outputFolder, outputCounter), frame)
        outputCounter += 1
      # 更新平均影像
      cv2.accumulateWeighted(blur, avg_float, 0.01)
      avg = cv2.convertScaleAbs(avg_float)
    cap.release()
    
    
    



  19. TTTT