Opencv2.4學習::輪廓矩
輪廓矩
原理部分:
矩
一、概率論上的定義
看到矩這個字,很容易聯想到概率論,在概率論中,定義如下:
或者說:
設 X 和 Y 是隨機變數,c 為常數,k 為正整數, 如果E(|X−c|^k)E(|X−c|^k)存在,則稱E(|X−c|^k)E(|X−c|^k)為 X 關於點 c 的 k 階矩。
- c = 0 時, 稱為 k 階原點矩;
- c = E(x) 時,稱為 k 階中心矩。
如果E(|X−c1|^p⋅|Y−c2|^q)存在,則稱其為 X,Y 關於 c 點 p+q 階矩。
二、在影象學上的定義
一幅M×N的數字影象f(i,j),其p+q階幾何矩和中心矩
其中:
- f(i,j)為影象在座標點(i,j)處的灰度值。
- 重心:,也是影象的一階矩
三、幾何矩的基本意義
(1)零階矩
可以發現,當影象為二值圖時,就是這個影象上白色區域的總和,因此,可以用來求二值影象(輪廓,連通域)的面積。
(2)一階矩
當影象為二值圖時,就是白色畫素關於x座標的累加和,而則是y座標的累加和
由此,可獲得影象的重心:,也就是前文提到的。
(3)二階矩
四、由幾何矩可表示出中心距如下:
為了消除影象比例變化帶來的影響,定義規格化中心矩如下:
利用二階和三階規格中心矩可以匯出下面7個不變矩組(Φ1 Φ7),它們在影象平移、旋轉和比例變化時保持不變
Opencv應用部分
核心函式:
(1)求矩
Moments moments(inputArray array, bool binaryImage=false)
- 輸入引數,可以是光柵影象(單通道,8位或浮點的二維陣列)或二維陣列(1N或N1)
- 預設值false,若此引數取true,則所有非零畫素為1.此引數僅對影象使用
(2)計算輪廓面積
double contourArea(inputArray contour, bool oriented=false)
- 輸入的向量,二維點(輪廓頂點)
- 面向區域識別符號,若為true,該函式返回一個帶符號的面積值,其正負取決於輪廓的方向(順時針還是逆時針)。根據這個特性我們可以根據面積的符號來確定輪廓的位置。需要注意的是,這個引數有預設值false,表示以絕對值返回,不帶符號。
(3) 計算輪廓長度
double arcLength(inputArray curve,bool closed)
- 輸入的二維點集
- 一個用於指示曲線是否封閉的識別符號,預設值closed,表示曲線封閉
一、求影象的重心和方向
前面提到二階矩可以用來求物體形狀的方向。
其中:
,
,
fastAtan2()為opencv的函式,輸入向量,返回一個0-360的角度。
個人認為:關於fastAtan2()的推算如下:
測試程式碼:
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/features2d/features2d.hpp>
#include<stdlib.h>
#include<stdio.h>
#include<iostream>
using namespace std;
using namespace cv;
void main()
{
Mat srcImg;
srcImg = imread("F:\\opencv_re_learn\\flash.jpg");
if (!srcImg.data){
cout<< "failed to read" << endl;
system("pause");
return;
}
Mat srcGray;
cvtColor(srcImg, srcGray, CV_BGR2GRAY);
Mat thresh;
threshold(srcGray, thresh, 100, 255, CV_THRESH_BINARY_INV |
CV_THRESH_OTSU);//二值化時主要要讓目標部分是白色畫素
Moments m = moments(thresh, true);//moments()函式計算出三階及一下的矩
Point2d center(m.m10 / m.m00, m.m01 / m.m00);//此為重心
//計算方向
double a = m.m20 / m.m00 - center.x*center.x;
double b = m.m11 / m.m00 - center.x*center.y;
double c = m.m02 / m.m00 - center.y*center.y;
double theta = fastAtan2(2 * b, (a - c)) / 2;//此為形狀的方向
cout << 2 * b << endl;
cout << a - c << endl;
cout <<"角度是:"<< theta << endl;
//繪製重心
circle(srcImg, center, 2, Scalar(0, 0, 255),2);
imshow("src", srcImg);
imshow("Gray", srcGray);
imshow("Thresh", thresh);
waitKey(0);
}
未完待續
參考文章: