c# opencvsharp学习笔记(6)直方图与反向投影直方图

1.直方图

先来对灰度图计算

        //     computes the joint dense histogram for a set of images.
        //      计算一组图像的联合密集直方图。
        // 参数:
        //   images://输入图像
        //
        //   channels://通道,输入图像是哪个通道
        //
        //   mask://掩码一般直接用 Mat mask = new Mat ();也就是不做掩码
        //
        //   hist://输出也是一个mat
        //
        //   dims://维数
        //
        //   histSize://箱子数量,多少不同像素值就有多少个箱子,例如灰度图像就是256个
        //                  0号箱子装的就是值位0的像素数量
        //   ranges://像素值范围
        //
        //   uniform:
        //
        //   accumulate:
        public static void CalcHist(Mat[] images, int[] channels, InputArray mask, OutputArray hist, int dims, int[] histSize, float[][] ranges, bool uniform = true, bool accumulate = false);

public static void CalcHist(Mat[] images, int[] channels, InputArray mask, OutputArray hist, int dims, int[] histSize, Rangef[] ranges, bool uniform = true, bool accumulate = false);
//直方图也是c++有写差别的地方,从形参上来看就比c++的少了个图片数量
Mat panda = new Mat(@"滚滚.png", ImreadModes.GrayScale);//读取为灰度图

            Mat[] mats = new Mat[] { panda};//一张图片,初始化为panda
            Mat hist = new Mat();//用来接收直方图
            int[] channels = new int[] { 0};//一个通道,初始化为通道0
            int[] histsize = new int[] { 256};//一个通道,初始化为256箱子
            Rangef[] range = new Rangef[1];//一个通道,值范围
            range[0].Start = 0.0F;//从0开始(含)
            range[0].End = 256.0F;//到256结束(不含)
            Mat mask = new Mat();//不做掩码
            Cv2.CalcHist(mats, channels, mask, hist, 1, histsize, range);//计算灰度图,dim为1 1维

            Console.WriteLine(hist.Rows + "行" + hist.Cols + "列");//把输出的行列打印出来


            Cv2.ImShow("处理后", panda);
            Cv2.WaitKey();

输出结果c# opencvsharp学习笔记(6)直方图与反向投影直方图_第1张图片

再把灰度图画出来


/在前面的基础上
          //Console.WritleLine的后面加上
            for (int i = 0; i < 256; i++)//画直方图
            {
              
                int len = (int)((hist.Get(i) / 10000) * panda.Rows);//单个箱子的长度,
                                                  // 10000) * panda.Rows)的作用只是让他变短,别超出了
                Cv2.Line(panda, i, 0, i, len, Scalar.Black, 2);//把线画出来
              
            }

可以看到开头和末尾,高耸入云,毕竟是熊猫啊。c# opencvsharp学习笔记(6)直方图与反向投影直方图_第2张图片

接下来对彩图计算

Mat panda = new Mat(@"滚滚.png", ImreadModes.AnyColor);//读取为彩图
            Mat[] mats = new Mat[] { panda};//一张图片,初始化为panda
            //Mat hist = new Mat();//用来接收直方图
            int[] channels = new int[] { 0,1,2};//三个通道,初始化为通道0
            int[] histsize = new int[] { 256,256,256};//三个通道,初始化为256箱子
            Rangef[] range = new Rangef[3];//三个通道,范围
            range[0].Start = 0.0F;//从0开始(含)
            range[0].End = 256.0F;//到256结束(不含)
            range[1] = range[0];//通道2和通道1一样
            range[2] = range[0];//通道3和通道1一样
            Mat mask = new Mat();//不做掩码
            SparseMat hist0 = new SparseMat(histsize, MatType.CV_32F);
            
            Cv2.CalcHist(mats, channels, mask,hist0 ,3, histsize, range);//dim为3 3维
            
          Console.WriteLine(hist.Rows + "行" + hist.Cols + "列");
             //这是照着c++写的,然而它并不能运行,这是因为opencvsharp没有针对稀疏矩阵的重载
             //具体原因不明

