opencv6.5-imgproc圖像處理模塊之輪廓

opencv6.4-imgproc圖像處理模塊之直方圖與模板html

這部分的《opencv_tutorial》上都是直接上代碼,沒有原理部分的解釋的。算法

11、輪廓數組

一、圖像中找輪廓app


  /// 轉成灰度並模糊化降噪
  cvtColor( src, src_gray, CV_BGR2GRAY );
  blur( src_gray, src_gray, Size(3,3) );
Mat canny_output;//找到輪廓的圖
  vector<vector<Point> > contours;//裝載曲線的點
  vector<Vec4i> hierarchy;

  /// 用Canny算子檢測邊緣
  Canny( src_gray, canny_output, thresh, thresh*2, 3 );
  /// 尋找輪廓
  findContours( canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );

  /// 繪出輪廓
  Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 );
  for( int i = 0; i< contours.size(); i++ )//經過對contours.size(),就知道有幾個分離的輪廓了
     {
       Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
       drawContours( drawing, contours, i, color, 2, 8, hierarchy, 0, Point() );//畫出輪廓
     }

  /// 在窗體中顯示結果
  namedWindow( "Contours", CV_WINDOW_AUTOSIZE );
  imshow( "Contours", drawing );
查找輪廓的函數原型:void findContours(InputOutputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method, Point offset=Point())
                                         void findContours(InputOutputArray image, OutputArrayOfArrays contours, int mode, int method, Point offset=Point())

參數列表:image:一個8-bit的單通道原圖像。非零的像素值被看成1來處理(相似bool類型)。0的像素值仍舊仍是0,因此這個image是被看成二值處理的。你可使用compare(),inRange(),threshold(),adaptiveThreshold(),Canny(),和其餘的從一個灰度或者彩色圖中生成一個二值圖。該函數會在提出輪廓的時候修改image。若是mode等於CV_RETR_CCOMP或者CV_RETR_FLOODFILL,那麼這個輸入一樣能夠是標籤的32-bit整數圖(CV_32SC1)。函數

                  contours:檢測到的輪廓,每一個輪廓都是存儲爲點向量;測試

                  hierarchy:可選的輸出向量,包含圖像拓撲信息。它有着和輪廓數量同樣多的元素。對於第i 個輪廓contours[i],元素hierarchy【i】【0】,hiearchy【i】【1】,hiearchy【i】【2】和hiearchy【i】【3】是在contours中基於0索引的,分別表示在同一個層次級別上的下一個輪廓上一個輪廓,第一個孩子輪廓父親輪廓。若是輪廓 i 沒有下一個、上一個、父親或者嵌套的輪廓,對應的hierarchy【i】的元素就是負的。(這裏其實就是個樹結構,來進行索引不一樣的輪廓)編碼

                  mode:輪廓索引模型spa

                 – CV_RETR_EXTERNAL     只檢索最外面的輪廓。它會對全部的輪廓設置 hierarchy[i][2] = hierarchy[i][3] = -1 .
                 – CV_RETR_LIST                 不創建任何層次關係來進行索引全部的輪廓.
                 – CV_RETR_CCOMP       索引全部的輪廓並將它們組織成一個two-level的hierarchy(兩個層次的層級關係):在頂層上,有着成分的外部邊界;在第二層是孔洞的邊界。若是有另外一個輪廓在一個鏈接起來的成份內部,那麼就將它放在頂層上。
                – CV_RETR_TREE        檢索全部的輪廓並重構一個全層次的嵌套輪廓結構,在contours.c的例子中你更能夠看到全層次創建的代碼。
                 method :輪廓逼近的方法.net

                   – CV_CHAIN_APPROX_NONE   存儲全部輪廓點的絕對值。也就是說任何的輪廓的2子序列點 (x1,y1) 和 (x2,y2) 就是表示水平的,豎直的或者對角線鄰居,也就是: max(abs(x1-x2),abs(y2-y1))==1;
                – CV_CHAIN_APPROX_SIMPLE    壓縮水平的,豎直的和對角線線段,只保留他們的終端。例如:對於一個up-right 的矩形輪廓是由4個點進行編碼的。指針

                 – CV_CHAIN_APPROX_TC89_L1,  CV_CHAIN_APPROX_TC89_KCOS     使用 Teh-Chin 鏈逼近算法中主流之一的算法。

                offset:可選的偏移量,經過這個值能夠平移每個輪廓。當輪廓是從一個圖像的ROI中提取而你須要在整個圖像上下文中分析的時候會變得頗有用。

該函數使用算法從二值圖像中索引輪廓。輪廓對於形狀分析和對象的檢測識別是頗有用的,在squares.c中有例子代碼。

Notes:image會被該函數所修改,一樣的該函數不考慮圖像的1像素邊界(它會被0填充而後用來做爲鄰居分析),所以接觸圖像邊界的輪廓會被修剪(clip,夾)。

畫出輪廓的函數原型:void drawContours(InputOutputArray image, InputArrayOfArrays contours, int contourIdx, const Scalar& color, int thickness=1, int lineType=LINE_8, InputArray hierarchy= noArray(), int maxLevel=INT_MAX, Point offset=Point() );

參數列表:目標圖像、輸入的輪廓、輪廓的索引id、輪廓的顏色、粗度、線類型、可選的層次信息、最大級別、偏移量;

   第一個參數:目標圖像,即畫布;

   第二個參數:全部的輸入輪廓,每一個輪廓存儲成點向量的形式;

   第三個參數:用來索引須要畫的輪廓的參數,若是是負的,那麼就畫全部的輪廓;

   第四個參數:輪廓的顏色;

   第五個參數:畫的輪廓的線的粗細程度,若是是負的(例如:thickness = CV_FILLED),輪廓內部也會畫出來;

   第六個參數:線鏈接類型,line()能夠有更詳細的說明。

   第七個參數:可選的關於層次的信息。當你只想畫某些輪廓的時候纔是須要的(見maxLevel);

   第八個參數:畫輪廓的最大等級。若是爲0,那麼只畫指定的輪廓。若是爲1,該函數會畫輪廓及全部的嵌套輪廓。若是爲2,該函數會畫輪廓、全部的嵌套輪廓、全部的嵌套-to-嵌套的輪廓,以此類推。該參數當hierarchy可用的時候才被考慮;

   第九個參數:可選的輪廓平移參數。經過制定的平移量offset = (dx,dy)來平移全部的畫的輪廓。

該函數但thickness >=0的時候會畫輪廓的外部線條,或者當thickness <0的時候會填充輪廓的框起來的區域。下面的代碼是展現如何從二值圖像中索引聯通的成分,而且標記他們:

Mat src;
     src = imread(name,0);
Mat dst = Mat::zeros(src.rows, src.cols, CV_8UC3);
     src = src > 1;

vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours( src, contours, hierarchy,RETR_CCOMP, CHAIN_APPROX_SIMPLE );
//經過對top-level的輪廓進行迭代來畫出每一個聯通的成分,使用隨機顏色

int idx = 0;
   for( ; idx >= 0; idx = hierarchy[idx][0] ){
     Scalar color( rand()&255, rand()&255, rand()&255 );
     drawContours( dst, contours, idx, color, FILLED, 8, hierarchy );
}
     namedWindow( "Components", 1 );
     imshow( "Components", dst );
     waitKey(0);
二、計算物體的凸包

凸包就是將對象進行外部輪廓的包含,並且是凸圖形的:


/// 轉成灰度圖並進行模糊降噪
   cvtColor( src, src_gray, CV_BGR2GRAY );
   blur( src_gray, src_gray, Size(3,3) );
Mat src_copy = src.clone();
   Mat threshold_output;
   vector<vector<Point> > contours;//存儲輪廓的點集合
   vector<Vec4i> hierarchy;//構建輪廓的層次結構

   /// 對圖像進行二值化
int thresh = 100;
 int max_thresh = 255;
 RNG rng(12345);
