C#叠加合并半透明图像的两种实现
生活随笔
收集整理的這篇文章主要介紹了
C#叠加合并半透明图像的两种实现
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
C#疊加合并半透明圖像
- 說明
- 方案一:系統自帶 GDI+ 實現
- 方案二:使用 EmguCV 實現
- 總結
說明
OpenCV作為一個圖像庫,竟然沒有提供一個直接的函數去做這件事情。
這里使用系統自帶的GDI和EmguCV(C#封裝的OpenCV)分別實現了疊加合并兩張半透明圖像的功能。
兩個半透明顏色色的疊加計算方法
透明顏色混合算法
方案一:系統自帶 GDI+ 實現
/// using System.Drawing;/// <summary> /// GDI+ 方式合并半透明圖像 /// </summary> /// <param name="background"></param> /// <param name="fontground"></param> /// <returns></returns> public Bitmap ImageOverlapping1(Bitmap background, Bitmap fontground) {if (background.Size != fontground.Size)throw new ArgumentException("background size != fontground size");using (Graphics g = Graphics.FromImage(background)){g.DrawImage(fontground, new Point(0, 0));}return background; }/// <summary> /// 按從下到上的順序合并多張輸入圖像 /// </summary> /// <param name="z2aImages">從下到上順序的圖像,第一張圖在最下面,最后一張圖在最上面</param> /// <returns></returns> public Bitmap ImageOverlapping1(params Bitmap[] z2aImages) {if (z2aImages.Length == 0)throw new ArgumentException();if (z2aImages.Length == 1)return z2aImages[0];for (int i = 0; i < z2aImages.Length - 1; i++){z2aImages[i + 1] = ImageOverlapping1(z2aImages[i], z2aImages[i + 1]);}return z2aImages[z2aImages.Length - 1]; }這個方式優點是代碼簡單,而且DrawImage的參數支持合并不同大小的圖片,支持指定左上角的位置。
方案二:使用 EmguCV 實現
/// <summary> /// EmguCV 兩張半透明圖片的疊加 /// </summary> /// <code> /// ushort a1 = A1; /// ushort a2 = A2 - (A1 * A2) / 256; /// ushort a = A1 + A2; /// uint8 R = (a1* R1 + a2* R2)/a; /// uint8 G = (a1* G1 + a2* G2)/a; /// uint8 B = (a1* B1 + a2* B2)/a; /// uint8 A = a; /// </code> /// <param name="background"></param> /// <param name="fontground"></param> /// <returns></returns> public Bitmap ImageOverlapping2(Bitmap background, Bitmap fontground) {if (background.Size != fontground.Size)throw new ArgumentException("background size != fontground size");// 因為中間計算涉及 uint8 數據的相乘與相加,// 因此統一使用 uint16 格式存放加載Image<Bgra, ushort> back = new Image<Bgra, ushort>(background);Image<Bgra, ushort> font = new Image<Bgra, ushort>(fontground);Size size = background.Size;UMat image1 = back.ToUMat(); // 背景UMat image2 = font.ToUMat(); // 前景// 拆分通道UMat[] image1Channels = image1.Split();UMat[] image2Channels = image2.Split();// 用于存放各通道計算結果UMat[] outputChannels = new UMat[]{new UMat(size,DepthType.Cv16U,1),new UMat(size,DepthType.Cv16U,1),new UMat(size,DepthType.Cv16U,1),new UMat(size,DepthType.Cv16U,1),};// 用于暫存中間結果數據UMat tmp = new UMat(size, DepthType.Cv16U, 1);// 255灰度值填充的灰度圖UMat white = new UMat(size, DepthType.Cv16U, 1);white.SetTo(new MCvScalar(255));// Alpha 通道計算CvInvoke.Multiply(image1Channels[3], image2Channels[3], tmp); // tmp = A1 * A2CvInvoke.Divide(tmp, white, tmp); // tmp = tmp / 255CvInvoke.Subtract(image2Channels[3], tmp, image2Channels[3]); // A2 = A2 - tmpCvInvoke.Add(image1Channels[3], image2Channels[3], outputChannels[3]); // A = A1 + A2// B G R 通道計算for (int i = 0; i < 3; i++){CvInvoke.Multiply(image1Channels[i], image1Channels[3], image1Channels[i]); // C1 = C1 * A1CvInvoke.Multiply(image2Channels[i], image2Channels[3], image2Channels[i]); // C2 = C2 * A2CvInvoke.Add(image1Channels[i], image2Channels[i], outputChannels[i]); // C = C1 + C2CvInvoke.Divide(outputChannels[i], outputChannels[3], outputChannels[i]); // C = C / A}// 通道合并輸出using (UMat output = new UMat(size, DepthType.Cv16U, 4)){CvInvoke.Merge(new VectorOfUMat(outputChannels), output);// 釋放資源tmp.Dispose();white.Dispose(); back.Dispose(); font.Dispose(); image1.Dispose();image2.Dispose();for (int i = 0; i < 4; i++){image1Channels[i].Dispose();image2Channels[i].Dispose();outputChannels[i].Dispose();}return output.ToImage<Bgra, byte>().ToBitmap();} }/// <summary> /// 按從下到上的順序合并輸入圖像 /// </summary> /// <param name="z2aImages">從下到上順序的圖像,第一張圖在最下面,最后一張圖在最上面</param> /// <returns></returns> public Bitmap ImageOverlapping2(params Bitmap[] z2aImages) {if (z2aImages.Length == 0)throw new ArgumentException();if (z2aImages.Length == 1)return z2aImages[0];for (int i = 0; i < z2aImages.Length - 1; i++){z2aImages[i + 1] = ImageOverlapping2(z2aImages[i], z2aImages[i + 1]);}return z2aImages[z2aImages.Length - 1]; }EmguCV寫起來有幾個資源釋放的坑,剛開始沒有釋放資源,反復調用會內存錯誤,
建議寫好之后循環執行1000遍,看內存占用。
總結
很遺憾的是.Net平臺下,方案2函數的運行耗時要大于方案1函數的運行耗時。
時間消耗主要在函數頭部和尾部Bitmap和UMat之間的互相轉換,實際上中間的計算時間EmguCV還是略有優勢的,畢竟顯卡加速。
總結
以上是生活随笔為你收集整理的C#叠加合并半透明图像的两种实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 即将出一期uniapp微信登陆-升级版,
- 下一篇: 职场管理(3)——提取公积金需要满足哪些