关于QImage提取单色通道方法(vector)
转载请标明处:
作者:微微苏荷
近日,用QT和mxnet结合做一个图像识别的demo。遇到需要把图片从QImage转为vector单色分离的格式的要求,用来识别时输入。
经实践,找到3种方法,分享给大家:
需要注意的是,QImage的存储顺序是 BGRA(opencv也是这样反着的),不是正常口述RGBA.
另:mx_float == float
一.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | int image_size = width * height * channels; //图像的宽/高/通道数(除去了A通道) std::vector<mx_float> image_data = std::vector<mx_float>(image_size); mx_float* ptr_image_r = image_data.data(); const uchar* pData= image.constBits(); // 获取图像原始数据 mx_float* ptr_image_g = image_data.data() + image_size / 3; mx_float* ptr_image_b = image_data.data() + image_size / 3 * 2; for ( int i = 0; i < height; i++){ int lineNum_32 = i * width * 4; for ( int k = 0; k < width; k++){ if (1 < IMAGE_CHANNELS){ // 乘以4的原因是QImage是四个通道存储的,BGRA,所以每个像素都占有4个字节。 *ptr_image_r++ = static_cast <mx_float> (pData[lineNum_32 + k * 4 + 2]) ; *ptr_image_g++ = static_cast <mx_float> (pData[lineNum_32 + k * 4 + 1]); } *ptr_image_b++ = static_cast <mx_float> (pData[lineNum_32 + k * 4 ]) ; } } |
二.利用image.scanLine(),获取每行扫描线的首地址
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | int image_size = width * height * channels; //图像的宽/高/通道数(除去了A通道) std::vector<mx_float> image_data = std::vector<mx_float>(image_size); mx_float* ptr_image_r = image_data.data(); const uchar* pData= image.constBits(); // 获取图像原始数据 mx_float* ptr_image_g = image_data.data() + image_size / 3; mx_float* ptr_image_b = image_data.data() + image_size / 3 * 2; for ( int i = 0; i < height; i++){ uchar *imageScanLine = image.scanLine(i); for ( int k = 0; k < width; k++){ if (1 < IMAGE_CHANNELS){ // 乘以4的原因是QImage是四个通道存储的,BGRA,所以每个像素都占有4个字节。 *ptr_image_r++ = static_cast <mx_float>(\ imageScanLine[k * 4 + 2]) ; *ptr_image_g++ = static_cast <mx_float>(\ imageScanLine[k * 4 + 1]) ; } *ptr_image_b++ = static_cast <mx_float>(\ imageScanLine[k * 4]) ; } } |
三.最可靠最简洁的方法.但是可能性能比上两个稍微差些(没有评估),因为他每个像素都要从QImage获取一次,不确定会不会比一次获取完和一次获取一行有性能之差,但个人感觉不会,因为QImage也是在内存中,不存在文件IO。但是他很简单,不需要考虑图片的位深和存储顺序/大端小端等问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | int image_size = width * height * channels; //图像的宽/高/通道数(除去了A通道) std::vector<mx_float> image_data = std::vector<mx_float>(image_size); mx_float* ptr_image_r = image_data.data(); const uchar* pData= image.constBits(); // 获取图像原始数据 mx_float* ptr_image_g = image_data.data() + image_size / 3; mx_float* ptr_image_b = image_data.data() + image_size / 3 * 2; for ( int i = 0; i < height; i++){ uchar *imageScanLine = image.scanLine(i); for ( int k = 0; k < width; k++){ // 没有做兼容单通道 QRgb bits = image.pixel(i, k); *ptr_image_r++ = static_cast <mx_float>(qRed(bits)) ; *ptr_image_g++ = static_cast <mx_float>(qGreen(bits)); *ptr_image_b++ = static_cast <mx_float>(qBlue(bits)) ; } } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 现代计算机视觉入门之:什么是图片特征编码
· .NET 9 new features-C#13新的锁类型和语义
· Linux系统下SQL Server数据库镜像配置全流程详解
· 现代计算机视觉入门之:什么是视频
· Sdcb Chats 技术博客:数据库 ID 选型的曲折之路 - 从 Guid 到自增 ID,再到
· .NET Core GC压缩(compact_phase)底层原理浅谈
· Winform-耗时操作导致界面渲染滞后
· Phi小模型开发教程:C#使用本地模型Phi视觉模型分析图像,实现图片分类、搜索等功能
· 语音处理 开源项目 EchoSharp