Emgu學習之(三)——操作圖像數據


Visual Studio Community 2015 工程和代碼:http://pan.baidu.com/s/1jHmlQeE

內容

在這篇文章中將提到以下內容:

  • 修改像素值
  • 圖像ROI
  • 圖像加法
  • 圖像減法
  • 按位運算
  • 圖像混合

准備工作

1 using Emgu.CV;
2 using Emgu.CV.Structure;
3 using Emgu.CV.CvEnum;

   

     如果你自己在實驗時無法得到圖片顯示的效果,那么可以試試修改ImageBox的SizeMode屬性。

  • 新建DataAccess類:
 1 using Emgu.CV;
 2 using Emgu.CV.Structure;
 3 using Emgu.CV.CvEnum;
 4 
 5 namespace AccessingImageData
 6 {
 7     public class DataAccess
 8     {
 9     }
10 }

修改像素值

可以通過行、列索引直接操作像素值,操作方式如下:

_image[row, cols] = new Bgr(Color.Green);

在DataAccess類中添加ExchangePixelValue方法,這個方法將交換兩個區域的像素值。

 1      /// <summary>
 2         /// 交換圖像中兩個區域的像素值
 3         /// </summary>
 4         /// <param name="image"></param>
 5         public static void ExchangePixelValue(Image<Bgr, Byte> image)
 6         {
 7             for(int i = 0; i < 100; i ++)
 8                 for(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>
 6         public 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>
4       public 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>
5       public 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>
4       public 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>
 7         public static Image<Bgr, Byte> JustAdd(Image<Bgr, Byte> image1, Image<Bgr, Byte> image2)
 8         {
 9             return image1.Add(image2);
10         }
11 
12         /// <summary>
13         /// 使用掩碼圖片進行相加操作
14         /// </summary>
15         /// <param name="image1"></param>
16         /// <param name="image2"></param>
17         /// <returns></returns>
18         public static Image<Bgr, Byte> AddUsingMask(Image<Bgr, Byte> image1, Image<Bgr, Byte> image2)
19         {
20             var rect = new Rectangle(new Point(0, 0), new Size(image1.Width / 2, image1.Height));
21             using (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
28                 var resImage = image1.Add(image2, mask);
29                 mask._Not();//反轉mask的值(255->0, 0->255)
30                 image1.Copy(resImage, mask);//在mask(I) != 0的條件下,把image1的值拷貝到resImage中
31                 return resImage;
32             }
33         }

在Form1中調用以上方法:

 1         private void Form1_Load(object sender, EventArgs e)
 2         {
 3             _image = new Image<Bgr, byte>(Properties.Resources.gougou);
 4             imageBox1.Image = _image;
 5             imageBox2.Image = DataAccess.JustAdd(_image, _image);//圖片自加  6             imageBox4.Image = DataAccess.AddUsingMask(_image, _image);
 7 
 8             //創建掩膜圖片
 9             var 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
13             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>
4        public 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>
5        public Image<TColor, TDepth> Sub(Image<TColor, TDepth> img2, Image<Gray, Byte> mask)
1        ///<summary> 當前圖片減去一個色彩值</summary>
2        ///<param name="val">被減去的色彩值</param>
3        ///<returns> 減去色彩值的結果</returns>
4        public 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>
 7         public static Image<Bgr, Byte> JustSub(Image<Bgr, Byte> image1, Image<Bgr, Byte> image2)
 8         {
 9             return 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>
18         public static Image<Bgr, Byte> SubUsingMask(Image<Bgr, Byte> image1, Image<Bgr, Byte> image2)
19         {
20             var rect = new Rectangle(new Point(0, 0), new Size(image1.Width / 2, image1.Height));
21             using (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
28                 var resImage = image1.Sub(image2, mask);
29                 mask._Not();//反轉mask的值(255->0, 0->255)
30                 image1.Copy(resImage, mask);//在mask(I)!= 0的條件下,把image1的值拷貝到resImage中
31                 return resImage;
32             }
33         }

在Form1中調用以上方法,在加法演示中我們使圖片自加,得到了一張更亮的照片,但是在減法中如果我們使圖片自減就會得到一張黑色的圖片,

但是為了使讀者能清晰的看到減法操作,我們使原圖減去一張紅色圖,所以在以下程序中我們需要創建一張紅色圖片:

 1         private void Form1_Load(object sender, EventArgs e)
 2         {
 3             _image = new Image<Bgr, byte>(Properties.Resources.gougou);
 4             imageBox1.Image = _image;
 5             using (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             //創建掩膜圖片
13             var 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         }

運行效果:

按位運算

按位運算有與(And)、或(Or)、非(Not)和異或(Xor)運算。要執行這些運算,你可以使用CvInvoke類下的靜態方法:BitwiseAnd、BitwiseNot、BitwiseOr、

BitwiseXor。但是與加減法類似,Image類同時也提供Add、Not、Or、Xor方法,同時還提供了_Add、_Not、_Or、_Xor,這些帶下划線的方法會在當前對象上進行

運算,而不帶下划線的方法則是返回新的對象。同時_Add、_Not、_Or、_Xor不提供掩膜操作。

接下來我們演示如何把OpenCV的logo添加到狗狗圖片中,這里我們需要一張和logo圖同樣的mask圖片。首先我們在DataAccess類中添加AddLogo方法:

 1         /// <summary>
 2         /// 在掩膜圖片的條件下,在圖片中添加logo,掩膜圖片為logo圖片的二值圖
 3         /// </summary>
 4         /// <param name="image"></param>
 5         /// <param name="logo"></param>
 6         /// <param name="mask"></param>
 7         /// <returns></returns>
 8         public static Image<Bgr, Byte> AddLogo(Image<Bgr, Byte> image, Image<Bgr, Byte> logo, Image<Gray, Byte> mask)
 9         {
10             var resImage = image.Copy();
11 
12             //設置操作區域,所有的操作都在這個區域中進行
13             image.ROI = new Rectangle(new Point(0, 0), logo.Size);
14             resImage.ROI = image.ROI;
15 
16             using (var colorMask = mask.Convert<Bgr, Byte>())
17             {
18                 //把Logo區域變成白色(0xFF)
19                 CvInvoke.Add(image, colorMask, resImage, mask);
20             }
21           
22             CvInvoke.BitwiseAnd(resImage, logo, resImage, mask);
23 
24             //失能操作區域
25             resImage.ROI = Rectangle.Empty;
26             return resImage;
27         }

然后,在Form1中調用AddLogo方法:

圖像混合

圖像混合和圖像加法類似,圖像加法是簡單的把兩張圖片相加,而圖像混合是將兩張圖片按照不同的權重相加:

 res[m, n] = α·src1[m,n] + β·src1[m,n] + γ(其中α = 1 - β)

實現這個功能的函數為cvAddWeighted方法,以下為調用實例:

1 var resImage =  image1.AddWeighted(image2, 0.5, 0.5, 0);

 

這里α = 0.5,β = 0.5, γ = 0。

運行效果為:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM