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#叠加合并半透明图像的两种实现相关推荐

  1. matlab批量处理程序设计,Matlab实现批量处理图像的两种方法

    Matlab实现批量处理图像的两种方法 基本上有两个方法:一个是将你的图像统一进行一次重命名如:1.jpg,2.jpg等,然后利用for循环依次进行处理即可,如下面的语句:假设你的图像共有20副: s ...

  2. Android实现圆形图像的两种方法(Glide和Picasso)

    Android实现圆形图像的两种方法 先上效果图 Glide Picasso CircleTransform.java(圆形图片工具类) 先上效果图 Glide 在app的build.gradle中引 ...

  3. 合并BIN文件的两种方法

    合并BIN文件的两种方法 在单片机的开发过程中,经常需要将两个单独的BIN文件合并成一个文件,方便烧写和生产.下面结合STM32的IAP Bootloader Code和Application Cod ...

  4. 多个PDF文件如何合并成一个?两种方法轻松get

    在日常学习生活中,如果你需要将多个文档整合为一个完整的文件,比如说多篇文章.多张图片.多个表格等等,这时候就需要将这些文档合并成一个PDF文件.如何将多个PDF文件如何合并成一个?两种方法轻松帮你搞定 ...

  5. 使用OpenCV对图像进行两种平移操作(图像的尺寸变化与图像的尺寸不变)

    使用OpenCV对图像进行两种平移操作(图像的尺寸变化与图像的尺寸不变) 图像的平移操作是将图像的所有像素点进行水平或垂直方向上的移动. 平移操作分为两种类型:图像的尺寸变化与图像的尺寸不变.前者保证 ...

  6. 数字图像隐藏图像的两种算法及实现代码

    数字图像 二值图像 也叫单色图像,是将每个像素点存放在一个bit空间(值为0或者1)的图像,也就是说每个像素"非黑即白",主要用于图像形态学的研究. 8位灰度图像 每个像素存放在一 ...

  7. 【Python】制作圆角图像的两种方案对比

    需求:现有200*200像素JPG图片,需制作成129*129像素的PNG圆角头像. 两种方案. 方案1:直接将JPG图片,利用灰度图mask,叠加得到圆角PNG. 优势:方便,不需动手P个透明模板底 ...

  8. 【Win 10 应用开发】将墨迹保存到图像的两种方法

    IT界最近这几年,各种乱七八糟的东西不断出现,其中能用在实际工作与生活中的,大概也就那么几个.Web 前端也冒出各种框架,这就为那些喜欢乱用框架的公司提供了很好的机会,于是造成很多项目体积越来越庞大, ...

  9. java 把图片插入窗体,JAVA JFrame窗体添加背景图像的两种方法

    首先还是要了解框架JFrame中的层次结构.JFrame中的层次分布及相对关系是:最底层是:JRootPane:第二层是:JlayerPane:最上层就是ContentPane,也正是我们常说的内容面 ...

最新文章

  1. linux基础学习(二)
  2. 为什么项目开放源代码之后就变成死项目 很少或几乎不再更新
  3. 在Delphi7中调试COM
  4. 【每日一题】7月6日精讲—平衡二叉树
  5. 两步验证杀手锏:Java 接入 Google 身份验证器实战
  6. 【渝粤题库】陕西师范大学200311常微分方程作业(高起本)
  7. 一、项目管理框架【PMP 】
  8. 交换机Trunk详解
  9. 全志V3s学习记录(11)音频、视频使用总结
  10. vue项目实现权限控制的几种思路
  11. 易基因 | 文献速递:重亚硫酸盐扩增子测序研究通过DNA甲基化监测急性髓系白血病MRD
  12. 微信转发软件后缀_微信发送不了100M的视频?其实只需要改个后缀,长知识了...
  13. Elasticsearch中的倒排索引和读写操作原理解析
  14. 苹果手机13和小米手环6NFC,录入“不支持类型”的门禁卡
  15. 联通数科一面+二面+面谈 经验分享 base济南
  16. 阿里云主机安全组端口开放完整教程
  17. Windows 下安装 Xdebug 受难记之(2)
  18. 10 降维算法(PCA降维/LDA分类/NMF非负矩阵)
  19. RxJava简单使用(Kotlin)
  20. gis如何加入emf图片_投票 | Ansys仿真的艺术图片大赛入围作品巡展

热门文章

  1. 坐标反算计算起始方位角_谁会坐标正算反算的公式,怎么计算两个坐标的方位角...
  2. c语言中ANSI标准的关键字,C语言中32个关键字详解
  3. MPU6050原始数据分析——学习笔记
  4. java微信多客服_微信多客服聊天功能怎么实现?
  5. 从表征到行动---意向性的自然主义进路(续四)
  6. 远程桌面 多人同时 使用谷歌浏览器
  7. javaweb基于JSP+Servlet开发水费管理系统+论文 大作业 毕业设计
  8. vmware中调整ubuntu的磁盘大小
  9. react-native-webrtc之采坑之旅
  10. anti-fraud-admin  反欺诈后台