threshold( src_gray, threshold_output, thresh, 255, THRESH_BINARY ); /// 尋找輪廓 findContours( threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) ); /// 對每一個輪廓計算其凸包 vector<vector<Point> >hull( contours.size() ); for( int i = 0; i < contours.size(); i++ ) {  
     convexHull( Mat(contours[i]), hull[i], false );//凸包計算
     }

   /// 繪出輪廓及其凸包
   Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 );
   for( int i = 0; i< contours.size(); i++ )
      {
        Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
        drawContours( drawing, contours, i, color, 1, 8, vector<Vec4i>(), 0, Point() );//畫輪廓
        drawContours( drawing, hull, i, color, 1, 8, vector<Vec4i>(), 0, Point() );//畫凸包
      }

   /// 把結果顯示在窗體
   namedWindow( "Hull demo", CV_WINDOW_AUTOSIZE );
   imshow( "Hull demo", drawing );
凸包函數原型:void convexHull(InputArray points, OutputArray hull, bool clockwise=false, bool returnPoints=true);

參數列表:2d點集合、輸出的凸包、定向標識、操做標識;

第一個參數:輸入的2D點集合,存儲在vector或者Mat中。

第二個參數:輸出的凸包,是一個包含索引的整數向量或者是點向量。在前者中,這個hull元素是在原始數組中的凸包點上基於0索引的;後者中,hull元素自身就是凸包點。(也就是說該參數要不是索引到原始圖像找凸包點,或者是直接提取凸包點);

第三個參數:定向標識,若是爲true,那麼輸出的凸包就是順時針方向的;否則就是逆時針方向的。假設的座標系的x 軸指向右邊,y 軸指向上面;

第四個參數:操做標識,在矩陣Mat的狀況中,當這個參數爲true,該函數返回凸包點;不然返回指向凸包點的索引值;當在第二個參數是數組vector的狀況中,該標識被忽略,輸出是依賴vector的類型指定的,vector<int> 暗示returnPoints= true ,vector<Point>暗示 returnPoints= false。

    該函數使用Sklansky的算法來查找一個2d點集的凸包,在當前的執行狀況下的複雜度是O(NlogN),能夠參見convexhull.cpp中驗證不一樣的函數變量的結果。

3、給輪廓加上矩形或者圓形邊界框


這個仍是挺有用的,有時候識別一個物體,想先用簡單的數字圖像處理方法獲得更少的區域而後能夠提取從而接着使用模式識別的方法進行訓練和創建分類器。

使用OpenCV函數 boundingRect 來計算包圍輪廓的矩形框.

使用OpenCV函數 minEnclosingCircle 來計算徹底包圍已有輪廓最小圓.

int thresh = 100;
int max_thresh = 255;
RNG rng(12345);
/// 轉化成灰度圖像並進行平滑 用來減小噪音點
  cvtColor( src, src_gray, CV_BGR2GRAY );
  blur( src_gray, src_gray, Size(3,3) );
Mat threshold_output;
  vector<vector<Point> > contours;//存儲輪廓點
  vector<Vec4i> hierarchy;//構建不一樣輪廓的層次結構

  /// 使用Threshold檢測邊緣
  threshold( src_gray, threshold_output, thresh, 255, THRESH_BINARY );
  /// 找到輪廓
  findContours( threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );

  /// 多邊形逼近輪廓 + 獲取矩形和圓形邊界框
  vector<vector<Point> > contours_poly( contours.size() );//建立contours.size()個空的多邊形
  vector<Rect> boundRect( contours.size() );//建立contours.size()個矩形框
  vector<Point2f>center( contours.size() );//建立contours.size()個圓心
  vector<float>radius( contours.size() );//建立contours.size()個半徑

  for( int i = 0; i < contours.size(); i++ )
     { 
       approxPolyDP( Mat(contours[i]), contours_poly[i], 3, true );//多邊形逼近
       boundRect[i] = boundingRect( Mat(contours_poly[i]) );//獲取某個輪廓的矩形框
       minEnclosingCircle( contours_poly[i], center[i], radius[i] );//生成某個輪廓的最小包含圓的圓心和半徑
     }


  /// 畫多邊形輪廓 + 包圍的矩形框 + 圓形框
  Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 );
  for( int i = 0; i< contours.size(); i++ )
     {
       Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );//隨機顏色
       drawContours( drawing, contours_poly, i, color, 1, 8, vector<Vec4i>(), 0, Point() );//畫輪廓-多邊形
       rectangle( drawing, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0 );//畫矩形
       circle( drawing, center[i], (int)radius[i], color, 2, 8, 0 );//畫圓形
     }

  /// 顯示在一個窗口
  namedWindow( "Contours", CV_WINDOW_AUTOSIZE );
  imshow( "Contours", drawing );
