[VS] C# - [02] EmguCV 影像处理(灰阶、通道撷取、遮罩相减)

摘要

本章节将把读取的影像进行处理如灰阶、分别撷取R, G, B通道、针对影像通道减少颜色操作,最后把显示的影像做保存,本篇依照上一篇[VS] C# - [01] EmguCV 影像读取的程式继续操作。


实作

介面设置

介面的部份把各转换的方式分成不同的按钮进行使用。


图一 主程式介面

Enum

在转换影像的时候,很多按钮处理的方式大同小异,因此我们会把重複性高的程式做一个函数,使用该函数只要丢进影像与转换类型即可获得预期输出,使用字串的方式传递会容易使错误,所以採用 enum (列举)的方式建立我们所需要的类型。

public enum EColorType{    Blue = 0,    Green,    Red,    Gray}

灰阶与影像通道处理

我们接取的影像型态为Image<Bgr, Byte>,经过转换灰阶或者是单独撷取通道的时候皆为一个通道,因此在输出的影像时候则为Image<Gray, Byte>的型态。

虽说接下来在按钮按下的时候会先检测影像是否存在,但为了安全起见,还是会从函式里面做一个检测影像是否为 null ,若为 null 透过 throw new 的方式建立我们所需要掷出的例外(Exception)资讯。

我们输入的影像型态为 Bgr 的格式,因此我们使用 a_bitmap[index] 当中的 index 位置做为通道如 [0] = B, [1] = G, [2] = R,因此我们只要将通道撷取出来即可完成我们要提取的通道。

Bgr 的格式转换成 Gray 的方式也只需要透过Convert<TColor, TDepth>方式进行转换。

参考资料:Image<TColor, TDepth>.Convert Method

private Image<Gray, Byte> ChanneConvert1(Image<Bgr, Byte> a_bitmap, EColorType a_type){    if (a_bitmap == null)    {        throw new NullReferenceException("影像不得为空。");    }    Image<Gray, Byte> convertImage;    // 颜色转换    switch (a_type)    {        case EColorType.Blue:            convertImage = a_bitmap[0].Clone();            break;        case EColorType.Green:            convertImage = a_bitmap[1].Clone();            break;        case EColorType.Red:            convertImage = a_bitmap[2].Clone();            break;        case EColorType.Gray:            convertImage = a_bitmap.Convert<Gray, Byte>().Clone();            break;        default:            throw new NullReferenceException("无其他类型。");    }    return convertImage;}

若不想要影像进来时因为掷出例外使程式中断,可以採用回传空影像(预设影像)的方式并带着错误的资讯显示给使用者,下面的方法则是将影像直接做一个 new Image<Gray, Byte> 并在每个像素预设为 Gray(255) ,也就是预设白影像。

convertImage = new Image<Gray, Byte>(m_image.Width, m_image.Height, new Gray(255));MessageBox.Show("影像显示错误。", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);

保留颜色

这边保留颜色指的是使用原图pixelA=(233, 50, 30)遮罩(0, 255, 255)进行相减保留蓝色的像素,最后会变成pixelA=(233, 0, 0),当然你也可以用图片作为参考遮罩,也许该称为滤镜比较适当。

Image<TColor, TDepth>.Sub Method

private Image<Bgr, Byte> ChannelReduce1(Image<Bgr, Byte> a_bitmap, EColorType a_type){    if (a_bitmap == null)    {        throw new NullReferenceException("影像不得为空。");    }    Image<Bgr, Byte> convertImage;    // 颜色转换    switch (a_type)    {        case EColorType.Blue:            convertImage = a_bitmap.Sub(new Bgr(0, 255, 255)).Clone();            break;        case EColorType.Green:            convertImage = a_bitmap.Sub(new Bgr(255, 0, 255)).Clone();            break;        case EColorType.Red:            convertImage = a_bitmap.Sub(new Bgr(255, 255, 0)).Clone();            break;        default:            throw new NullReferenceException("无其他类型。");    }    return convertImage;}

保存影像

Image<TColor, TDepth> 格式众多,为了方便这边直接使用 Bitmap 的方式进行影像保存,只要使用 Save() 的函式并带上路径与档案名称就可以完成保存,为了让开发者了解影像是否保存成功,使用 bool 的方式来进行响应,因路径或者是档名可能会有错误,因此採用 try catch 的方式掌控。

private bool SaveImage(Bitmap a_image, string a_path, string a_fileName){    try    {        a_image.Save($"{a_path}/{a_fileName}");        return true;    }    catch (Exception e)    {        MessageBox.Show(e.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);        return false;    }}

元件

因大部分影像处理的功能皆为重複操作,因此只用按钮第一个(蓝)色作为显示,只需要改变函式中的 EColorType.{名称} 就可以对应各功能了。

灰阶影像:

private void button2GrayImage_Click(object sender, EventArgs e){    if (m_image == null) return;    pictureBoxDisplayImage.Image = (Bitmap)ChanneConvert1(m_image, EColorType.Gray).ToBitmap().Clone();    pictureBoxDisplayImage.Invalidate();}蓝:private void buttonChannelBlue_Click(object sender, EventArgs e){    if (m_image == null) return;    pictureBoxDisplayImage.Image = (Bitmap)ChanneConvert1(m_image, EColorType.Blue).ToBitmap().Clone();    pictureBoxDisplayImage.Invalidate();}保留蓝:private void buttonKeepBlue_Click(object sender, EventArgs e){    if (m_image == null) return;        pictureBoxDisplayImage.Image = (Bitmap)ChannelReduce1(m_image, EColorType.Blue).ToBitmap().Clone();    pictureBoxDisplayImage.Invalidate();}影像保存:private void buttonSaveImage_Click(object sender, EventArgs e){    // "./" 代表当前路径    // 后面名称需附上副档名    if (SaveImage((Bitmap)pictureBoxDisplayImage.Image, "./", "save_image.bmp") == true)    {        MessageBox.Show("保存影像成功。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);    }     else    {        MessageBox.Show("保存影像失败。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);    }}

结果


图二 灰阶影像


图三 蓝通道


图四 透过遮罩显示的保留蓝


图五 保存影像结果

结论

EmguCV在影像的操作是非常的完整,在这边你已经学会了如何把读取影像进来的影像做简易的处理,如整张影像灰阶、提取通道、透过Sub遮罩减掉通道这些操作,下一篇我们将会学到 Panel 与 Dock 进行元件编排,以及使用 EmguCV 所提供的 ImageBox 元件取代 PictureBox。

Github: Link.


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章