OpenCVSharp4の画像モーメントで面積、重心計算

画像のモーメントからは、面積・重心など様々な情報がわかる。

 ↓使用例

negizoku.hatenablog.jp

 

p=q=0かつ画像Ixyが二値画像のとき、M00=x=0m1y=0n1Ixyとなり、画像の面積を表す。
また、M00,M10,M01を使って重心Gの座標(Gx,Gy)を表すことができる。
(Gx,Gy)=(xIxyIxy,yIxyIxy)=(M10M00,M01M00)

方法

  1. 画像の読み込み
  2. 二値化
  3. クロージング
  4. エッジ検出
  5. 輪郭を求める
  6. 輪郭からモーメント計算

プログラム

using System;  
using System.Linq;  
using OpenCvSharp;  

namespace imageMoment {  
    class Program {  
        static void Main(string[] args) {  
            //1.画像の読込  
            Mat src = new Mat(@"D:\Learning\OpenCV\picture.png");  


            //2.二値化  
            Mat bw = new Mat();  
            Cv2.CvtColor(src, bw, ColorConversionCodes.BGR2GRAY);  
            Cv2.Threshold(bw, bw, 1, 255, ThresholdTypes.Binary);  

            //3.クロージング  
            Cv2.MorphologyEx(bw, bw, MorphTypes.Close, Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3)));  
            Cv2.ImShow("bw", bw);  

            //4.エッジ検出  
            Mat edges = new Mat();  
            Cv2.Canny(bw, edges, 100, 255);  
            Cv2.ImShow("edges", edges);  

            //5.輪郭を求める  
            Point[][] contours;  
            HierarchyIndex[] hierarchyIndices;  
            edges.FindContours(out contours, out hierarchyIndices, RetrievalModes.CComp, ContourApproximationModes.ApproxSimple);  


            //6.輪郭からモーメント計算  
            double maxArea = 0;  
            int largestContour = 0;  
            for(int i = 0; i < contours.GetLength(0); ++i) {  
                if(hierarchyIndices[i].Parent != -1) { continue; }  
                {  
                    var array = contours[i].ToArray();  
                    var area = Cv2.ContourArea(array, false);  


                    if(area> maxArea){  
                        maxArea = area;  
                        largestContour = i;  
                    }  
                }  
            }  

            //7.結果の表示  
            Console.Write("ID:");  
            Console.WriteLine(largestContour);  
            Console.Write("面積:");  
            Console.WriteLine(maxArea);  
            Console.Write("周囲:");  
            Console.WriteLine(Cv2.ArcLength(contours[largestContour], true));  

            Console.WriteLine("******************************************");  
            Moments moments = Cv2.Moments(contours[largestContour]);  
            Console.WriteLine(moments.M00);  


            Point G = new Point();  
            G.X = (int)(moments.M10 / moments.M00);  
            G.Y = (int)(moments.M01 / moments.M00);  

            Console.Write("重心x:");  
            Console.WriteLine(G.X);  
            Console.Write("重心y:");  
            Console.WriteLine(G.Y);  

            src.Circle(G, 10, Scalar.Red, 2);  
            Cv2.ImShow("重心", src);  

            Cv2.WaitKey();  
        }  
    }  
}