1. 程式人生 > >【OpenCV計算機視覺程式設計攻略】全書總結

【OpenCV計算機視覺程式設計攻略】全書總結

第1章 影象程式設計入門

1.1 簡介

1.2 安裝OpenCV庫

1.3 裝載、顯示和儲存影象

  • - imread——讀影象
  • - namedWindow——定義視窗
  • - imshow——顯示影象
  • - flip——翻轉影象
  • - waitKey——等待按鍵
  • - imwrite——儲存影象
  • - setMouseCallback——響應滑鼠在影象上的點選操作
  • - circle、ellipse、line、rectangle——在影象上繪畫對應形狀
  • - putText——在影象上寫入文字

1.4 深入瞭解cv::Mat

  • - Mat::create——重新分配一個新影象
  • - Mat::copyTo——把影象複製給另外一個影象
  • - Mat::convertTo——轉換影象資料型別

1.5 定義興趣區域

  • - 方法一:
  cv::Mat imageROI(image,
                 cv::Rect(image.cols-logo.cols,  //ROI座標
                          image.rows-logo.rows,
                          logo.cols,logo.rows)); //ROI大小
  logo.copyTO(imageROI);                           //插入標誌
  •   - 所謂ROI其實就是Mat類的一種建構函式產生的對原影象記憶體的新的引用,使用Rect來定義ROI區域時,前兩個引數為ROI區域的左上角座標,後兩個引數表示ROI的行列大小。
  • - 方法二:
  cv::Mat imageROI(image,
    cv::Range(image.rows-logo.rows, logo.rows)   //ROI行範圍      
    cv::Range(image.rows-logo.rows, logo.rows)); //ROI列範圍
  logo.copyTO(imageROI);                           //插入標誌
  •   - 第二種方法是給出行列座標的起始和終止範圍
  • - 影象掩碼:: OpenCV中有些操作可以定義掩碼,掩碼必須為8點陣圖像,如果掩碼中某個位置的值不為0,則在這個位置上的操作就會起作用;如果掩碼中的某些畫素位置的值為0,那麼對影象中的相應位置的操作將不起作用;OpenCV中大多數基於畫素的操作都可以使用掩碼。

第2章 操作畫素

2.1 簡介

2.2 訪問畫素值

  • - Mat::at<typename T>(row,col)\[n]——對8-bit影象而言,單通道影象時,T=uchar,\[n]不需要;當為三通道時,T=cv::Vec3b,\[n]可以是0、1、2。

2.3 用指標掃描影象

  • - Mat::ptr<typename T>(row)——T為影象資料型別,此方法是把影象看成三維立體的來訪問,row對應的不是單純的行,更準確的說是三維立體的層。
  • - 低層次指標演算法訪問行:
  uchar *data = image.data;
  data += image.step;                              //從一行移到下一行

2.4 用迭代器掃描影象

  • - cv::MatIterator_<cv::Vec3b> it
  • - cv::Mat_<cv::Vec3b>::iterator it
  cv::Mat_<cv::Vec3b>::iterator it_begin =
                     image.begin<cv::Vec3b>();     //獲得起始位置
  cv::Mat_<cv::Vec3b>::iterator it_end   =
                     image.end<cv::Vec3b>();       //獲得結束位置

2.5 編寫高效的影象掃描迴圈

  • - cv::getTickCount——返回從最近一次電腦開機到當前的時鐘週期數
  • - cv::getTickFrequency——返回每秒的時鐘週期數,獲得某個函式(或程式碼段)的執行時間的方法如下:
  const int64 start = cv::getTickCount();
  function();                                      //呼叫的函式
  double duration = (cv::getTickCount()-start) /   //經過的時間(s)
                     cv::getTickFrequency()

結果表明:`Mat::at<typename T>(row,col)\[n]方法應該在需要隨機訪問資料的時候使用`,絕不要在掃描影象時使用,速度比較慢。

2.6 掃描影象並訪問相鄰畫素

  • - 主要就是訪問某個畫素點周圍26個(對三通道而言)的方法,使用的是智慧指標Mat::ptr<typename T>(row)來訪問不同行,同一行的訪問看作是把二維陣列連續排放成一維陣列來訪問就可以了。
  •   - cv::saturate_cast<tpyename T>——函式的作用是確保結果在該資料型別定義的範圍之內。
  •   - cv::filter2D——呼叫函式時傳入影象和核心
    void sharpen2D(const cv::Mat& image, cv::Mat& result) {
      cv::Mat kernel(3,3,CV_32F,cv::Scalar(0));
      kernel.at<float>(1,1) = 5.0;
      kernel.at<float>(0,1) = -1.0;
      kernel.at<float>(2,1) = -1.0;
      kernel.at<float>(1,0) = -1.0;
      kernel.at<float>(1,2) = -1.0;
      cv::filter2D(image,result,image.depth(),kernel);
    }

2.7 實現簡單的影象運算

  • - add——實現相加功能
  • - addWeighted——實現加權相加
  // c[i] = a[i] + b[i]
  cv::add(imageA, imageB, resultC);
  // c[i] = a[i] + k
  cv::add(imageA, cv::Scalar(k), resultC);
  // c[i] = k1*a[i] + k2*b[i] + k3
  cv::addWeighted(imageA, k1, imageB, k2, k3, resultC);
  // c[i] = k*a[i] + b[i]
  cv::scaleAdd(imageA, k, imageB, resultC);
  • - cv::sqrt、pow、abs、exp、log、
  • - split——將影象的三通道分別複製到三個不同的cv::Mat例項中
  • - merge——用三個單通道影象建立一個彩色影象

2.8 影象重對映

  • - remap——對映方程為:dst(x,y)=src(map_x(x,y),map_y(x,y))

第3章

  • - absdiff——計算影象的畫素與標量值之間差的絕對值
  • - 仿函式或函式物件
  •   過載operator()方法,呼叫類的處理方法就像呼叫一個純粹額函式,這種類的例項被稱為函式物件或仿函式(functor)。
  • - cvtColor——轉換影象的色彩空間
  •   在`搜尋特定顏色`的物體時,HSV色彩空間非常實用,比如膚色檢測。

第4章

4.1 簡介

4.2 計算影象直方圖

  • - calcHist——計算影象直方圖,支援單通道灰度圖,也支援多通道影象

4.3 利用查詢表修改圖象外觀

  • - cv::LUT——對8-bit影象,輸入的查詢表有256個bin,每個bin對應一個新的值,從而實現非線性對映
  •   使用此方法可以`伸展直方圖`以提高影象對比度:以灰度圖為例,先計算出直方圖,然後根據設定的最小灰度值畫素數量和最大灰度值畫素數量,通過遍歷直方圖256個bin來找到滿足條件的最小灰度值和最大灰度值(最小灰度值:先從灰度0開始查詢,相應灰度在直方圖中對應的畫素說不滿足>設定的畫素數量時,逐步提高灰度值,直到滿足條件;最大灰度值:從灰度255開始反向查詢,不滿足>設定的畫素數量時,逐步減小灰度值),下一步就是建立查詢表,方法是小於最小灰度值的bin對映為0,大於最大灰度值的bin對映為255,介於最小最大之間的先進行歸一化,然後乘以255,均勻的雜湊在0~255之間,最後就是呼叫LUT函式實現重對映。
  • - cvRound——對float型的數進行四捨五入
  • - cvFloor——返回不大於float型引數的最大整數值
  • - cvCeil 返回不小於float型引數的最小整數值

4.4 直方圖均衡化

  • - equalizeHist——直方圖均衡化處理

4.5 反向投影直方圖檢測特定影象內容

  • - calcBackProject——從歸一化後的直方圖中讀取概率值並把輸入影象中的畫素替換成與之對應的概率值
  • 直方圖是影象內容的一個重要特性。 如果影象的某個區域含有特定的紋理或物體,這個區域的直方圖就可以看作一個函式,歸一化之後,該函式返回某個畫素屬於這個特殊紋理或物體的概率。

4.6 均值平移演算法查詢目標

  • - TermCriteria——此類定義迭代演算法終止準則
  • - meanShift——根據反向對映直方圖進行均值平移演算法查詢目標
  • 直方圖反向投影的結果是一個概率分佈圖,表示一個指定影象片段出現在特定位置的概率。假設我們已經知道影象中某個物體的大致位置,就可以`用概率分佈圖`找到物體的準確位置。 最可能出現的位置就是視窗中概率最大的位置。因此我們可以從一個初始位置開始,在周圍反覆移動,就可能找到物體所在的準確位置。這個實現方法稱為均值平移演算法。均值偏移演算法是一個迭代過程,用於定位概率函式的區域性最大值。`定位的方法`是尋找預定義視窗內部資料點的重心或加權平均值。然後把視窗移動到重心的位置,並重復該過程, 直到視窗中心收斂到一個穩定的點。

4.7 比較直方圖搜尋相似影象

  • - compareHist——比較兩個直方圖的相似性

