C#中如何实现Bitmap图像处理加速
发表于:2025-01-16 作者:千家信息网编辑
千家信息网最后更新 2025年01月16日,这篇文章主要讲解了"C#中如何实现Bitmap图像处理加速",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"C#中如何实现Bitmap图像处理加速"吧!B
千家信息网最后更新 2025年01月16日C#中如何实现Bitmap图像处理加速
这篇文章主要讲解了"C#中如何实现Bitmap图像处理加速",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"C#中如何实现Bitmap图像处理加速"吧!
BitmapData类
BitmapData类专门用于位图处理,与Bitmap的不同点在于,它使用指针直接修改内存,而Bitmap是使用SetPixel()方法间接修改颜色,因此其效率远远超过SetPixel()
传统代码
以灰度处理为例,为了便于演示,此处的灰度算法采用 Gray=(R+G+B) / 3
private void Gray_Tradition(){ for(int i = 0; i < bitmap.Width; i++) { for(int j = 0; j < bitmap.Height; j++) { Color color = bitmap.GetPixel(i, j); int RGB = (color.R + color.G + color.B) / 3; bitmap.SetPixel(i, j, Color.FromArgb(255, RGB, RGB, RGB)); } }}
使用BitmapData的代码
private void Gray_BitmapData(){ int width = bitmap.Width, height = bitmap.Height;//图片的宽度和高度 //在内存中以读写模式锁定Bitmap BitmapData bitmapData = bitmap.LockBits( new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); //图片像素点数组的长度,由于一个像素点占了3个字节,所以要乘上3 int size = width * height * 3; //缓冲区数组 byte[] srcArray = new byte[size]; //获取第一个像素的地址 IntPtr ptr = bitmapData.Scan0; //把像素值复制到缓冲区 Marshal.Copy(ptr, srcArray, 0, size); int p; for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { //定位像素点位置 p = j * width * 3 + i * 3; //计算灰度值 byte color = (byte)((srcArray[p] + srcArray[p + 1] + srcArray[p + 2]) / 3); srcArray[p] = srcArray[p + 1] = srcArray[p + 2] = color; } } //从缓冲区复制回BitmapData Marshal.Copy(srcArray, 0, ptr, size); //从内存中解锁 bitmap.UnlockBits(bitmapData);}
效率对比
代码
private void onTest(){ double t1, t2; Stopwatch watch = new Stopwatch(); watch.Start(); Gray_BitmapData(); watch.Stop(); t1 = watch.Elapsed.TotalMilliseconds; watch.Reset(); watch.Start(); Gray_Tradition(); watch.Stop(); t2 = watch.Elapsed.TotalMilliseconds; MessageBox.Show("BitmapData=" + (long)t1 + "\nTradition=" + (long)t2);}
图片信息
耗时
可以看到传统方法的耗时是使用BitmapData方法的106倍,需要整整14秒,而BitmapData仅用了0.1秒
GPU加速
使用CUDA生成dll后,可以在GPU上高效处理图像,但是这种方式需要使用dll,而且异常繁琐,因此只适合对效率有极高要求时使用
生成Dll
#include "cuda_runtime.h"#include "device_launch_parameters.h" #include#include __global__ void DoInKernel(byte* o, int num){ int i = blockIdx.x * blockDim.x + threadIdx.x; if (i >= num) return; byte* ori = o + i * 3; ori[0] = ori[1] = ori[2] = (ori[0] + ori[1] + ori[2]) / 3;} extern "C" _declspec(dllexport) void Gray(byte * oriArray, int num) { int size = num * 3 * sizeof(byte); byte* dev_ori; //在GPU上分配内存 cudaMalloc((void**)&dev_ori, size); //把数组复制到显存 cudaMemcpy(dev_ori, oriArray, size, cudaMemcpyHostToDevice); //计算 DoInKernel << > > (dev_ori, num); //从显存复制到内存 cudaMemcpy(oriArray, dev_ori, size, cudaMemcpyDeviceToHost); //释放 cudaFree(dev_ori);}
实际上GPU的thread和block数量应该根据实际数组大小来动态调整,但是这里为了演示方便,直接定义1024个线程
调用Dll
[DllImport("CUDA.dll", EntryPoint = "Gray", CallingConvention = CallingConvention.Cdecl)]public static extern void Gray(IntPtr ori, int num);
此时不需要定义缓冲区数组了,可以直接把数据复制到显存中使用
private void Gray_GPU(){ int width = bitmap.Width, height = bitmap.Height;//图片的宽度和高度 //在内存中以读写模式锁定Bitmap BitmapData bitmapData = bitmap.LockBits( new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); //图片像素点数组的长度,由于一个像素点占了3个字节,所以要乘上3 int size = width * height * 3; //获取第一个像素的地址 IntPtr ptr = bitmapData.Scan0; Gray(ptr, width * height); //从内存中解锁 bitmap.UnlockBits(bitmapData); pictureBox1.Refresh();}
耗时
由于加载dll需要时间,因此第二次执行的耗时才是真正的GPU执行时间
仅用了34毫秒
感谢各位的阅读,以上就是"C#中如何实现Bitmap图像处理加速"的内容了,经过本文的学习后,相信大家对C#中如何实现Bitmap图像处理加速这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!
像素
处理
内存
数组
图像
图片
图像处理
C#
缓冲区
缓冲
代码
效率
方法
显存
灰度
学习
传统
内容
地址
字节
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
如何将数据库的三张表合到一张表
郑远雄软件开发工作室
聚财汇互联网科技有限公司
网络安全法 外媒
php pdo数据库原理
苏州互联网印象科技有限公司
腐蚀服务器怎么找
东南大学研究生网络安全
太仓正规网络技术哪个好
长沙通誉网络技术有限公司
手机服务器转换
学校网络安全讲座活动简报
汽车资源数据库
腾讯软件开发在线笔试题目
流星群侠传服务器维护中
溢思优控制网络安全
桓台办公oa软件开发公司
wow服务器满
5亿网络安全概念
cnki学问论文数据库
服务器合服
承德网络服务器机柜规格
长沙通誉网络技术有限公司
东莞市聚焦网络技术有限公司
焦作网络安全宣传周视频
麒麟系统应用软件开发用什么语言
软件开发中计划的目的
热血传奇手游推荐哪个服务器
服务器虚拟化安装软路由
济南达森互联网科技怎么样