天天看點

unity3d OpenCVForUnity(二)

靜态方法 描述
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 壓縮水準,垂直和斜的部分
unity3d OpenCVForUnity(二)
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,近似曲線是閉合的
unity3d OpenCVForUnity(二)
//輪廓近似
    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;
        //
    }
           

③邊界矩形和外接圓

unity3d OpenCVForUnity(二)
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)為小圖

unity3d OpenCVForUnity(二)
//模闆比對
    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;
    }
           
unity3d OpenCVForUnity(二)

均衡化原理

unity3d OpenCVForUnity(二)
灰階值[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

映射完後的值再取整

①測試

unity3d OpenCVForUnity(二)
//均衡化
    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);
           

繼續閱讀