4.8 用積分影象統計畫素

  • - 自適應的閾值化
  • 採用區域性閾值,即根據每個畫素的領域計算閾值。將每個畫素的值與鄰域的平均值進行比較。如果某畫素的值與它的區域性平均值差別很大,就會被當作異常值在閾值化過程中剔除。求均值過程中可以利用積分圖加速計算一個領域內的累計值。
  • - 用直方圖實現視覺跟蹤

第5章 用形態學運算變換影象

5.1 簡介

5.2 形態學濾波器腐蝕和膨脹影象

  • - erode——腐蝕影象,可以去除噪聲點
  • - dilate——膨脹影象

5.3 用形態學濾波器開啟和閉合影象

  • - morphologyEx——根據傳入引數實現開啟或閉合運算
  • 閉合的定義是對影象先膨脹後腐蝕。開啟的定義是對影象先腐蝕後膨脹。

5.4 用形態學濾波器檢測邊緣和角點

  • - morphologyEx——根據傳入引數實現邊緣檢測
  • 利用腐蝕和膨脹分別對影象進行操作,之所以可以檢測出邊緣的原理是:腐蝕會使邊緣的範圍變小,而膨脹會使邊緣的範圍變大,因此兩種操作分別得到的影象的差異主要體現在邊緣的範圍大小上,所以將兩種操作後的影象進行absdiff操作就可以就可以得到邊緣了。
  • - 角點檢測
  • 用四個不同的結構元素,分別是正方形、菱形、十字形和X形。先十字形元素膨脹,然後再對其進行菱形元素腐蝕;先用X形元素膨脹,再對其進行正方形元素腐蝕;將以上兩幅影象absdiff得到角點。

5.5 用分水嶺演算法實現影象分割

  • - watershed——

5.6 用MSER演算法提取特徵區域

  • - cv::MSER——

5.7 用GrabCut演算法提取前景物體

  • - cv::grabCut——

第6章 影象濾波

  • - blur——將每個畫素的值替換成該畫素鄰域的平均值(鄰域是矩形的),從而使影象更加平滑,這種濾波器也成為塊濾波器(box filter)
  • - GaussianBlur——將每個畫素的值換成該畫素領域的畫素值進行高斯加權後的平均值
  • - pyrDown——先進行低通濾波,然後影象尺寸縮小一半
  • - pyrUp——放大影象
  • - resize——對影象進行縮放
  • - medianBlur——中值濾波器,`非常有助於消除椒鹽噪聲`
  • 中值濾波器把當前畫素和它的領域組成一個集合,然後計算出這個集合的中間值,以此作為當前畫素的值(集合中數值經過排序,中間位置的數值就是中間值) 。這正是中值濾波器在消除椒鹽噪聲中如此高效的原因,相反,簡單的均值濾波器會在很大程度上受到這種噪聲影響。
  • - Soble——因為它只對垂直或水平方向的影象頻率起作用(具體方向取決於濾波器選用的核心) ,所以它被認為是一種定向濾波器,其原理是計算垂直和水平方向上的梯度。
  •   - Prewitt運算元
  •   - Roberts運算元
  •   - Scharr運算元(相對來說更精確)
  •   因為這些定向濾波器都會計算影象函式的一階導數,因此,對強度變化大的區域,得到較大的響應;較平坦的區域得到較小的值,故稱`計算影象導數的濾波器為高通濾波器`。
  • - cv::Laplacian——計算影象的拉普拉斯運算元

第7章 提取直線、輪廓與區域

7.1 簡介

7.2 用Canny運算元檢測影象輪廓

  • - cv::Canny——根據一個低閾值和一個高閾值來判斷哪個點屬於輪廓
  • Canny演算法結合高低閾值得到的兩種邊緣分佈圖,生成最優的輪廓分佈圖。具體做法是在`低閾值邊緣分佈圖上只保留具有連續路徑的邊緣點`,`同時把那些邊緣點連線到屬於高閾值邊緣分佈圖的邊緣上`,`即把低閾值邊緣分佈圖上的連續邊緣點融合到高閾值邊緣分佈圖上`,這樣一來, `高閾值分佈圖上的所有邊緣點都保留下來`, 而`低閾值分佈圖上邊緣點的孤立鏈全部被移除`。 這是一種很好的折中方案,只要指定適當的閾值,就能獲得高質量的輪廓。這種基於兩個閾值獲得二值分佈圖的策略,稱為`滯後閾值化`,可用於任何需要用閾值化獲得二值分佈圖的場景。但是它的計算複雜度比較高。

