Feature dection

SIFT尺度不變特徵轉換 影像中的局部特徵

  1. 偵測
  2. 描述

視訊分析

week2_introduction

Digitization數位化:用3步驟,將float像素值數位化為數位影像

  1. Sampling : 將時間軸離散化
  2. Quantization 量化 : 將振幅軸切割成有限的位階(level),將 振幅軸離散化,浮點數變成整數
  3. Coding : 整數值編成二元碼

物體經由鏡片投影產生影像(連續的),

生成取樣影像(像素位置是離散的、色彩值是連續的),量化將色彩值轉為離散數值

取樣(產生離散的位置x,y)+量化(每個位置得到離散的色彩值0~255)=數位影像可表示為二維矩陣,矩陣中的每一個元素稱為 像素 I(x,y) MxN矩陣>> x=0M-1;y=0N-1 有M個row + N個colum

數位影像的品質:

  • 取樣決定空間解析度
  • 量化決定色彩解析度 R,G,B = 分別為256 level(8 bit)

數位影像的類別:由量化(bit)數決定

  • Binary 二值影像(1 bit):0 or 1
  • Gray-level(1 byte = 8bit):0~255
  • True-Color(3 byte):255^3=16.7M colors
  • Indexed-color(log2n bit)索引全彩影像,用較少的bit表示彩色影像

week3_Image_Read、Show、Write

  • cv2.imread() 同個目錄下'name.jpg';其他目錄:'檔案路徑';0:gray imge/1:color/-1:alpha channel
  • cv2.imshow()
  • cv2.imwrite()
import cv2 //使用openCV img=cv2.("pohot_name",-1) // -1:用灰階 讀入圖片(放在同目錄下)放到陣列img裡 cv2.imshow("wondows_name",img) //開視窗 秀圖片img cv2.waitkey(0) //等待輸入的指令(字母)/延遲X秒後結束 0:無限秒 cv2.destroyAllWindows() //關閉所有視窗

cv2.waitKey(delay) 接受一個按鈕事件並返回按鈕的ASCII碼; delay=1000:延遲1秒 0:延遲時間無窮大 cv2.destroyWindow(winname) 關閉某視窗 e.g.

超過0~255範圍 會不自然

圖片的型態img.shape :秀出圖像的長垂直、寬水平、色彩(灰階1 黑白2 彩色3)

print("color_img_shap",img.shap)

cv2.imwrite("outname.jpg",img) 存檔,搭配 cv2.waitkey(0)使用-按某鍵存檔:

​k=cv2.waitkey(0) ​... ​if k==ord('s') //ord('c')==char()一個字母 回傳ASCII碼 ​ cv2.imwrite("outname.jpg",img)

單獨秀出某通道的圖像

Python openCV uses BGR mode 顯示各個通道的圖像

  • b,g,r=cv2.split(img) 把3種通道分割開來
  • img2=cv2.merge(b,g,r) 合併成3種通道(彩色影像)
  • cv2.imgshow()

先切割BGR的通道>>有三個 長*寬 的矩陣,裡面分別放0~255的數字 單獨抓某個通道會是灰階圖片

cv2.imshow('single_green_channel', g)
#display single channel (regard as gray-level image)

所以要把其他兩個通道清空(放0),再與某通道合併,才能呈現單獨某色的圖像

img = cv2.imread( "WIN_20230302_13_18_26_Pro.jpg") b,g,r = cv2.split(img) #分割成3種通道b,g,r if img is None: sys.exit("could not read photo.") cv2.imshow( "Example", img ) b[:]=0 #b矩陣清空放0 g[:]=0 r_color=cv2.merge((b,g,r)) k=cv2.waitKey( 0 ) if k==ord("s"): cv2.imshow( "R_color",r_color ) k=cv2.waitKey( 0 ) if k==ord("a"): cv2.destroyAllWindows( ) print("color_img_shap",img.shape) cv2.destroyAllWindows( ) print("done.")

week4_video

cap=cv2.VideoCapture(0) create攝影機物件object

  • 0:預設第一隻 1:第二隻 2:第三隻
  • 一幀一幀(frame by frame)的捕捉攝像頭

ret,frame=cap.read() 回傳兩個值(bool/numpy.array)

  • ret:True正確取幀(沒有漏掉)或 False
  • frame:下一張影像的矩陣

cap.release() 釋放幀;關閉攝影機

