【OpenCV】使用筆記

OpenCV使用疑難點記錄

樓主推薦的opencv中文教程的學習
opencv-python原版教程

基本概念

  • using namespace cv:如果希望不要每次都輸入 cv:: ,則可使用這個語句
  • IplImage和Mat的區別:IplImage使用的是C結構,而Mat使用的是C++結構,前者需要手動釋放內存,後者不需要。而Mat 是 OpenCV 中用來表示圖像的多維數組,類似 tensorflow 和 pytorch 中的 tensor。
  • cv2.imread讀取的RGB圖片是BGR格式的,這是因爲但是流行,所以一直沿用下來了哈哈哈哈哈哈哈
  • cv2.cvtColor(image, cv2.COLOR_BGR2RGB),不同顏色的格式的轉換
  • 灰度轉換公式 = 0.2126 * R + 0.7152 * G + 0.0722 * B
  • HSV:色調(H),飽和度(S),明度(V)參考鏈接

Gui 特性

  • 先創建一個窗口,之後再加 載 圖 像。這種情況下,你可以決定窗口是否可以調整大小。 使用到函數是cv2.namedWindow()。 初 始 設 定 函 數標 籤 是 cv2.WINDOW_AUTOSIZE。 但是如果你把標 籤改成cv2.WINDOW_NORMAL,你就可以調整窗口大小了。當圖像維度太大,或者要添加軌跡條時,調整窗口大小將會很有用。
  • 視頻的調用:cv2.VideoCapture(0)一般爲零就是調用本機的攝像頭,也可以調用本地的視頻文件
  • 窗口滑條的使用:cv2.getTrackbarPos()  第一個參數是滑動條的名字;第二個參數是滑動條被放置窗口的名字;第三個參數是滑動條的默認位置;第四個參數是滑動條的最大值;cv2.setMouseCallback返回鼠標的操作

核心操作

  • 爲圖像擴邊(填充): cv2.copyMakeBorder()
  • 圖像混合和加法:加法cv2.add(x,y),混合:cv2.addWeighted,兩者本質也是加法,只是兩幅圖的權重不同,混合後會形成透明效果
  • 效率檢測:cv2.getTickCount 函數返回從參考點到這個函數被執行的時鐘數。所以當你在一個函數執行前後都調用它的話,你就會得到這個函數的執行時間(時鐘數)。cv2.getTickFrequency 返回時鐘頻率,或者說每秒鐘的時鐘數。所以你可以按照下面的方式得到一個函數運行了多少秒。
  • 圖像放縮:cv2.resize:1)INTER_NEAREST - 最近鄰插值法,2)INTER_LINEAR - 雙線性插值法(默認),3)INTER_AREA - 基於局部像素的重採樣(resampling using pixel area relation)。對於圖像抽取(image decimation)來說,這可能是一個更好的方法。但如果是放大圖像時,它和最近鄰法的效果類似。,4)INTER_CUBIC - 基於4x4像素鄰域的3次插值法,5)INTER_LANCZOS4 - 基於8x8像素鄰域的Lanczos插值
  • 平移: 構造平移矩陣傳給:cv2.warpAffine()
    在這裏插入圖片描述
  • 旋轉:(默認是逆時針哦)在這裏插入圖片描述
    構造旋轉矩陣M=cv2.getRotationMatrix2D((cols/2,rows/2),45,0.6)
    dst=cv2.warpAffine(img,M,(2cols,2rows))(第三個參數是輸出圖像的尺寸中心)
  • 仿射變換仿射變換是一種二維座標到二維座標之間的線性變換。 在仿射變換中,原圖中所有的平行線在結果圖像中同樣平行。爲了創建這個矩陣我們需要從原圖像中找到三個點以及他們在輸出圖像中的位置。cv2.getAffineTransform 同樣會創建一個 2x3 的矩陣,最後這個矩陣會被傳給函數 cv2.warpAffine
  • 透視變換(投影變換)透視變換是將圖片投影到一個新的視平面,也稱作投影映射.它是二維(x,y)到三維(X,Y,Z),再到另一個二維(x’,y’)空間的映射。 對於視角變換,我們需要一個 3x3 變換矩陣。在變換前後直線還是直線。要構建這個變換矩陣,你需要在輸入圖像上找 4 個點,以及他們在輸出圖像上對應的位置。這四個點中的任意三個都不能共線。這個變換矩陣可以有函數 cv2.getPerspectiveTransform() 構建。然後把這個矩陣傳給函數cv2.warpPerspective。
  • 圖像閾值: 在前面的部分我們使用是全局閾值,整幅圖像採用同一個數作爲閾值。當時這種方法並不適應與所有情況,尤其是當同一幅圖像上的不同部分的具有不同亮度時。這種情況下我們需要採用自適應閾值。此時的閾值是根據圖像上的每一個小區域計算與其對應的閾值。因此在同一幅圖像上的不同區域採用的是不同的閾值,從而使我們能在亮度不同的情況下得到更好的結果。
    這種方法需要我們指定三個參數,返回值只有一個。
      • Adaptive Method- 指定計算閾值的方法。
      – cv2.ADPTIVE_THRESH_MEAN_C:閾值取自相鄰區域的平均值
      – cv2.ADPTIVE_THRESH_GAUSSIAN_C:閾值取值相鄰區域的加權和,權重爲一個高斯窗口。
      • Block Size - 鄰域大小(用來計算閾值的區域大小)。
      • C - 這就是是一個常數,閾值就等於的平均值或者加權平均值減去這個常數。
  • Otsu’ ’s 二值化:這裏用到到的函數還是 cv2.threshold(),但是需要多傳入一個參數(flag):cv2.THRESH_OTSU。這時要把閾值設爲 0。然後算法會找到最優閾值,這個最優閾值就是返回值 retVal。如果不使用 Otsu 二值化,返回的retVal 值與設定的閾值相等。

