【Emgu.CV教程】第16篇 、色彩处理之灰度图

        我们看到的彩色图像,一般都是BGR颜色空间的,也就是一副图像,是由蓝色通道、绿色通道、红色通道组合而成。而灰度图只有一个通道,他有256个灰度等级,255代表全白,0表示全黑。

        注意啊,下面这副黑白图像,利用Emgu.CV的默认方式读取的时候,可不是灰度图,而是BGR格式的彩色图片。

【Emgu.CV教程】第16篇 、色彩处理之灰度图_第1张图片

        读取过程如下,您看是不是个三通道的BGR颜色空间图片,这个时候要是遍历srcMat的所有像素点,您会发现它每个像素点上三个通道的值是相同的。它其实可以看成是三个完全相同的灰度图组成。

【Emgu.CV教程】第16篇 、色彩处理之灰度图_第2张图片

       记住:灰度图是单通道、彩色图片是三通道,不是黑白色的图像就是灰度图。

       那要怎么把Emgu.CV的读取的图片转成灰度图呢?下面以  lena.jpg 举例。

【Emgu.CV教程】第16篇 、色彩处理之灰度图_第3张图片

1、CvtColor()转灰度图

        可以使用CvtColor(),官方介绍如下:

public static void CvtColor(
    IInputArray src, // 输入图像
    IOutputArray dst, // 输出图像
    ColorConversion code, // 颜色空间转换代码
    int dstCn = 0 // 输出图像的通道数,默认值为 0,可以不写
)

        这个函数就是完成颜色空间转换,功能非常强大,当BGR转灰度图时,要选择 ColorConversion.Bgr2Gray,使用方式如下:

Mat dstMat = srcMat.Clone();
CvInvoke.CvtColor(dstMat, dstMat, ColorConversion.Bgr2Gray);
CvInvoke.Imshow("CvtColor gray Mat, " + dstMat.Size.ToString(), dstMat);

        lena.jpg转成灰度图的效果如下:

【Emgu.CV教程】第16篇 、色彩处理之灰度图_第4张图片

2、更进一步的背景知识

        其实是我从网上搜集到的,BGR转灰度图,是有很多算法的。使用不同的算法,得到的灰度图结果也不一样,比如:

  • 平均值法:Gray = (Red + Green + Blue) / 3
  • 最大灰度值法:Gray = Max(Red, Green, Blue) 
  • 最小灰度值法:Gray = Max(Red, Green, Blue) 
  • 加权平均 - - 浮点处理法:Gray = (Red * 0.299 + Green * 0.587 + Blue * 0.114)
  • 加权平均 - - 整数处理法:Gray = (Red * 30 + Green * 59 + Blue * 11) / 100

       Emgu.CV里的CvtColor()函数,更准确的说是OpenCV里的CvtColor()函数采用的是什么算法,我也不知道。读者与兴趣可以去github上研究研究。

3、Decolor()脱色处理

        这个介绍的不多哈,读者们赚了。彩色图片转灰度图时,除了用最常见的CvtColor()函数以外,还有一个Decolor()函数,与CvtColor()函数相比,更能保持原始图像的颜色对比度。这个算法更加复杂,该代码是源于香港中文大学计算机科学与工程系的一篇论文 ,链接地址如下:

Contrast Preserving Decolorization

        不想研究源码的读者,直接看下面的使用方法:

Mat tempMat = srcMat.Clone();
Mat dstMat1 = new Mat();
Mat dstMat2 = new Mat();
Mat colorBoostMat = new Mat();
CvInvoke.Decolor(tempMat, dstMat1, colorBoostMat);
CvInvoke.CvtColor(tempMat, dstMat2, ColorConversion.Bgr2Gray);
CvInvoke.Imshow("Decolor() gray Mat, " + dstMat1.Size.ToString(), dstMat1);
CvInvoke.Imshow("Decolor() color boost Mat, " + colorBoostMat.Size.ToString(), colorBoostMat);
CvInvoke.Imshow("CvtColor gray Mat, " + dstMat2.Size.ToString(), dstMat2);

         原始图片srcMat、Decolor()脱色后的灰度图、CvtColor()直接转换的灰度图如下:

【Emgu.CV教程】第16篇 、色彩处理之灰度图_第5张图片

         可以看到,Decolor()脱色后的灰度图明暗对比要更明显一些。这个函数比较适合这种透雾处理的图片,但是运算速度要明显比CvtColor()函数慢很多,一般情况下还是选择用CvtColor()函数。

4、手搓算法转灰度图

        据说是采用 加权平均更符合人眼的视觉效果,而且整数法又要快于浮点法。那接下来我们自己也可以写一个算法,试一试把BGR图像转灰度图:

int width = srcMat.Cols;
int height = srcMat.Rows;
Mat dstMat = new Mat(new System.Drawing.Size(width, height), DepthType.Cv8U, 1);
Mat tempMat = srcMat.Clone();
Image dstImage = new Image(width, height);
Image tempImage = tempMat.ToImage();
for (int i = 0; i < height; i++)
{
    for (int j = 0; j < width; ++j)
    {
        dstImage.Data[i, j, 0] = ((11 * tempImage.Data[i, j, 0]) + (59 * tempImage.Data[i, j, 1]) + (30 * tempImage.Data[i, j, 2])) / 100;
    }
}

dstMat = dstImage.Mat;
dstMat.ConvertTo(dstMat, DepthType.Cv8U);
CvInvoke.Imshow("Custom function gray Mat, " + dstMat.Size.ToString(), dstMat);

        转换后的lena.jpg如下图:

【Emgu.CV教程】第16篇 、色彩处理之灰度图_第6张图片

        将lena.jpg转灰度图时,用Emgu.CV的CvtColor()函数用时0.012秒,手搓的算法用时0.019秒,慢差不多0.007秒,如果使用C++配合OpenCV应该更快。看到了吧,差距不小,为什么OpenCV这么流行,人家是有很高的技术含量的。至于有多高,两层楼那么高吧。

        灰度图只有亮度信息而没有颜色信息,这种特性使得它在在图像处理领域中应用非常广泛,包括:

  • 去除颜色影响后,灰度图像可以更容易地反应图像的纹理、边缘。比如医学领域里的X光、CT影像图片。
  • 灰度图每个点就256个维度,而BGR图每个点有256 * 256 * 256 = 16777216个维度,寻找特征时计算量太大了。
  • 相比彩色图像,减少了三分之二的存储空间。

        一般来说,为了寻找特征,转换完成灰度图后,接下来会紧跟着下一步:二值化。那什么是二值化,二值化怎么转换,二值化后又有什么好处呢。下一篇将详细举例。

原创不易,请勿抄袭。共同进步,相互学习。

你可能感兴趣的:(Emgu.CV使用教程,计算机视觉,c#,图像处理,Emgu.CV)