cap.isOpened()檢查攝影機是否啟動 cap.open()開啟攝影機

cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)將影像轉成灰階

#HW22目的:用攝影機捕捉1.全彩視訊、2.紅色、3.藍綠交換 cap=cv2.VideoCapture(0) while True: #在無窮迴圈裡一直秀圖片>>影片串流 ret,frame=cap.read() if not ret: #如果是flase(不正常取幀) print("can't recive frame") break cv2.imshow('frame',frame) #秀出全彩影片串流 b,g,r=cv2.split(frame) #分割三種通道 temp=b #把blue green通道交換 b=g g=temp exchange=cv2.merge((b,g,r)) #合併 cv2.imshow('exchange',exchange) b[:]=0 #清空(秀紅色通道) g[:]=0 r_color=cv2.merge((b,g,r)) cv2.imshow('R_color',r_color) if cv2.waitKey(1)==ord('q'): #按Q結束 cap.release() #釋放幀 cv2.destroyAllWindows() break

儲存影片

cv2.VideoWriter(output_name,int fourcc,fps,size,全彩:true or flase)

  • 檔名
  • 壓縮的方式compress the frames: DIVX(Windows建議使用) 、XVID..
  • fps每秒幀數
  • 寬width、高heigt ex.640*480
  • true:color false:gray
fourcc= cv2.VideoWriter_fourcc('DIVX')// 設定儲存的格式 out=cv2.VideoWriter(output_name,fourcc,20.0,(680,480))

Numpy

x=np.array([ [1,2,3],[4,5,6] ])

陣列屬性:

  • np.ndim維度
  • np.shap外型 #(row,column)
  • np.size大小
  • np.dtype資料內容:(unit8)

陣列±* /運算: element-wise:*/是一個元素對一個元素運算

  • np.multiply() 一個一個相乘

  • C=np.transpose (B) 一般矩陣乘法:要先轉置 讓基底相同 result_1= np.matmul (A , C) 矩陣相乘

元素都是0的矩陣 np.zeros(shape,dtype =float) 元素都是1的矩陣 np.ones(shape,dtype =float)

隨機陣列 np.random.randint(low最小值(含),high(不含),size維度,dtype=int)

#創造隨機矩陣,隨機給r、g、b的值,單獨秀出r、g灰階影像與三種通道的影像 import numpy as np import cv2 import sys import random r=np.random.randint(20,255,size=(300,300),dtype=np.uint8) g=np.random.randint(20,255,size=(300,300),dtype=np.uint8) b=np.random.randint(20,255,size=(300,300),dtype=np.uint8) //uint8 沒有符號int 8bit img2=cv2.merge((b,g,r)) #三種通道都有(彩色) img1=cv2.add(r,g) #兩矩陣相加(還是一個通道)(灰階) cv2.imshow('rgb',img2) cv2.imshow('gray',img1) cv2.imshow('r',r) cv2.imshow('g',g) k=cv2.waitKey(0) if k==ord("a"): #按A結束 cv2.destroyAllWindows( )

e.g. 20x40的黑色區域

import numpy as np import cv2 global img filename = input( "Please enter filename: " ) #輸入圖片檔名 img = cv2.imread( filename, -1 ) cv2.namedWindow( filename ) #cv2.setMouseCallback( filename, onMouse ) 用滑鼠 cv2.imshow( filename, img ) x=input( "Please enter X: " ) y=input( "Please enter Y: " ) for i in range(20): #用雙層迴圈 i:row的數量 南北向 for j in range(40): #j:colum數 東西向 img[int(x)+i,int(y)+j]=[0,0,0] cv2.imshow( filename, img ) k=cv2.waitKey(0) if k==ord("a"): cv2.destroyAllWindows( )

HW23.用內建的相機捕捉20秒的影片並儲存.

cv2.getTickCount ()函數向我們返回從參考事件發送到調用cv2.getTickCount()函數的時間的時鐘信號計數。

要計算代碼塊執行的時間,我們可以使用cv2.getTickCount()在代碼塊的開頭和結尾計算時鐘信號的數量,並將其差值除以頻率,可以使用cv2.getTickFrequency ()函數。

cv2.getTickCount() 計算兩次getTickCount()之間的時鐘數量/頻率 cv2.getTickFrequency () =時間

import cv2 cap=cv2.VideoCapture(0) #width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) # 取得影像寬度 #height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) # 取得影像高度 fourcc= cv2.VideoWriter_fourcc(*'mp4v') # 設定儲存的格式 out=cv2.VideoWriter('01.mp4',fourcc,30.0,(640,480))#產生空的影像檔 capture_time = 20.0 #設定影片時長 start_time = cv2.getTickCount() #開始計時 while True: ret,frame=cap.read() if not ret: print("can't recive frame") break cv2.imshow('frame',frame) out.write(frame) #把frame放入影像檔內 elapsed_time = (cv2.getTickCount() - start_time) / cv2.getTickFrequency() #結束時間=(結束-開始)/頻率 if elapsed_time >= capture_time or cv2.waitKey(1) == ord('q'): break cap.release() out.release() cv2.destroyAllWindows() #還是無法固定影片儲存的時長,可能被執行時間/電腦效能影響(會越跑越短)

e.g.呈上,再秀出b、g、r三種通道的影像 np.zeros_like(matrix) 創造與matrix相同形狀的矩陣,但元素皆是0 cap.get(cv2.CAP_PROP_FRAME_WIDTH) 捕捉相機長寬

#用內建相機分別捕捉(全彩/R/G/B)四種通道並儲存20秒的影片 import cv2 import numpy as np cap=cv2.VideoCapture(0) fourcc= cv2.VideoWriter_fourcc(*'mp4v') # 設定儲存的格式 width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))#用cap.get()捕捉攝影機的規格 height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) out_color=cv2.VideoWriter('01_merge.mp4',fourcc,30.0,(width,height))#產生空的影像檔 out_g=cv2.VideoWriter('01_g.mp4',fourcc,30.0,(width,height)) out_b=cv2.VideoWriter('01_b.mp4',fourcc,30.0,(width,height)) out_r=cv2.VideoWriter('01_r.mp4',fourcc,30.0,(width,height)) capture_time = 20.0 #設定影片時長 start_time = cv2.getTickCount() #開始計時 while True: ret,frame=cap.read() if not ret: print("can't recive frame") break b,g,r=cv2.split(frame)#切割成三種通道 matrix=np.zeros_like(b)#創造一個跟b大小相同、元素都是0的矩陣 r_color=cv2.merge((matrix,matrix,r))#合併 g_color=cv2.merge((matrix,g,matrix)) b_color=cv2.merge((b,matrix,matrix)) out_color.write(frame) #把frame放入影像檔內 out_g.write(g_color) out_r.write(r_color) out_b.write(b_color) cv2.imshow('frame',frame)#秀出來 cv2.imshow('b_color',b_color) cv2.imshow('g_color',g_color) cv2.imshow('r_color',r_color) key=cv2.waitKey(1) elapsed_time = (cv2.getTickCount() - start_time) / cv2.getTickFrequency() #結束時間=(結束-開始)/頻率 if elapsed_time >= capture_time or key== ord('q'): break cap.release()#釋放資源 out_color.release() out_g.release() out_b.release() out_r.release() cv2.destroyAllWindows()

week5_OpenCV基礎影像操作

ROI:region-of-interest img[200:300,400:500] >>> X:200~300 Y:400~500 之間的範圍

image blending影像融合

cv2.addWeighted(img1,a,img2,i-a,gamma) 影像融合(兩張圖片大小要相同)

#影像融合 用a透明度讓影像漸變到另一張 import numpy as np import cv2 img1=cv2.imread("test1.png")#圖片大小要一樣 img2=cv2.imread("test2.png") i=0.00 while True: i=i+0.01 dst=cv2.addWeighted(img1,i,img2,1-i,50) cv2.imshow("dst",dst) print("a=",i) k=cv2.waitKey(10)#等待時間1000:1秒 if k==ord('s') or i>=1: cv2.destroyAllWindows()#最後關掉所有視窗 break

在影像上畫圖

  • cv2.line()
    • ( img,(x1,y1),(x2.y2),(B,G,R),Thickness粗細 )
  • cv2.circle()
    • -1:填滿
  • cv2.rectangle() 矩形
  • cv2.ellipse() 橢圓
  • cv2.putText()
