靜态方法 | 描述 |
---|---|
Imgproc.findContours | 輪廓檢索方式,是形狀分析和對象檢測和識别的有用工具,參考 PCAExample示例 |
Imgproc.drawContours | 繪制輪廓輪廓或填充輪廓,與findContours 合用,參數== contourIdx==:-1為全部繪制,根據contours數量填寫,thickness:線條粗細,LineTypes 參數層次結構有關層次結構的可選資訊。僅當您隻想繪制一些輪廓時才需要它參數 ,maxLevel 繪制輪廓的最大級别。如果為 0,則僅繪制指定的輪廓。如果為 1,則該函數繪制等高線和所有嵌套的等高線。如果為 2,則函數繪制輪廓、所有嵌套輪廓、所有嵌套到嵌套輪廓,依此類推。僅當有可用的層次結構時才考慮此參數 |
Imgproc.contourArea | 輪廓區域,計算輪廓面積 |
Imgproc.arcLength | 計算輪廓周長或曲線長度,該函數計算曲線長度或閉合輪廓周長。 |
Imgproc.approxPolyDP | 以指定的精度逼近多邊形曲線。近似函數 |
Imgproc.boundingRect | 計算灰階圖像的點集或非零像素的右上邊界矩形 |
Imgproc.matchTemplate | 模闆比對,将模闆與重疊的圖像區域進行比較。參考場景示例== MatchTemplateExample== |
Imgproc.calcHist | 直方圖計算 |
Imgproc.equalizeHist | 均衡灰階圖像的直方圖 |
Imgproc.createCLAHE | 對一張圖進行區域劃分,然後再做智能直方圖均衡化 |
Imgproc.getStructuringElement | 自己定義一個核的大小,參數shape:形狀 Imgproc.MORPH_RECT矩形等等,ksize:核的大小,anchor:核的錨點,預設(-1,-1) |
Core.minMaxLoc | 查找數組中的全局最小值和最大值 |
一.圖像輪廓
① 輪廓檢索
Imgproc.findContours(image, contours, hierarchy, mode, method)參數解釋
1.mode
參數 | 描述 |
---|---|
Imgproc.RETR_EXTERNAL | 隻檢測最外面的輪廓 |
Imgproc.RETR_LIST | 檢測所有輪廓,并儲存到一條連結清單當中 |
Imgproc.RETR_CCOMP | 檢測所有輪廓,并分為兩層 |
Imgproc.RETR_TREE | 檢測所有輪廓,并重構嵌套輪廓的整個層次 |
2.method
參數 | 描述 |
---|---|
Imgproc.CHAIN_APPROX_NONE | 以Freeman鍊碼的方式輸出輪廓 |
Imgproc.CHAIN_APPROX_SIMPLE | 壓縮水準,垂直和斜的部分 |
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiclRnblN2XjlGcjAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHL51keOp3YE9UNNpHW4Z0MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnLmhDOkdzMkJTNxATNiZWYhVjY1QTZlRGNzYmYwMDO1czLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
void TestContours()
{
//讀取灰階圖
Mat mat = Imgcodecs.imread(Application.streamingAssetsPath + "/pca_test1.jpg");
Mat mat1 = new Mat();
//轉為灰階圖
Imgproc.cvtColor(mat, mat1, Imgproc.COLOR_BGR2GRAY);
//門檻值處理,作用是為了更好的去做輪廓檢測
Imgproc.threshold(mat1, mat1, 50, 255, Imgproc.THRESH_BINARY | Imgproc.THRESH_OTSU);
List<MatOfPoint> matOfPoints = new List<MatOfPoint>();
Mat hierarchy = new Mat();
//matOfPoints取得輪廓資料
Imgproc.findContours(mat1, matOfPoints, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_NONE);
Mat Apply = new Mat();
mat.copyTo(Apply);
// for (int i=0;i< matOfPoints.Count;i++)
//{
// Imgproc.drawContours(Apply, matOfPoints, i, new Scalar(255, 0, 0), 3);
//}
//把全部輪廓繪制到原圖上
Imgproc.drawContours(Apply, matOfPoints, -1, new Scalar(255, 0, 0), 3);
//計算第1個輪廓面積
//Imgproc.drawContours(Apply, matOfPoints, 0, new Scalar(255, 0, 0), 3);
//double area= Imgproc.contourArea(matOfPoints[0]);
計算第1個輪廓周長
//MatOfPoint2f ofPoint2F = new MatOfPoint2f(matOfPoints[0].toArray());
//double arclength = Imgproc.arcLength(ofPoint2F, true);
//Debug.Log(area);
//Debug.Log(arclength);
//輪廓圖
Texture2D texture = new Texture2D(Apply.cols(), Apply.rows(), TextureFormat.BGRA32, false);
Utils.matToTexture2D(Apply, texture);
rawImage.texture = texture;
//原圖
Texture2D texture1 = new Texture2D(mat.cols(), mat.rows(), TextureFormat.BGRA32, false);
Utils.matToTexture2D(mat, texture1);
GetRaw.texture = texture1;
}
② 輪廓近似
參數 | 描述 |
---|---|
approxCurve | 傳回一個近似結果 |
epsilon | 指定近似精度的參數。這是原始曲線與其近似值之間的最大距離 |
closed | 如果為true,近似曲線是閉合的 |
//輪廓近似
void TestapproxPolyDP()
{
//讀取灰階圖
Mat mat = Imgcodecs.imread(Application.streamingAssetsPath + "/pca_test1.jpg");
Mat mat1 = new Mat();
//轉為灰階圖
Imgproc.cvtColor(mat, mat1, Imgproc.COLOR_BGR2GRAY);
//門檻值處理,作用是為了更好的去做輪廓檢測
Imgproc.threshold(mat1, mat1, 50, 255, Imgproc.THRESH_BINARY | Imgproc.THRESH_OTSU);
List<MatOfPoint> matOfPoints = new List<MatOfPoint>();
Mat hierarchy = new Mat();
//matOfPoints取得輪廓資料
Imgproc.findContours(mat1, matOfPoints, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_NONE);
Mat Apply1f = new Mat();
mat.copyTo(Apply1f);
Mat Apply2f = new Mat();
mat.copyTo(Apply2f);
//取其中一條輪廓對比
MatOfPoint2f ofPoint2F = new MatOfPoint2f(matOfPoints[0].toArray());
//0.1的近似程度
double epsilon1=0.1f* Imgproc.arcLength(ofPoint2F, true);
MatOfPoint2f first1f= new MatOfPoint2f();
Imgproc.approxPolyDP(ofPoint2F, first1f, epsilon1, true);
MatOfPoint matOf1f = new MatOfPoint(first1f.toArray());
Imgproc.drawContours(Apply1f, new List<MatOfPoint> { matOf1f }, -1, new Scalar(255, 0, 0), 3);
Texture2D texture = new Texture2D(Apply1f.cols(), Apply1f.rows(), TextureFormat.BGRA32, false);
Utils.matToTexture2D(Apply1f, texture);
rawImage.texture = texture;
//0.02的近似程度
double epsilon2 = 0.02f * Imgproc.arcLength(ofPoint2F, true);
MatOfPoint2f first2f = new MatOfPoint2f();
Imgproc.approxPolyDP(ofPoint2F, first2f, epsilon2, true);
MatOfPoint matOf2f = new MatOfPoint(first2f.toArray());
Imgproc.drawContours(Apply2f, new List<MatOfPoint> { matOf2f }, -1, new Scalar(255, 0, 0), 3);
Texture2D texture1 = new Texture2D(Apply2f.cols(), Apply2f.rows(), TextureFormat.BGRA32, false);
Utils.matToTexture2D(Apply2f, texture1);
GetRaw.texture = texture1;
//
}
③邊界矩形和外接圓
void TestShape()
{
Mat mat = Imgcodecs.imread(Application.streamingAssetsPath + "/pca_test1.jpg");
Mat mat1 = new Mat();
//轉為灰階圖
Imgproc.cvtColor(mat, mat1, Imgproc.COLOR_BGR2GRAY);
//門檻值處理,作用是為了更好的去做輪廓檢測
Imgproc.threshold(mat1, mat1, 50, 255, Imgproc.THRESH_BINARY | Imgproc.THRESH_OTSU);
List<MatOfPoint> matOfPoints = new List<MatOfPoint>();
Mat hierarchy = new Mat();
//matOfPoints取得輪廓資料
Imgproc.findContours(mat1, matOfPoints, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_NONE);
Rect rect= Imgproc.boundingRect(matOfPoints[0]);
Mat Apply1f = new Mat();
mat.copyTo(Apply1f);
Debug.Log(rect);
//矩形框 外接圓
Imgproc.rectangle(Apply1f, new Point(rect.x, rect.y),new Point(rect.x+rect.width,rect.y+rect.height), new Scalar(255, 0, 0),3);
MatOfPoint2f matOfPoint2F = new MatOfPoint2f(matOfPoints[1].toArray());
Point center = new Point();
float[] radius = new float[1] ;
Imgproc.minEnclosingCircle(matOfPoint2F, center, radius);
Imgproc.circle(Apply1f, center,(int) radius[0], new Scalar(255, 0, 0), 3);
Texture2D texture = new Texture2D(Apply1f.cols(), Apply1f.rows(), TextureFormat.BGRA32, false);
Utils.matToTexture2D(Apply1f, texture);
rawImage.texture = texture;
//原圖
Texture2D texture1 = new Texture2D(mat.cols(), mat.rows(), TextureFormat.BGRA32, false);
Utils.matToTexture2D(mat, texture1);
GetRaw.texture = texture1;
}
二.模闆比對
參考文檔 https://www.w3cschool.cn/opencv/opencv-pswj2dbc.html
參數method解釋
填寫參數 | 描述 |
---|---|
Imgproc.TM_SQDIFF | 計算平方,值越小與相關 |
Imgproc.TM_SQDIFF_NORMED | 計算歸一化的平方值,值越接近0,越相關 |
Imgproc. TM_CCORR | 計算相關性,值越大越相關 |
Imgproc.TM_CCORR_NORMED | 計算歸一化相關性,值越接近1,越相關 |
Imgproc.TM_CCOEFF | 計算相關系數,值越大,越相關 |
Imgproc. TM_CCOEFF_NORMED | 計算歸一化相關系數,值越接近1,越相關 |
輸出resultmat=(A-a+1,B-b+1) 其中(A,B)為大圖,(a,b)為小圖
//模闆比對
void TestMatchTemplate()
{
Texture2D imgTexture = Resources.Load("lena") as Texture2D;
Texture2D tempTexture = Resources.Load("template2") as Texture2D;
Mat imgMat = new Mat(imgTexture.height, imgTexture.width, CvType.CV_8UC4);
Mat tempMat = new Mat(tempTexture.height, tempTexture.width, CvType.CV_8UC4);
Utils.texture2DToMat(imgTexture, imgMat);
Utils.texture2DToMat(tempTexture, tempMat);
//建立一個傳回結果的mat
int result_cols = imgMat.cols() - tempMat.cols() + 1;
int result_rows = imgMat.rows() - tempMat.rows() + 1;
Mat result = new Mat(result_rows, result_cols, CvType.CV_32FC1);
/*The mask應具有CV_8U或CV_32F深度和與模闆圖像相同數量的通道。在CV_8U情況下,
* mask值被視為二進制,即零和非零。在CV_32F情況下,值應該落在[0..1]範圍内,
* 并且模闆像素将乘以相應的The mask像素值。由于樣本中的輸入圖像具有CV_8UC3類型,
* 是以屏蔽也被讀取為彩色圖像。*/
/*目前隻有兩種比對方法接受掩碼:CV_TM_SQDIFF和CV_TM_CCORR_NORMED*/
/* if( match_method == Imgproc.TM_SQDIFF || match_method == Imgproc.TM_SQDIFF_NORMED )
{ matchLoc = mmr.minLoc; }
else
{ matchLoc = mmr.maxLoc; } 這是文檔java描述*/
Imgproc.matchTemplate(imgMat, tempMat, result, Imgproc.TM_SQDIFF_NORMED);
Mat mask = new Mat();
//傳回最大值和最小值
MinMaxLocResult minMaxLoc= Core.minMaxLoc(result);
double minx = minMaxLoc.minLoc.x;
double miny = minMaxLoc.minLoc.y;
Debug.Log(new Point(minx + tempMat.cols(), miny + tempMat.rows()));
Debug.Log(minMaxLoc.minLoc);
Imgproc.rectangle(imgMat, minMaxLoc.minLoc, new Point(minx + tempMat.cols(),miny+tempMat.rows()), new Scalar(0, 255, 0, 255), 2);
Texture2D texture = new Texture2D(imgMat.cols(), imgMat.rows(), TextureFormat.BGRA32, false);
Utils.matToTexture2D(imgMat, texture);
rawImage.texture = texture;
//原圖
Texture2D texture1 = new Texture2D(tempMat.cols(), tempMat.rows(), TextureFormat.BGRA32, false);
Utils.matToTexture2D(tempMat, texture1);
GetRaw.texture = texture1;
}
三.直方圖
什麼是直方圖?
- 直方圖是将資料組織成一組預定義倉的收集計數
- 當我們說資料時,我們并不把它限制為強度值(正如我們在前面的教程中看到的)。收集的資料可以是您發現有用的描述您的圖像的任何功能。
unity3d OpenCVForUnity(二) 方法 Imgproc.calcHist ( List< Mat > images,MatOfInt channels,Mat mask,Mat hist,MatOfInt histSize,MatOfFloat ranges,bool accumulate )
對應參數解釋
- image:傳入一個數組,對原圖像格式像素采集,bins
- channels:如果是灰階圖 new MatOfInt (0),如果是彩色圖像傳入new MatOfInt (0,1,2) 分别對應BGR
- mask : 掩膜圖像 ,統計自己劃定的區域
- hist : 輸出參數 ,得到mat資訊
- histSize :bins的數量,詳情在圖檔裡
- ranges:像素取值範圍[0,255]
void TestCalchist()
{
//讀取灰階圖
Mat mat = Imgcodecs.imread(Application.streamingAssetsPath + "/lena.jpg");
Mat mat1 = new Mat();
//轉為灰階圖
Imgproc.cvtColor(mat, mat1, Imgproc.COLOR_BGR2GRAY);
List<Mat> mats = new List<Mat>();
mats.Add(mat1);
Mat b_hist = new Mat();
//取16個區域
Imgproc.calcHist(mats, new MatOfInt(0), new Mat(), b_hist, new MatOfInt(16), new MatOfFloat(0, 255));
Debug.Log(b_hist);
int hist_w = (int)mat.size().width; int hist_h = (int)mat.size().height;
//每一條資料的間隔
int bin_w = (int)Mathf.Round(hist_w / b_hist.rows());
Mat histImage = new Mat(mat.size(), CvType.CV_8UC3, new Scalar(0,0,0));
//歸一化
Core.normalize(b_hist, b_hist, 0, histImage.rows(), Core.NORM_MINMAX, -1, new Mat());
for (int i = 0; i < b_hist.rows()-1; i++)
{
for (int j = 0; j < b_hist.cols(); j++)
{
//得到對應像素的b值
int b_first= (int)b_hist.get(i, j)[0];
int b_Second = (int)b_hist.get(i+1, j)[0];
Debug.Log(bin_w * i + " "+ bin_w * (i + 1));
Point point1 = new Point(bin_w *i, hist_h - b_first);
Point point2 = new Point(bin_w*(i+1), hist_h- b_Second);
//畫線
Imgproc.line(histImage, point1, point2, new Scalar(0, 0, 255,1), 2, 8, 0);
}
}
Texture2D texture = new Texture2D(histImage.cols(), histImage.rows(), TextureFormat.BGRA32, false);
Utils.matToTexture2D(histImage, texture);
rawImage.texture = texture;
}
均衡化原理
灰階值[0,255] | 像素個數 | 機率 | 累計機率 | 映射後灰階值 |
---|---|---|---|---|
50 | 4 | 4/16=0.25 | 0.25+0=0.25 | 0.25*(255-0)=63.75 |
128 | 3 | 0.1875 | 0.25+0.1875=0.4375 | 0.4375*(255-0)=111.56 |
200 | 5 | 0.3125 | 0.75 | 191.25 |
255 | 4 | 0.25 | 1 | 255 |
映射完後的值再取整
①測試
//均衡化
void TestEqualizeHist()
{
//輸出灰階圖
Mat mat = Imgcodecs.imread(Application.streamingAssetsPath + "/lena.jpg",0);
Mat mat1 = new Mat();
mat.copyTo(mat1);
Imgproc.equalizeHist(mat1, mat1);
Texture2D texture = new Texture2D(mat1.cols(), mat1.rows(), TextureFormat.BGRA32, false);
Utils.matToTexture2D(mat1, texture);
rawImage.texture = texture;
//原圖
Texture2D texture1 = new Texture2D(mat.cols(), mat.rows(), TextureFormat.BGRA32, false);
Utils.matToTexture2D(mat, texture1);
GetRaw.texture = texture1;
}
②自适應直方圖均衡化
在上面代碼添加自适應均衡化代碼,看看效果吧
CLAHE cLAHE= Imgproc.createCLAHE(2, new Size(8, 8));
cLAHE.apply(mat1, mat1);