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)
    cv2.imshow('frame',frame)
    if cv2.waitKey(6000) & 0xFF == ord('q'): pass
    # 釋放攝影機
    cap.release()
    cv2.destroyAllWindows()
    
  3. 從攝影機擷取一張影像+矩形框圖

  4. cap = cv2.VideoCapture(0)
    ret, frame = cap.read()
    import numpy as np
    import cv2
    
    cap = cv2.VideoCapture(0)
    ret, frame = cap.read()
    cv2.line(frame, (0, 0), (255, 255), (0, 255, 255), 5)
    cv2.imwrite("YCC_1.png", frame)
    cv2.imshow('frame',frame)
    if cv2.waitKey(2000) & 0xFF == ord('q'): pass
    cap.release()
    cv2.destroyAllWindows()
    
    
    for i in range(10):
        x1=50+50*i; x2=x1+100
        y1=200; y2=300
        print(i,(x1,y1),(x2,y2))
        img=np.copy(frame)
        cv2.rectangle(img, (x1, y1), (x2, y2), (255, 0, 0), 2)
        cv2.imshow('img',img)
        if cv2.waitKey(3000) & 0xFF == ord('q'): break
    cv2.destroyAllWindows()
    
  5. 設定/取得擷取影像的尺寸大小

  6. 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
    



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

  8. firework-2.mp4

    import cv2 cap = cv2.VideoCapture('firework-2.mp4') while(cap.isOpened()): ret, frame = cap.read() if(ret==False): break cv2.imshow('frame',frame) if cv2.waitKey(1) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows() print('cv2 done')



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

  10. import cv2
    cap = cv2.VideoCapture('firework-2.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.mp4', 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()
    



  11. 從攝影機擷取影像並使用imshow

  12. import cv2
    cap = cv2.VideoCapture(0)
    t=0
    while(t<500 and cap.isOpened()):
        ret, frame = cap.read()
        if cv2.waitKey(1) & 0xFF == ord('q'): break
        cv2.imshow('frame',frame)
        t+=1
        if(t%100==0): print(t)
    cap.release()
    cv2.destroyAllWindows()
    



  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('cam_1.mp4', fourcc, 20.0, (640, 360))
    t=0
    while(t<200 and cap.isOpened()):
      if(t%50 == 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. 快速篩選監視器影像

  16. 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()