7.3 用霍夫變換檢測直線

  • - cv::HoughLines——輸入二值分佈圖,即檢測到的邊緣影象,返回極座標的引數rho和角度theta
  • - cv::HoughLinesP——霍夫變換的改進版,返回所得直線線段的兩個端點座標,其使用了二維累加器來記錄某一直線穿過的畫素點數,只有數量達到一定值才會被認為是直線
  • - cv::HoughCircles——

7.4 點集的直線擬合

  • - cv::fitLine——擬合直線
  • - cv::fitEllipse——擬合橢圓,它返回一個旋轉的矩形(一個cv::RotatedRect例項), 矩形中有一個內切的橢圓。

7.5 提取區域的輪廓

  • - cv::findContours——輸入二值圖想,輸出一個儲存輪廓的cv::Point型別的向量
  • - cv::drawContours——在影象上畫出那些區域的輪廓
  • - cv::findContours——檢測二值影象中所有的閉合輪廓
  • - cv::boundingRect——找出矩形邊界框
  • - cv::minEnclosingCircle——找出最小圓形邊界框
  • - cv::approxPolyDP——計算區域輪廓的多邊形逼近
  • - cv::polylines——繪製多邊形
  • - cv::moments——計算輪廓矩
  • - cv::minAreaRect——計算最小覆蓋自由矩形
  • - cv::contourArea——估算輪廓的面積
  • - cv::pointPolygonTest——判斷一個點在輪廓內部還是外部
  • - cv::matchShapes——度量兩個輪廓之間的相似度

第8章 檢測興趣點

8.1 簡介

8.2 檢測影象中的角點

  • - cv::cornerHarris——檢測Harris角點
  •   其原理是計算興趣點周圍領域內某個方向上強度值的平均強度值變化:$R≈\sum(I(x+u,y+u)-I(x,y))^2$ ,然後在$I(x,y)$ 處進行一階泰勒展開得到下式:
  •   $R\approx\sum((I(x,y)+\frac{\partial I}{\partial \text{x}}u+\frac{\partial I}{\partial \text{x}}v-I(x,y)))^2$=$\sum((\frac{\partial I}{\partial x}u)^2+(\frac{\partial I}{\partial y}v)^2+2\frac{\partial I}{\partial x}\frac{\partial I}{\partial y}uv))$
  •   寫成矩陣的形式,就是:
  •   $R\approx[u\quad v]\left[\begin{matrix}\sum(\frac{\partial I}{\partial x})^2&\sum\frac{\partial I}{\partial x}\frac{\partial I}{\partial y}\\\sum\frac{\partial I}{\partial x}\frac{\partial I}{\partial y}&\sum(\frac{\partial I}{\partial y})^2\end{matrix}\right]\left[\begin{matrix}u\\v\end{matrix}\right]$
  •   然後根據最小特徵值與設定閾值的關係判定是否為角點。`Harris角點演算法的原始定義不顯式的計算特徵值`,而是通過計算下式的評分:$Det(C)-kTrace^2(C)$來判定是否為角點。
  • - cv::cornerEigenValsAndVecs——計算Harris角點,並求出$R$的特徵值和對應的特徵向量
  • - cv::cornerMinEitenVal——計算Harris角點,只返回$R$的最小特徵值
  • - cv::goodFeatureToTrack——從Harris值最強的點開始,只允許一定距離之外的點成為興趣點,解決特徵點聚集的問題
  // 計算適合跟蹤的特徵
  std::vector<cv::Point2f> corners;
  cv::goodFeaturesToTrack(image, // 輸入影象
  corners, // 角點影象
  500, // 返回角點的最大數量
  0.01, // 質量等級
  10); // 角點之間允許的最短距離
// KeyPoint型別的向量
  std::vector<cv::KeyPoint> keypoints;
  // 適合跟蹤的特徵檢測器的建構函式
  cv::Ptr<cv::FeatureDetector> gftt=
  new cv::GoodFeaturesToTrackDetector(
  500, // 返回角點的最大數量
  0.01, // 質量等級
  10); // 興趣點之間允許的最短距離
  // 用FeatureDetector方法檢測興趣點
  gftt->detect(image,keypoints);