对于此我们可以将个1个3个通道图像拆分成3个1通道的图像

            Mat panda = new Mat(@"滚滚.png", ImreadModes.AnyColor);//读取为彩图

            Mat[] mats =Cv2.Split(panda);//一张图片,将panda拆分成3个图片装进mat
            Mat[] mats0 = new Mat[] { mats[0]};//panda的第一个通道,也就是B
            Mat[] mats1 = new Mat[] { mats[1] };//panda的第二个通道,也就是G
            Mat[] mats2 = new Mat[] { mats[2] };//panda的第三个通道,也就是R

            Mat[] hist = new Mat[] {new Mat(),new Mat (),new Mat ()};//一个矩阵数组,用来接收直方图,记得全部初始化
            int[] channels = new int[] { 0};//一个通道,初始化为通道0,这些东西可以共用设置一个就行
            int[] histsize = new int[] { 256};//一个通道,初始化为256箱子
            Rangef[] range = new Rangef[1];//一个通道,范围
            range[0].Start = 0.0F;//从0开始(含)
            range[0].End = 256.0F;//到256结束(不含)
            Mat mask = new Mat();//不做掩码

            Cv2.CalcHist(mats0, channels, mask, hist[0],1, histsize, range);//对被拆分的图片单独进行计算
            Cv2.CalcHist(mats1, channels, mask, hist[1], 1, histsize, range);//对被拆分的图片单独进行计算
            Cv2.CalcHist(mats2, channels, mask, hist[2], 1, histsize, range);//对被拆分的图片单独进行计算

            for (int i = 0; i < 3; i++)
            {
                Console.WriteLine(hist[i].Rows + "行" + hist[i].Cols + "列");
            }
           
           Cv2.ImShow("处理后", panda);
           Cv2.WaitKey();
运行结果c# opencvsharp学习笔记(6)直方图与反向投影直方图_第3张图片

画出彩图的直方图

           //在Cv2.ImShow("处理后", panda);前面加上
           Scalar[] color = new Scalar[] { Scalar.Blue, Scalar.Green, Scalar.Red };//BGR线条颜色
            for (int i = 0; i < 256; i++)//画直方图
            {
               
                for (int j = 0; j < 3; j++)
                {   int len = (int)((hist[j].Get(i) / 10000) * panda.Rows);
                    Cv2.Line(panda,i,0,i,len, color[j], 2);
                 }
               
           }
c# opencvsharp学习笔记(6)直方图与反向投影直方图_第4张图片

2.反向投影直方图

// 摘要:
        //     computes the joint dense histogram for a set of images.
        //计算一组图像的联合稠密直方图。
        // 参数:
        //   images:
        //图像
        //   channels:
        //通道
        //   hist:
        //直方图
        //   backProject:
        //反向投影直方图
        //   ranges:
        //范围
        //   uniform:
        public static void CalcBackProject(Mat[] images, int[] channels, InputArray hist, OutputArray backProject, Rangef[] ranges, bool uniform = true);

        
              Mat panda = new Mat(@"滚滚.png", ImreadModes.AnyColor);//读取为彩图 
            Mat src = new Mat();
            panda.CopyTo(src);//作为对比
            Rect rect = new Rect(30, 250, 50, 50);//roi的区域
            Mat roi = new Mat(panda, rect);//定义roi
            Cv2.Rectangle(src, rect, Scalar.White);
            Cv2.ImShow("roi", src);
            Mat[] mats = Cv2.Split(roi);//一张图片,将panda拆分成3个图片装进mat 
            Mat[] mats0 = new Mat[] { mats[0] };//panda的第一个通道,也就是B 
            Mat[] mats1 = new Mat[] { mats[1] };//panda的第二个通道,也就是G 
            Mat[] mats2 = new Mat[] { mats[2] };//panda的第三个通道,也就是R 
            Mat[] hist = new Mat[] { new Mat(), new Mat(), new Mat() };//一个矩阵数组,用来接收直方图,记得全部初始化 
            int[] channels = new int[] { 0 };//一个通道,初始化为通道0,这些东西可以共用设置一个就行 
            int[] histsize = new int[] { 256 };//一个通道,初始化为256箱子 
            Rangef[] range = new Rangef[1];//一个通道,范围 
            range[0].Start = 0.0F;//从0开始(含) 
            range[0].End = 256.0F;//到256结束(不含) 
            Mat mask = new Mat();//不做掩码
            Cv2.CalcHist(mats0, channels, mask, hist[0], 1, histsize, range);//对被拆分的图片单独进行计算
            Cv2.CalcHist(mats1, channels, mask, hist[1], 1, histsize, range);
            Cv2.CalcHist(mats2, channels, mask, hist[2], 1, histsize, range);


            Mat[] pandas = new Mat[] { panda };
            Mat[] histBack = new Mat[] { new Mat(), new Mat(), new Mat() };//用来接收转换的反向直方图
            Cv2.CalcBackProject(pandas, channels, hist[0], histBack[0], range);
            Cv2.CalcBackProject(pandas, channels, hist[1], histBack[1], range);
            Cv2.CalcBackProject(pandas, channels, hist[2], histBack[2], range);
            Cv2.Merge(histBack, panda);
            Cv2.ImShow("处理后", panda);
            Cv2.WaitKey();