#HW33圖中心畫綠色圓+對角紅色線 import cv2 import numpy as np img1=cv2.imread("test1.png") x,y,z=img1.shape#影像大小 垂直高度/水平寬度/通道數量 print(x,y) cv2.line(img1 ,(0,0),(y-1,x-1),(0,0,255),5) cv2.line(img1 ,(0,x),(y,0),(0,0,255),5) cv2.circle(img1,(int(y/2),int(x/2)),100,(0,255,0),-1) #(int(y/2):避免不能整除產生小數點 cv2.imshow("draw",img1) k=cv2.waitKey(0) cv2.destroyAllWindows()

Color Space色彩空間

  • RGB:亮度彩度混在一起
    • opencv使用BGR(順序不同喔)
  • HSV:
    • 彩度Hue: in opencv的範圍[0,179]
    • 飽和度Saturation:how far is the color from gray [0,255]
    • 亮度Value: [0,255]
  • YCrCb
    • Y:亮度分量
    • Cr-Cb:彩度
  • 色彩空間
    • 分割:
      • h,s,v=cv2.splite(img)
      • y,cr,cb=cv2.split(img)
    • 轉換:
      • cv2.cvtColor(bgr,cv2.COLOR_BGR2HSV)
      • cv2.cvtColor(bgr,cv2.COLOR_BGR2YCR_CB)

正規化

  • 制定一個標準或算法,使其有可信的比較基準
  • r=R/(R+G+B)、G/(R+G+B)、B/(R+G+B)
    • b=1-g-r,r+g+b=1

滑桿

cv2.createTrackbar('滑桿名稱','windows_name',min,max,Fn) 在視窗上產生滑桿 滑動時執行Fn程式 cv2.getTrackbarPos('滑桿名稱','視窗名稱') 取得滑桿的位置

week6_Color Object Dection and Tracking

創造遮罩

cv2.bitwise_and(frame,frame,msak=mask)

  • 做bit_and運算
  • mask=mask:要提取的範圍
  • frame :執行運算的原始影像
#將輸入影像和遮罩做bit_and二進位AND運算。只保留在遮罩範圍內的畫素值 import cv2 as cv2 def image_and(image,mask): #輸入影像和遮罩 area = cv2.bitwise_and(image,image,mask=mask) #不打mask的話就是算兩張圖片的交集 cv2.imshow("area",area) return area

cv2.inRange(img,lowerb,upperb) 抓取特定範圍的顏色

  • img輸入的影像
  • 色彩範圍最低數值
  • 色彩範圍最高數值

#color object dection
#捕捉影片中的藍色部分
import cv2
import numpy as np
cap = cv2.VideoCapture('blue_object_video.mp4')
while True:
    ret, frame = cap.read()
    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)#轉成hsv
    
    lower_blue = np.array([110, 50, 50])#設定遮罩範圍(已知HSV中藍色的範圍
    high_blue = np.array([130, 255, 255])
    mask = cv2.inRange(hsv, lower_blue, high_blue)
    res = cv2.bitwise_and(frame, frame, mask=mask)
    
    cv2.imshow('frame',frame)
    cv2.imshow('mask',mask)
    cv2.imshow('res',res)
    
    if cv2.waitKey(100) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

skin color dection

  • range:
    • BGR:[0,20,70]~[230,255,255]
    • HSV:[0,20,70]~[20,255,255]
    • TCrCb: [0,135,85]~[255,180,135]
#skincolor_HSV vs YCrCb import cv2 import numpy as np cap = cv2.VideoCapture(0) # 定義設定HSV和YCrCb顏色範圍的變數 lower_hsv = (0, 20, 70) upper_hsv = (20, 255, 255) lower_YCbCr = (0, 138, 85) upper_YCbCr = (255, 173, 133) # 不斷從攝影機讀取影像 while True: # 讀取影像 ret, frame = cap.read() # 如果影像讀取失敗則退出迴圈 if not ret: break # 轉換影像色彩空間為YCrCb、HSV frame_YCrCb = cv2.cvtColor(frame, cv2.COLOR_BGR2YCR_CB) frame_hsv=cv2.cvtColor(frame,cv2.COLOR_BGR2HSV) # 膚色偵測(使用HSV) mask_hsv = cv2.inRange(frame_hsv, lower_hsv, upper_hsv) res_hsv = cv2.bitwise_and(frame, frame, mask=mask_hsv) # 膚色偵測(使用YCrCb) mask_YCbCr = cv2.inRange(frame_YCrCb, lower_YCbCr, upper_YCbCr) res_YCbCr = cv2.bitwise_and(frame, frame, mask=mask_YCbCr) cv2.imshow('HSV Skin Detection', res_hsv) cv2.imshow('YCbCr Skin Detection', res_YCbCr) if cv2.waitKey(1) == ord('q'): break cap.release() cv2.destroyAllWindows()

week7_Geometric Image Transformation幾何變化

Scaling、Translation、Rotation

齊次座標 :X、Y方向之外 再加一個分量 ,讓所有變換都可以透過矩陣乘法來表示 變換矩陣 transformation matrix 來達成(矩陣乘法)

  • 縮放

  • 平移 沿(x,y)方向移動:移動量(tx,ty)

    1. 用numpy建構M矩陣(變換矩陣translate matrix)
      • np.float32([ [1,0,100],[0,1,50] ])
    2. 傳給 cv2.warpAffine(img,M,(clos,rows) ) 執行變換
      • (cols,rows)輸出影像的大小(width水平寬,height垂直高)
import cv2 import numpy as np img=cv2.imread("img_name.jpg",0) rows,cols=img.shape #用img.shape取得影像大小(垂直高/水平寬/通道) M=np.float32([ [1,0,100],[0,1,50] ]) #創造變換矩陣M,移動量:(100,50) dst=cv2.warpAffine(img,M,(cols,rows)) cv2.imshow('img',dst) cv2.waitKey(0) cv2.destroyAllWindows()
  • 旋轉Rotation
    1. 旋轉角度Θ,使用旋轉矩陣
    2. cv2.getRotationMatrix2D( (x,y),Θ,比例)
      • 旋轉中心(x,y)
      • 旋轉角度:逆時針為正、順時針為負
      • 比例
import cv2 import numpy as np img=cv2.imread("img_neme.jpg",0) rows,cols=img.shape[0:2] #用img.shape取得影像大小(垂直高/水平寬/通道) M=cv2.getRotationMatrix2D( (cols/2,rows/2),90,1) #創造旋轉矩陣, dst=cv2.warpAffine(img,M,(cols,rows)) cv2.imshow('img',dst) cv2.waitKey(0) cv2.destroyAllWindows()

剪切Shear

將圖像在在水平垂直方向剪切,實現扭曲和變形

直方圖

np.reval()降維:多維降成1維

w11

捲積

#edge dection import numpy as np import cv2 cap=cv2.VideoCapture(0) while True: ret,frame=cap.read() frame=cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY) lo=cv2.Laplacian(frame,cv2.CV_64F) sobelx=cv2.Sobel(frame,cv2.CV_64F,1,0,ksize=5) sobely=cv2.Sobel(frame,cv2.CV_64F,0,1,ksize=5) cv2.imshow('frame',frame) cv2.imshow("lo",lo) cv2.imshow("sx",sobelx) cv2.imshow("sy",sobely) if cv2.waitKey(1)==ord('s'): break cv2.destroyAllWindows cap.release()
#canny邊緣偵測 #用滑桿控制上下範圍 import cv2 cap = cv2.VideoCapture(0) # 設定攝影機為640x480 cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) def Fn(): print("good") x=50 y=200 cv2.namedWindow('frame') cv2.createTrackbar("x","frame",40,80,Fn) cv2.createTrackbar("y","frame",100,200,Fn) while True: ret, frame = cap.read() if not ret: break gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 使用高斯模糊降噪 blur = cv2.GaussianBlur(gray, (5, 5), 0) # 邊緣檢測 edges = cv2.Canny(blur, x, y) x=cv2.getTrackbarPos('x',"frame") y=cv2.getTrackbarPos('y',"frame") cv2.imshow('frame', edges) if cv2.waitKey(1) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows()

W12

前處理:二值化

W15形態學

1. dilation 膨脹(平移+聯集)

A是原始影像 B是結構化元素(可以自行定義)

2. erosion 侵蝕(A-B)

cv2.erode(ing,kernel,iterations=1)

opening 開運算/整形(侵蝕+膨脹)

可以用來 去除雜訊

cv2.morphologyEx(img,cv2.MORPH_OPEN,kernel)

例:

closing 閉運算(膨脹+侵蝕)

可以用來 捕小洞

cv2.morfhologyEx(img,v2.MORPH_CLOSE,kernel)

自定義結構化元素

  • 矩形 cv2.getStructuringElement(cv2.MORPH_RECT(5,5))

  • 橢圓

  • 十字形

convolution捲積

image 功能:

  • 補洞、去雜訊 平滑化smoothing