8.3 快速檢測特徵

  • - cv::FAST——根據候選特徵點周圍的畫素值判斷該點是否為關鍵點
  • 如果存在這樣一段圓弧,它的連續長度超過周長的3/4,並且它上面所有畫素的強度值都與圓心的強度值明顯不同(全部更黑或更亮),那麼就認定這是一個關鍵點。
  // 關鍵點的向量
  std::vector<cv::KeyPoint> keypoints;
  // FAST特徵檢測器的建構函式
  cv::Ptr<cv::FeatureDetector> fast=
  new cv::FastFeatureDetector(
  40); // 檢測用的閾值
  // 檢測特徵點
  fast->detect(image,keypoints);
  cv::FAST(image, // 輸入影象
  keypoints, // 輸出關鍵點的向量
  40, // 閾值
  false); // 是否進行非最大值抑制?
  • - cv::DynamicAdaptedFeatureDetector——可以指定被檢測興趣點的數量範圍
  cv::DynamicAdaptedFeatureDetector fastD(
  new cv::FastAdjuster(40), // 特徵檢測器
  150, // 特徵的最小數量
  200, // 特徵的最大數量
  50); // 最大迭代次數
  fastD.detect(image,keypoints); // 檢測特徵點
  • - cv::GridAdaptedFeatureDetector——在影象上定義一個網格,可以設定每個網格中最大特徵點數量
  cv::GridAdaptedFeatureDetector fastG(
  new cv::FastFeatureDetector(10), // 特徵檢測器
  1200, // 關鍵點總數的最大值
  5, // 網格的行數
  2); // 網格的列數
  fastG.detect(image,keypoints);
  • - cv::PyramidAdaptedFeatureDetector——在一個影象金字塔上應用特徵檢測器,結果被合併到輸出的關鍵點向量中。
  cv::PyramidAdaptedFeatureDetector fastP(
  new cv::FastFeatureDetector(60), // 特徵檢測器
  3); // 金字塔的層數
  fastP.detect(image,keypoints);

8.4 尺度不變特徵的檢測

  • - cv::SURF——Hessian矩陣
  // SURF特徵檢測器的建構函式
  cv::Ptr<cv::FeatureDetector> detector =
  new cv::SURF(2000.); // 閾值
  // 檢測SURF特徵
  detector->detect(image,keypoints);
  • - cv::SIFT——DoG
  // 構造SIFT特徵檢測器物件
  detector = new cv::SIFT();
  // 檢測SIFT特徵
  detector->detect(image,keypoints);

8.5 多尺度FAST特徵的檢測

  • - BRISK(Binary Robust Invariant Scalable Keypoints) ——先建立影象金字塔,然後每個影象用`FAST`找關鍵點,然後再用類似SIFT的方法篩選關鍵點,在空間尺度上進行插值尋找更精確的關鍵點,因此在不連續的影象尺度上最後卻檢測到對應尺度連續的關鍵點
  // 構造BRISK特徵檢測器物件
  detector = new cv::BRISK();
  // 檢測BRISK特徵
  detector->detect(image,keypoints);
  • - ORB(Oriented `FAST` and Rotated `BRIEF`)——先建立影象金字塔,然後使用FAST檢索每個影象找出關鍵點,之後通過計算Harris評分:$Det(C)-kTrace^2(C)$去除一些邊緣點,根據計算FAST找到的關鍵點周圍領域內的畫素值重心,與關鍵點連線形成角度,實現旋轉不變性
  // 構造ORB特徵檢測器物件
  detector = new cv::ORB(200, // 關鍵點的總數
  1.2, // 圖層之間的縮放因子
  8); // 金字塔的圖層數量
  // 檢測ORB特徵
  detector->detect(image,keypoints);

 第9章

9.1 簡介

9.2 區域性模板匹配

  • - SSD(Sum of Squared Differences)——計算以兩個以關鍵點為中心的正方形區域(即影象塊)中對應畫素的SSD,滿足設定閾值即認為這兩個點是匹配的

9.3 描述區域性強度值模式

  • - SURF、SIFT——計算特徵描述子之間差距
  • - 提高匹配質量的方法
  •   - 交叉檢查匹配項:假設有特徵點集A和B,$A_x$與B集中的$B_y$最匹配,然後檢查$B_y$與A集中最匹配的點,如果這兩個關鍵點互為最佳匹配,才認為是一個有效的匹配項
  •   - 比率檢驗法:為每個關鍵點找兩個最佳匹配項,如果兩個最佳匹配項與關鍵點的距離比值(即相似度)超過設定比率,則剔除此關鍵點
  •   - 匹配插值的閾值化:雖然關鍵點對應的點是最匹配的,但是匹配差值太大的也是不行的,超過閾值的關鍵點須剔除

9.4 用二值特徵描述關鍵點

  • - BRIEF、BRISK、FREAK、ORB(FAST+BRIEF)