多邊形逼近的函數原型:void approxPolyDP(InputArray curve, OutputArray approxCurve, double epsilon, bool closed);

參數列表:輸入數組、逼近的結果、逼近的精度、是否閉合的標識;

第一個參數:一個2d點的輸入向量能夠存儲在:

                          – std::vector or Mat    (C++ interface)
                         – Nx2 numpy array      (Python interface)
                        – CvSeq or ‘‘ CvMat      (C interface)

第二個參數:逼近的結果,該參數的類型應該匹配輸入曲線的類型。(在c接口中,逼近的曲線存儲在內存存儲區中,返回的是指向該內存的指針,我列出來的都是cpp接口,因此該句可忽略);

第三個參數:指定逼近精度的參數。這是介於原始曲線與它的逼近之間的最大的距離;

第四個參數:若是爲真,逼近的曲線是閉合的(即,將首尾連起來);不然就不是閉合的。

該函數使用一個更少頂點的曲線/多邊形來逼近另外一個曲線或多邊形,使得介於他們之間的距離小於或者等於指定的精度。該函數使用的是Douglas-Peucker算法。http://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm


計算一個點集合的up-right邊界矩形的函數原型:Rect boundingRect(InputArray points);

參數列表:輸入點;

第一個參數:輸入的2D點集合,存儲在vector或者Mat中。

該函數對指定的點集合計算並返回最小的up-right矩形。


計算一個2d點集合的最小區域圓的函數原型:void minEnclosingCircle(InputArray points, Point2f& center, float& radius)

參數列表:輸入的點集合、輸出的圓心座標、輸出的半徑;

第一個參數:2D點的輸入向量,存儲在:

                        – std::vector<> or Mat (C++ interface)
                         – CvSeq* or CvMat* (C interface)
                        – Nx2 numpy array (Python interface)

第二個參數:圓的輸出的圓心;

第三個參數:圓的輸出的半徑

該函數在一個2D點集合中使用一個迭代算法來查找最接近的圓,見minarea.cpp中有例子。

四、給輪廓加上傾斜的邊界框和橢圓

該部分與上面部分很類似,不過採用的函數是不一樣的。


int thresh = 100;
int max_thresh = 255;
RNG rng(12345);
 /// 轉爲灰度圖並模糊化 來減少噪音點
  cvtColor( src, src_gray, CV_BGR2GRAY );
  blur( src_gray, src_gray, Size(3,3) );
 Mat threshold_output;
  vector<vector<Point> > contours;//存儲輪廓的向量
  vector<Vec4i> hierarchy;//輪廓的層次結構

  /// 閾值化檢測邊界
  threshold( src_gray, threshold_output, thresh, 255, THRESH_BINARY );
  /// 尋找輪廓
  findContours( threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );

  /// 對每一個找到的輪廓建立可傾斜的邊界框和橢圓
  vector<RotatedRect> minRect( contours.size() );//存儲contours.size()個旋轉的邊界框***************此處是重點,RotateRect
  vector<RotatedRect> minEllipse( contours.size() );////存儲contours.size()個旋轉的橢圓*************

  for( int i = 0; i < contours.size(); i++ )
     { 
        minRect[i] = minAreaRect( Mat(contours[i]) );//獲取包含最小區域的矩形
       if( contours[i].size() > 5 )
         { 
         minEllipse[i] = fitEllipse( Mat(contours[i]) );//獲取橢圓所需的信息
         }
     }

  /// 繪出輪廓及其可傾斜的邊界框和邊界橢圓
  Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 );
  for( int i = 0; i< contours.size(); i++ )
     {
       Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
       // contour
       drawContours( drawing, contours, i, color, 1, 8, vector<Vec4i>(), 0, Point() );//畫對象的輪廓
       // ellipse
       ellipse( drawing, minEllipse[i], color, 2, 8 );//畫橢圓
       // rotated rectangle
       Point2f rect_points[4]; 
       minRect[i].points( rect_points );//將旋轉矩形的頂點賦值給實參;
       for( int j = 0; j < 4; j++ )
          line( drawing, rect_points[j], rect_points[(j+1)%4], color, 1, 8 );//畫出傾斜矩形,採用的是畫四條線的形式實現的
     }

  /// 結果在窗體中顯示
  namedWindow( "Contours", CV_WINDOW_AUTOSIZE );
  imshow( "Contours", drawing );
在輸入的2D點集合中找到一個最小區域的旋轉後的矩形的函數原型:RotatedRect minAreaRect(InputArray points)
參數列表:輸入的2D點集合
第一個參數:輸入的2D點的向量,存儲在:
                               – std::vector<> or Mat (C++ interface)

                              – CvSeq* or CvMat* (C interface)
                              – Nx2 numpy array (Python interface)

該函數計算並返回一個指定的點集合的最小區域邊界的矩形,在minarea.cpp中有例子,開發者應該注意當數據是接近包含的矩陣元素邊界的時候 返回的旋轉矩形能夠包含負指數。


沿着一個2D點集合進行擬合一個橢圓的函數原型:RotatedRect fitEllipse(InputArray points)

第一個參數:輸入的2D點集合,能夠存儲在:

                      – std::vector<> or Mat (C++ interface)
                     – CvSeq* or CvMat* (C interface)
                     – Nx2 numpy array (Python interface)

該函數計算在對一個2D點集合擬合的最好的橢圓(最小二乘做爲損失函數來判別)。它返回旋轉的矩形中內含的橢圓,使用的算法是[FItzgibbon95].開發者應該注意當數據點很靠近包含的矩陣元素的邊界的時候,返回的橢圓/旋轉矩形數據包含負指數例子代碼在fitellipse.cpp中。

五、計算輪廓的矩

使用OpenCV函數 moments 計算圖像全部的矩(最高到3階)

使用OpenCV函數 contourArea 來計算輪廓面積

使用OpenCV函數 arcLength 來計算輪廓或曲線長度

int thresh = 100;
int max_thresh = 255;
RNG rng(12345);
 /// 把原圖像轉化成灰度圖像並進行平滑
  cvtColor( src, src_gray, CV_BGR2GRAY );
  blur( src_gray, src_gray, Size(3,3) );
Mat canny_output;
  vector<vector<Point> > contours;//存儲輪廓
  vector<Vec4i> hierarchy;//存儲輪廓的層次結構

  /// 使用Canndy檢測邊緣
  Canny( src_gray, canny_output, thresh, thresh*2, 3 );
  /// 找到輪廓
  findContours( canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );

  /// 計算矩
  vector<Moments> mu(contours.size() );
  for( int i = 0; i < contours.size(); i++ )
     { 
         mu[i] = moments( contours[i], false );//計算輪廓的矩
      }

  ///  計算中心矩:
  vector<Point2f> mc( contours.size() );
  for( int i = 0; i < contours.size(); i++ )
     { 
          mc[i] = Point2f( mu[i].m10/mu[i].m00 , mu[i].m01/mu[i].m00 ); 
      }

  /// 繪製輪廓
  Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 );
  for( int i = 0; i< contours.size(); i++ )
     {
       Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
       drawContours( drawing, contours, i, color, 2, 8, hierarchy, 0, Point() );
       circle( drawing, mc[i], 4, color, -1, 8, 0 );
     }

  /// 顯示到窗口中
  namedWindow( "Contours", CV_WINDOW_AUTOSIZE );
  imshow( "Contours", drawing );

  /// 經過m00計算輪廓面積而且和OpenCV函數比較
  printf("\t Info: Area and Contour Length \n");
  for( int i = 0; i< contours.size(); i++ )
     {
       printf(" * Contour[%d] - Area (M_00) = %.2f - Area OpenCV: %.2f - Length: %.2f \n", 
              i, mu[i].m00, contourArea(contours[i]), arcLength( contours[i], true ) //第幾個輪廓,輪廓的空間矩,輪廓的面積,輪廓的周長
               );//計算輪廓面積和 輪廓或曲線的長度
       Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
       drawContours( drawing, contours, i, color, 2, 8, hierarchy, 0, Point() );
       circle( drawing, mc[i], 4, color, -1, 8, 0 );
 

計算一個多邊形或者光柵形狀全部的矩最高到3階的函數原型:Moments moments(InputArray array, bool binaryImage=false )

參數列表:輸入數組、標識

第一個參數:光柵圖像(單通道,8-bit或者浮點2D數組);或者一個2D點(Point 或者 Point2f)的數組(1xN或者Nx1);

第二個參數:若是爲真,全部的非0圖像像素被視爲 1 ;該參數只用在圖像上。

該函數計算一個向量形狀或者光柵形狀的矩到3階。結果返回在結構體Moments。

class Moments
{
public:
<span style="white-space:pre">		</span>Moments();
<span style="white-space:pre">		</span>Moments(double m00, double m10, double m01, double m20, double m11,
<span style="white-space:pre">		</span>double m02, double m30, double m21, double m12, double m03 );
<span style="white-space:pre">		</span>Moments( const CvMoments& moments );
<span style="white-space:pre">		</span>operator CvMoments() const;
// spatial moments
<span style="white-space:pre">		</span>double m00, m10, m01, m20, m11, m02, m30, m21, m12, m03;
// central moments
<span style="white-space:pre">		</span>double mu20, mu11, mu02, mu30, mu21, mu12, mu03;
// central normalized moments
<span style="white-space:pre">		</span>double nu20, nu11, nu02, nu30, nu21, nu12, nu03;
}
在光柵圖像的時候,空間矩 如下面的方式計算:

 

中心矩如下面的方式計算:

這裏是團塊中心:

歸一化的中心矩按照下面的方式計算:

notes:
輪廓的矩以一樣的方式定義,不過是使用Green(http://en.wikipedia.org/wiki/Green_theorem).)的公式計算的。因此由於一個受限的光柵分辨率,輪廓的矩的計算輕微的不一樣於一樣的光柵輪廓的矩計算。

由於輪廓矩是使用Green公式計算的,因此可能看到奇怪的與自相交的輪廓結果,例如:一個蝴蝶形狀輪廓的0區域(m00)。


計算一個輪廓的面積的函數原型:double contourArea(InputArray contour, bool oriented=false )

第一個參數:輸入的2D點的向量(輪廓索引),存儲在vector或者Mat中;

第二個參數:定向區域標識。若是爲true,該函數返回一個有符號的面積值,依賴於輪廓的方向(順時針或者逆時針)。使用這個特徵,你能夠經過使用一個區域的符號決定一個輪廓的方向。默認狀況下,該參數是false的,這意味着會返回絕對值。

該函數計算一個輪廓的面積,類似於moment()。該面積是使用Green公式計算的。因此,若是你經過使用drawContours()或者fillPoly()畫這個輪廓,返回的面積和非0像素的個數,會不同。一樣的該函數差很少會在一個有着自相交的輪廓上給出一個錯誤的結果。(也就是這時候該函數不靠譜)。

例子代碼:

   vector<Point> contour;
contour.push_back(Point2f(0, 0));
contour.push_back(Point2f(10, 0));
contour.push_back(Point2f(10, 10));
contour.push_back(Point2f(5, 4));
   double area0 = contourArea(contour);
vector<Point> approx;
   approxPolyDP(contour, approx, 5, true);
   double area1 = contourArea(approx);
cout << "area0 =" << area0 << endl <<
<span style="white-space:pre">	</span>"area1 =" << area1 << endl <<
<span style="white-space:pre">	</span>"approx poly vertices" << approx.size() << endl;

計算一個輪廓的周邊或者一個曲線長度的函數原型:double arcLength(InputArray curve, bool closed)

參數列表:

第一個參數:輸入的2D點向量,存儲在vector或者Mat中;

第二個參數:表示該曲線是否閉合。

該函數計算一個曲線的長度或者一個閉合輪廓的周長。

六、多邊形測試


是執行一個輪廓中點的測試。

 /// 建立一個圖形     const int r = 100;
  Mat src = Mat::zeros( Size( 4*r, 4*r ), CV_8UC1 );//建立畫布

  /// 繪製一系列點建立一個輪廓:
  vector<Point2f> vert(6);//一個有6個點的輪廓

  vert[0] = Point( 1.5*r, 1.34*r );
  vert[1] = Point( 1*r, 2*r );
  vert[2] = Point( 1.5*r, 2.866*r );
  vert[3] = Point( 2.5*r, 2.866*r );
  vert[4] = Point( 3*r, 2*r );
  vert[5] = Point( 2.5*r, 1.34*r );//本身定輪廓的6各點

  /// 在src內部繪製
  for( int j = 0; j < 6; j++ ){ 
      line( src, vert[j],  vert[(j+1)%6], Scalar( 255 ), 3, 8 ); //將該輪廓畫出來
      }

  /// 獲得輪廓
  vector<vector<Point> > contours; vector<Vec4i> hierarchy;
  Mat src_copy = src.clone();

  findContours( src_copy, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);//查找輪廓

  /// 計算到輪廓的距離
  Mat raw_dist( src.size(), CV_32FC1 );

  for( int j = 0; j < src.rows; j++ ){ 
    for( int i = 0; i < src.cols; i++ ){ 
           raw_dist.at<float>(j,i) = pointPolygonTest( contours[0], Point2f(i,j), true ); 整個畫布,逐點測試到第0個輪廓的距離
          }
     }

  double minVal; double maxVal;
  minMaxLoc( raw_dist, &minVal, &maxVal, 0, 0, Mat() );//查找全局最大最小
  minVal = abs(minVal); maxVal = abs(maxVal);

  /// 圖形化的顯示距離
  Mat drawing = Mat::zeros( src.size(), CV_8UC3 );

  for( int j = 0; j < src.rows; j++ ){ 
      for( int i = 0; i < src.cols; i++ ) {
            if( raw_dist.at<float>(j,i) < 0 ){ 
               drawing.at<Vec3b>(j,i)[0] = 255 - (int) abs(raw_dist.at<float>(j,i))*255/minVal;
             }
            else if( raw_dist.at<float>(j,i) > 0 ){
               drawing.at<Vec3b>(j,i)[2] = 255 - (int) raw_dist.at<float>(j,i)*255/maxVal;
              }
            else{ 
              drawing.at<Vec3b>(j,i)[0] = 255; drawing.at<Vec3b>(j,i)[1] = 255; drawing.at<Vec3b>(j,i)[2] = 255;
              }
          }
     }

  /// 建立窗口顯示結果
  char* source_window = "Source";
  namedWindow( source_window, CV_WINDOW_AUTOSIZE );
  imshow( source_window, src );
  namedWindow( "Distance", CV_WINDOW_AUTOSIZE );
  imshow( "Distance", drawing );
執行一個輪廓中點的測試的函數原型:double pointPolygonTest(InputArray contour, Point2f pt, bool measureDist)
參數列表:輸入的輪廓、測試的點、標識;

第一個參數:輸入的輪廓;

第二個參數:針對某個的測試的點;

第三個參數:若是爲真,該函數將評估一個點到最近的輪廓的邊界的有符號距離;不然只檢查該點是否在輪廓內部。

該函數決策着該點在一個輪廓的內部,外部,或者恰好在輪廓的邊界上(或者恰好在輪廓的頂點上)。該函數返回爲正(內部),負(外部),0(在邊界上)。當measureDist = false,該函數返回+1,-1,0;否則返回的值是一個點到最近輪廓邊的有符號距離值。


圖像處理部分的例子算是都過了一遍了,接下來是ml部分

相關文章
相關標籤/搜索