所谓反向投影就是首先计算某一特征的直方图模型,然后使用模型去寻找图像中存在的该特征。。如果吧图像的某个区域含有特定和的纹理和物体,这个区域的的直方图就可以看作是一个函数,该函数返回某个像素属于这个特殊纹理或物体的概率;

c# opencvsharp学习笔记(6)直方图与反向投影直方图_第5张图片

可以看出越黑的地方概率越低,不过这样还是不太适合人看。实际上更多的时候使用一个通道就够,为了突出被寻找物体的特征,一般将图片转换成HSV空间,仅使用色调的通道,

并且过滤掉较低饱和度的像素,因为饱和度在较低时色调会变得不稳定


            Mat panda = new Mat(@"sky.png", ImreadModes.AnyColor);//读取为彩图
            Mat src = new Mat();
            panda.CopyTo(src);//作为对比
            
            Mat[] hist = new Mat[] {new Mat()};//一个矩阵数组,用来接收直方图,记得全部初始化
            int[] channels = new int[] { 0};//一个通道,初始化为通道0,这些东西可以共用设置一个就行
            int[] histsize = new int[] {256};//一个通道,初始化为256箱子
            Rangef[] range = new Rangef[1];//一个通道,范围
            range[0].Start = 0.0F;//从0开始(含)
            range[0].End = 180.0F;//到180结束(不含)色调的范围0到180
            Cv2.CvtColor(panda, panda, ColorConversionCodes.BGR2HSV);//将图片转换成HSV空间

            Rect rect = new Rect(30,550,50, 50);//roi的区域
            Mat roi = new Mat(panda,rect);//定义roi
            Cv2.Rectangle(src, rect, Scalar.White);
            Cv2.ImShow("roi", src);

            Mat[] mats = Cv2.Split(roi);//将图片拆分
            Mat mask  =new Mat();//掩码
            Cv2.Threshold(mats[1], mask,50, 255, ThresholdTypes.Binary);//过滤掉较低饱和度的像素
           
            Mat[] mats0 = new Mat[] { mats[0] };//图片的第一个通道,也就是H,色调
            Cv2.CalcHist(mats0, channels, mask, hist[0],1, histsize, range);//转换成直方图

            Mat[] pandas = new Mat[] { panda };
            Mat[] histBack = new Mat[] { new Mat()};//一个通道就够
            Cv2.CalcBackProject(pandas, channels, hist[0], histBack[0], range);//转换成反向直方图

            Cv2.Threshold(histBack[0], histBack[0], 120, 255, ThresholdTypes.Binary);//二值化,更容易看出来,去不去无所谓
            Cv2.ImShow("处理后", histBack[0]);
            Cv2.WaitKey(););

运行结果roi是最下角的那朵花

c# opencvsharp学习笔记(6)直方图与反向投影直方图_第6张图片

你可能感兴趣的:(c#,opencvsharp)