C#中如何实现Bitmap图像处理加速
发表于:2024-10-03 作者:千家信息网编辑
千家信息网最后更新 2024年10月03日,这篇文章主要讲解了"C#中如何实现Bitmap图像处理加速",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"C#中如何实现Bitmap图像处理加速"吧!B
千家信息网最后更新 2024年10月03日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安全错误
数据库的锁怎样保障安全
华为网络技术大赛
储能软件开发需要什么知识
网络安全班会心得作文
提升软件开发质量的作用
挂课软件开发
it数据库的特点
国际上有名的网络安全认证
激流勇进数据库有用吗
公安网络安全周反恐宣传总结
五年级关于网络安全画
软件开发阶段包括维护吗
怎么配置dns主服务器
泰州智能化服务器
大专文科学软件开发
gis软件开发工作
网络安全病毒威胁
连接到本地的数据库
计算机网络技术有哪些应用
使命召唤18连接不了服务器
农安正规网络技术服务诚信经营
可视化数据库技术方案
山西电商软件开发公司排名
服务器搭建代理软件
数据库和软件的接口
网络安全事故的时事近两年
数据库如何约束字段的范围
服务器安全4.2
软件开发员工要什么学历
国际陨石数据库的网址中文版
如何打开桌面服务器管理