圖像濾波

  • 平均: 這是由一個歸一化卷積框完成的。他只是用卷積框覆蓋區域所有像素的平均值來代替中心元素。可以使用函數 cv2.blur() 和 cv2.boxFilter() 來完這個任務。需要設定卷積框的寬和高:1/9*ones(3,3)。
    注意:如果不想使用歸一化卷積框,應該使用 cv2.boxFilter(),這時要傳入參數 normalize=False。

  • 高斯模糊: 卷積核換成高斯核(簡單來說,方框不變,將原來每個方框的值是相等的,現在裏面的值是符合高斯分佈的,方框中心的值最大,其餘方框根據距離中心元素的距離遞減,構成一個高斯小山包。原來的求平均數現在變成求加權平均數,全就是方框裏的值)。實現的函數是 cv2.GaussianBlur()。我們需要指定高斯核的寬和高(必須是奇數)。以及高斯函數沿 X,Y 方向的標準差。如果我們只指定了 X 方向的的標準差,Y 方向也會取相同值。如果兩個標準差都是 0,那麼函數會根據核函數的大小自己計算。高斯濾波可以有效的從圖像中去除高斯噪音。也可以使用函數 cv2.getGaussianKernel() 自己構建一個高斯核。

  • 形態學轉換: 腐蝕cv2.erode(img,kernel,iterations = 1);膨脹cv2.dilate(img,kernel,iterations = 1);先進性腐蝕再進行膨脹就叫做開運算cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel);閉運算先膨脹再腐蝕。它經常被用來填充前景物體中的小洞,或者前景物體上的小黑點。cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel);

  • 形態學梯度其實就是一幅圖像膨脹與腐蝕的差別。結果看上去就像前景物體的輪 cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel);禮帽原始圖像與進行開運算之後得到的圖像的差;黑帽進行閉運算之後得到的圖像與原始圖像的差。

  • 圖像梯度 :Sobel 算子是高斯平滑與微分操作的結合體,所以它的抗噪聲能力很好。你可以設定求導的方向(xorder 或 yorder)。還可以設定使用的卷積核的大小(ksize)。如果 ksize=-1,會使用 3x3 的 Scharr 濾波器,它的的效果要比 3x3 的 Sobel 濾波器好(而且速度相同,所以在使用 3x3 濾波器時應該儘量使用 Scharr 濾波器)

  • 邊界檢測 :cv2.Canny()需要設置滯後閾值的最大最小值;當圖像的灰度梯度高於 maxVal 時被認爲是真的邊界,那些低於 minVal 的邊界會被拋棄。如果是位於中間的話,就需要判斷他是不是與maxVal是相連的。

  • 圖像金字塔:Gaussian pyramid:cv2.pyrDown() 從一個高分辨率大尺寸的圖像向上構建一個金子塔(尺寸變小,分辨率降低)。 Laplacian Pyramid:函數 cv2.pyrUp() 從一個低分辨率小尺寸的圖像向下構建一個金子塔(尺寸變大,但分辨率不會增加)

  • 直方圖均衡化:

img = cv2.imread('wiki.jpg',0)
equ = cv2.equalizeHist(img)
res = np.hstack((img,equ)) #stacking images side-by-side
cv2.imwrite('res.png',res)
  • CLAHE: 自適應的直方圖均衡化。這種情況下,整幅圖像會被分成很多小塊,這些小塊被稱爲“tiles”(在 OpenCV 中 tiles 的大小默認是 8x8),然後再對每一個小塊分別進行直方圖均衡化
  • 2D 直方圖:以上直方圖均衡化、CLAHE都是一維直方圖,之所以稱爲一維,是因爲我們只考慮了圖像的一個特徵:灰度值。但是在 2D 直方圖中我們就要考慮兩個圖像特徵。對於彩色圖像的直方圖通常情況下我們需要考慮每個的顏色(Hue)和飽和度(Saturation)。
  • 直方圖反向投影:輸出與輸入圖像(待搜索)同樣大小的圖像,其中的每一個像素值代表了輸入圖像上對應點屬於目標對象的概率。用更簡單的話來解釋,輸出圖像中像素值越高(越白)的點就越可能代表我們要搜索的目標(在輸入圖像所在的位置)。這是一個直觀的解釋。直方圖投影經常與 camshift算法等一起使用。

圖像特徵提取與描述(單獨開一集吧。。。)

  • 衆多的角點檢測方法:Harris、Shi-Tomasi、SIFT、SURF、FAST、BRIEF、ORB
  • cv2.cornerSubPix(),它可以提供亞像素級別的角點檢測。下面是一個例子。首先我們要找到 Harris角點,然後將角點的重心傳給這個函數進行修正
  • cv2.cornerHarris(gray,2,3,0.04)輸入圖像,用sobel算子求得區域的梯度,再對區域打分,高分的就是角點。
    cv2.goodFeaturesToTrack()是Harris的改進版,如果導數矩陣的兩個特徵值的打分超過閾值,纔會判定他是角點。
    cv2.cornerHarris和cv2.goodFeaturesToTrack都有旋轉不變特性,但是對於放大和縮小的圖像就不行了。
  • SIFT 不同尺度使用不同的檢測窗口,尺度空間濾波器可以使用一些列具有不同方差 σ 的高斯卷積核構成;然後使用 2x2 的 Hessian 矩陣計算主曲率慮去那些沒用的邊界,剩下關鍵的點;每一個關鍵點賦予一個反向參數,這樣它纔會具有旋轉不變性。獲取關鍵點(所在尺度空間)的鄰域,然後計算這個區域的梯度級和方向。根據計算得到的結果創建一個含有 36 個 bins(每 10 度一個 bin)的方向直方圖。(使用當前尺度空間 σ 值的 1.5 倍爲方差的圓形高斯窗口和梯度級做權重)。直方圖中的峯值爲主方向參數,如果其他的任何柱子的高度高於峯值的80% 被認爲是輔方向。這就會在相同的尺度空間相同的位置構建除具有不同方向的關鍵點。最後採用關鍵點特徵向量的歐式距離來作爲兩幅圖像中關鍵點的相似性判定度量,取第一個圖的某個關鍵點,通過遍歷找到第二幅圖像中的距離最近的那個關鍵點完成匹配。
  • SURF使用盒子濾波器(box_filter)對 LoG 進行近似。第二就是主方向爲最大的 Haar 響應累加值對應的方向。
  • 圖像特徵提取與描述官方翻譯的說明1
    圖像特徵提取與描述官方翻譯的說明2

視頻分析

  • meanshift和camshift: 要在 OpenCV 中使用 Meanshift 算法首先我們要對目標對象進行設置,計算目標對象的直方圖,這樣在執行 meanshift 算法時我們就可以將目標對象反向投影到每一幀中去了。另外我們還需要提供窗口的起始位置。在這裏我們值計算 H(Hue)通道的直方圖,同樣爲了避免低亮度造成的影響,我們使用函數 cv2.inRange() 將低亮度的值忽略掉。與 Meanshift 基本一樣,但是返回的結果是一個帶旋轉角度的矩形(這是我們的結果),以及這個矩形的參數

**重投影** ``` for i in xrange(len(objpoints)): imgpoints2, _ = cv2.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist) error = cv2.norm(imgpoints[i],imgpoints2, cv2.NORM_L2)/len(imgpoints2) tot_error += error ```

雜問

  • cap = cv2.VideoCapture(0)#獲取視頻的控制權
    cap.release()#結束視頻的控制權 釋放這個進程
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章