Emgu学习之(三)——操作图像数据
内容
在这篇⽂章中将提到以下内容:
修改像素值
图像ROI
图像加法
图像减法
按位运算
图像混合
准备⼯作
创建⼯程:参考创建⼀个WinForm项⽬
Form1.cs引⽤命名空间:
1using Emgu.CV;
2using Emgu.CV.Structure;
3using Emgu.CV.CvEnum;
界⾯:在Form1中添加2⾏2列的TableLayout容器,然后添加四个Emgu.CV.UI.ImageBox控件(),添加后界⾯如下:
如果你⾃⼰在实验时⽆法得到图⽚显⽰的效果,那么可以试试修改ImageBox的SizeMode属性。
新建DataAccess类:
1using Emgu.CV;
2using Emgu.CV.Structure;
3using Emgu.CV.CvEnum;
4
5namespace AccessingImageData
6 {
7public class DataAccess
8    {
9    }
10 }
修改像素值
可以通过⾏、列索引直接操作像素值,操作⽅式如下:
_image[row, cols] = new Bgr(Color.Green);
在DataAccess类中添加ExchangePixelValue⽅法,这个⽅法将交换两个区域的像素值。
1     ///<summary>
2///交换图像中两个区域的像素值
3///</summary>
4///<param name="image"></param>
5public static void ExchangePixelValue(Image<Bgr, Byte> image)
6        {
7for(int i = 0; i < 100; i ++)
8for(int j = 0; j < 200; j ++)
9                {
10                    Bgr tmp = image[i, j];
11                    image[i, j] = image[i + 100, j + 200];
12                    image[i + 100, j + 200] = tmp;
13                }
14        }
在Form1.cs中调⽤此⽅法的效果如下,⼩狗的脸去到了左上⾓,左上⾓的天空去到了⼩狗的脸位置。
图像ROI
ROI即为region of interest(感兴趣区域)。
“在很多情况下,使⽤它会提⾼计算机视觉代码的执⾏速度,这是因为它允许对图像的某⼀⼩部分进⾏操作,⽽不是对整个图像进⾏运算。在OpenCV中,普遍⽀持ROI,函数的
操作被限于感兴趣区域。”——《学习OpenCV(中⽂版)》。也就是如果你想只对图⽚的某个区域操作,你可以设置ROI后直接对图⽚进⾏操作,这时候被处理的部分只有ROI
区域。
OpenCV提供了cvSetImageROI()函数设置ROI区域,和cvResetImageROI()函数取消ROI,在Emgu中你可以在CvInvoke类中到这两个⽅法,同时你也可以设置Image
类的ROI属性来设置ROI,通过访问IsROISet来获取当前对象是否已经设置了ROI,如果要取消ROI,你需要把对象的ROI属性设置为Rectangle.Empty。Rectangle类来⾃于
System.Drawing,也就是在Emgu中ROI为Rectangle对象指定的矩形区域。
下⾯代码显⽰了设置、取消ROI操作,在DataAccess类中添加SetRoiRed⽅法:
1///<summary>
2///设置指定ROI区域为红⾊
3///</summary>
4///<param name="image"></param>
5///<param name="roi"></param>
6public static void SetRoiRed(Image<Bgr, Byte> image, Rectangle roi)
7        {
8            image.ROI = roi;
9            image.SetValue(new Bgr(Color.Red));
10//要记得取消ROI的设置,否则后续的操作都会在ROI中进⾏,包括显⽰图像
11            image.ROI = Rectangle.Empty;
12        }
在Form1中调⽤这个⽅法的运⾏效果为:
图像加法
使⽤Image.Add()⽅法,你可以让两个图像相加,或让当前图像加上⼀个⾊彩值。另外你也可以使⽤CvInvoke.Add()⽅法执⾏相同的操作,Image.Add()⽅法内部就是调⽤CvInvoke.Add()⽅法实现的。
Image.Add()有3个实现,每个实现的返回都是⼀个相同⾊彩空间、值类型的Image对象:
1   ///<summary>当前图⽚与另外⼀张图⽚相加,另外⼀张图⽚必须与当前图⽚是相同的类型和尺⼨(或相同ROI尺⼨)</summary>
2///<param name="img2">与当前图⽚相加的图⽚</param>
3///<returns>相加的结果</returns>
4public Image<TColor, TDepth> Add(Image<TColor, TDepth> img2)
1   ///<summary>当前图⽚与另外⼀张图⽚相加(ret(I)=src1(I)+src2(I) if mask(I)!=0),另外⼀张图⽚必须与当前图⽚是相同的类型和尺⼨(或形同ROI尺⼨)</summary> 2///<param name="img2">另⼀张图⽚</param>
3///<param name="mask">掩膜图⽚</param>
4///<returns>使⽤掩膜图⽚相加的结果</returns>
5public Image<TColor, TDepth> Add(Image<TColor, TDepth> img2, Image<Gray, Byte> mask)
1///<summary>当前图⽚加上⼀个⾊彩值</summary>
2///<param name="val"> ⾊彩值</param>
3///<returns>相加的结果<paramref name="val"/> from the current image</returns>
4public Image<TColor, TDepth> Add(TColor val)
接下来我们演⽰如何使⽤这些⽅法:在DataAccess类中添加JustAdd和AddUsingMask⽅法,JustAdd⽅法只是简单的调⽤Add⽅法。
⽽AddUsingMask⽅法中,我们⾸先需要创建⼀张掩膜图⽚,掩膜图⽚左半边为⽩⾊(255),右半边为⿊⾊(0),在执⾏加操作时,
⽩⾊部分会执⾏加操作,⽽⿊⾊部分不执⾏任何操作,所以resImage的右半边是⿊⾊的,这时把原图的右半边拷贝到resImage的右半
边上,代码如下:
1///<summary>
2///两张图⽚相加
3///</summary>
4///<param name="image1">相加的源图⽚1</param>
5///<param name="image2">相加的源图⽚2</param>
6///<returns></returns>
7public static Image<Bgr, Byte> JustAdd(Image<Bgr, Byte> image1, Image<Bgr, Byte> image2)
8        {
9return image1.Add(image2);
10        }
11
12///<summary>
13///使⽤掩码图⽚进⾏相加操作
14///</summary>
15///<param name="image1"></param>
16///<param name="image2"></param>
17///<returns></returns>
18public static Image<Bgr, Byte> AddUsingMask(Image<Bgr, Byte> image1, Image<Bgr, Byte> image2)
19        {
20var rect = new Rectangle(new Point(0, 0), new Size(image1.Width / 2, image1.Height));
21using (var mask = new Image<Gray, Byte>(image1.Size))
22            {
23                mask.SetZero();//设置所有值为0
24                mask.ROI = rect;
25                mask.SetValue(255);//设置ROI的值为255
26                mask.ROI = Rectangle.Empty;//去掉ROI
27//res(I)=img1(I)+img2(I) if mask(I)!=0
28var resImage = image1.Add(image2, mask);
29                mask._Not();//反转mask的值(255->0, 0->255)
30                image1.Copy(resImage, mask);//在mask(I) != 0的条件下,把image1的值拷贝到resImage中
31return resImage;
32            }
33        }
在Form1中调⽤以上⽅法:
1private void Form1_Load(object sender, EventArgs e)
2        {
3            _image = new Image<Bgr, byte>(ugou);
4            imageBox1.Image = _image;
5            imageBox2.Image = DataAccess.JustAdd(_image, _image);//图⽚⾃加
6            imageBox4.Image = DataAccess.AddUsingMask(_image, _image);
7
8//创建掩膜图⽚
9var mask = new Image<Gray, Byte>(_image.Size);
10            mask.SetZero();//设置所有值为0
11            mask.ROI = new Rectangle(new Point(0, 0), new Size(_image.Width / 2, _image.Height));
12            mask.SetValue(255);//设置ROI的值为255
rectangle函数opencv13            mask.ROI = Rectangle.Empty;//去掉ROI
14
15            imageBox3.Image = mask;
16        }
运⾏效果:
图像减法
使⽤Image.Sub()⽅法,你可以让当前图像减去另外⼀个图像,或让当前图像减去⼀个⾊彩值。另外你也可以使⽤CvInvoke.Subtract()⽅法执⾏相同的操作,
Image.Sub()⽅法内部就是调⽤CvInvoke.Subtract()⽅法实现的。
与加法相似,Image.Sub()同样有3个实现,每个实现的返回都是⼀个相同⾊彩空间、值类型的Image对象:
1///<summary>当前图⽚减去⼀张图⽚,被减图⽚必须与当前图⽚是相同的类型和尺⼨(或相同的ROI尺⼨)</summary>
2///<param name="img2">被减图⽚</param>
3///<returns>相减的结果</returns>
4public Image<TColor, TDepth> Sub(Image<TColor, TDepth> img2)
1  ///<summary>当前图⽚减去另外⼀张图⽚(ret(I)=src1(I)-src2(I) if mask(I)!=0),被减图⽚必须与当前图⽚是相同的类型和尺⼨(或相同的ROI尺⼨)</summary> 2///<param name="img2">被减图⽚</param>
3///<param name="mask">掩膜图⽚</param>
4///<returns>使⽤掩膜图⽚相减的结果</returns>
5public Image<TColor, TDepth> Sub(Image<TColor, TDepth> img2, Image<Gray, Byte> mask)
1///<summary>当前图⽚减去⼀个⾊彩值</summary>
2///<param name="val">被减去的⾊彩值</param>
3///<returns>减去⾊彩值的结果</returns>
4public Image<TColor, TDepth> Sub(TColor val)
接下来我们演⽰如何使⽤这些⽅法:在DataAccess类中添加JustSub和SubUsingMask⽅法,代码如下:
1///<summary>
2///图像减法
3///</summary>
4///<param name="image1"></param>
5///<param name="image2"></param>
6///<returns></returns>
7public static Image<Bgr, Byte> JustSub(Image<Bgr, Byte> image1, Image<Bgr, Byte> image2)
8        {
9return image1.Sub(image2);
10        }
11
12///<summary>
13///在掩码图⽚的条件下,⽤image1减去image2的值
14///</summary>
15///<param name="image1"></param>
16///<param name="image2"></param>
17///<returns></returns>
18public static Image<Bgr, Byte> SubUsingMask(Image<Bgr, Byte> image1, Image<Bgr, Byte> image2)
19        {
20var rect = new Rectangle(new Point(0, 0), new Size(image1.Width / 2, image1.Height));
21using (var mask = new Image<Gray, Byte>(image1.Size))
22            {
23                mask.SetZero();//设置所有值为0
24                mask.ROI = rect;
25                mask.SetValue(255);//设置ROI的值为255
26                mask.ROI = Rectangle.Empty;//去掉ROI
27//res(I)=img1(I)-img2(I) if mask(I)!=0
28var resImage = image1.Sub(image2, mask);
29                mask._Not();//反转mask的值(255->0, 0->255)
30                image1.Copy(resImage, mask);//在mask(I)!= 0的条件下,把image1的值拷贝到resImage中
31return resImage;
32            }
33        }
在Form1中调⽤以上⽅法,在加法演⽰中我们使图⽚⾃加,得到了⼀张更亮的照⽚,但是在减法中如果我们使图⽚⾃减就会得到⼀张⿊⾊的图⽚,
但是为了使读者能清晰的看到减法操作,我们使原图减去⼀张红⾊图,所以在以下程序中我们需要创建⼀张红⾊图⽚:
1private void Form1_Load(object sender, EventArgs e)
2        {
3            _image = new Image<Bgr, byte>(ugou);
4            imageBox1.Image = _image;
5using (var colorImage = new Image<Bgr, Byte>(_image.Size))
6            {//⾸先创建⼀张红⾊图⽚
7                colorImage.SetValue(new Bgr(Color.Red));
8                imageBox2.Image = DataAccess.JustSub(_image, colorImage);
9                imageBox4.Image = DataAccess.SubUsingMask(_image, colorImage);
10            }
11
12//创建掩膜图⽚
13var mask = new Image<Gray, Byte>(_image.Size);
14            mask.SetZero();//设置所有值为0
15            mask.ROI = new Rectangle(new Point(0, 0), new Size(_image.Width / 2, _image.Height));
16            mask.SetValue(255);//设置ROI的值为255
17            mask.ROI = Rectangle.Empty;//去掉ROI
18
19            imageBox3.Image = mask;
20        }
运⾏效果:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。