解决cv::Mat宽度非4倍数时在PictureBox显示的异常问题
解决24位RGB格式cv::Mat显示到PictureBox时的步长对齐问题
问题根源
Windows的Bitmap要求每行像素数据的字节数(即stride/步长)必须是4的倍数,而OpenCV的cv::Mat在24位RGB格式下,若列数cols不是4的倍数,其默认步长为cols*3,不满足4的倍数要求。直接修改步长会导致内存缓冲区长度不匹配,触发System.AccessViolationException。
解决方案:使用Bitmap.LockBits逐行复制数据
通过LockBits获取Bitmap的缓冲区,逐行将cv::Mat的有效像素数据复制到Bitmap的对齐缓冲区中,既满足步长要求,又避免内存访问越界。
完整代码示例(C++/CLI)
// 确保matSrc是24位RGB格式(OpenCV默认是BGR,需先转换) cv::cvtColor(matSrc, matSrc, cv::COLOR_BGR2RGB); // 创建对应尺寸的24位RGB Bitmap System::Drawing::Bitmap^ bmp = gcnew System::Drawing::Bitmap( matSrc.cols, matSrc.rows, System::Drawing::Imaging::PixelFormat::Format24bppRgb ); // 锁定Bitmap缓冲区以写入数据 System::Drawing::Imaging::BitmapData^ bmpData = bmp->LockBits( System::Drawing::Rectangle(0, 0, bmp->Width, bmp->Height), System::Drawing::Imaging::ImageLockMode::WriteOnly, bmp->PixelFormat ); unsigned char* srcPtr = matSrc.data; unsigned char* dstPtr = static_cast<unsigned char*>(bmpData->Scan0); int srcStride = matSrc.step; // 原Mat的步长 int dstStride = bmpData->Stride;// Bitmap对齐后的步长 // 逐行复制像素数据 for (int i = 0; i < matSrc.rows; ++i) { // 复制一行的有效RGB数据(共cols*3字节) memcpy(dstPtr, srcPtr, matSrc.cols * 3); // 移动到下一行的起始地址 srcPtr += srcStride; dstPtr += dstStride; } // 解锁缓冲区 bmp->UnlockBits(bmpData); // 显示到PictureBox pictureBox1->Image = bmp;
关键说明
- 颜色格式转换:OpenCV读取的图像默认是BGR格式,必须先通过
cv::COLOR_BGR2RGB转换为RGB,否则显示颜色会反转。 - 逐行复制:
Bitmap的对齐步长可能大于cols*3,复制时仅需覆盖每行的有效像素区域,剩余填充字节无需处理,不影响显示效果。 - 内存安全:通过
LockBits操作缓冲区,避免直接修改步长导致的内存越界,完全符合Windows位图的内存规范。
内容的提问来源于stack exchange,提问作者user727062
相关产品推荐
相关产品推荐

