You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

QVector<quint16>转cv::Mat再转QImage奇数尺寸裁剪出现斜线问题

故障根本原因

这个问题是OpenCV的cv::Mat步长对齐规则与QImage对16位灰度格式的步长计算逻辑不匹配导致的,具体触发逻辑如下:

  1. cv::Mat默认按4字节对齐分配内存,每行的实际字节数(即step[0])会向上取整到4的倍数。你使用rowRange/colRange裁剪得到的是原始图像的子视图,不会重新分配内存,所以裁剪后的子矩阵的step仍和原始大矩阵的step一致,不会跟随裁剪后的宽度变化。
  2. 部分Qt版本在处理QImage::Format_Grayscale16格式时,会忽略构造函数传入的自定义步长参数,自行按「宽度×单像素字节数」(或仅按2字节对齐规则)计算行步长,不会做4字节对齐。
  3. 当你裁剪为399像素的奇数宽度时:
    • 16位灰度单像素占2字节,一行有效数据为399*2=798字节
    • cv::Mat的step按4字节对齐为800字节
    • Qt自行计算的步长为798字节,两者差2字节(恰好1个16位像素的大小)
    • 这就导致QImage读取第二行数据时,会从cv::Mat第一行有效数据的末尾开始读,刚好拿到你裁剪掉的第一行第400个像素,后续每行叠加这个偏移,最终形成斜线。
  4. 当你裁剪为400像素的偶数宽度时:
    • 一行有效数据为400*2=800字节,刚好是4的倍数
    • cv::Mat的step和Qt计算的步长完全一致,因此不会出现错位。

验证方法

打印裁剪后outImage.step[0]和outImage.cols*2的数值,两者在裁剪奇数宽度时会存在2字节的差值,即可验证上述判断。


修复方案

不要直接用子矩阵的内存构造QImage,裁剪后先把子矩阵拷贝到连续内存的新Mat中,再做格式转换:

/* 裁剪后新增clone操作,生成连续内存的新矩阵 */
cv::Mat outImage = image.rowRange(0, 399).colRange(0, 399).clone();

如果仍有兼容问题,可以手动按行拷贝数据到QImage,彻底规避步长不匹配的问题:

cv::Mat cropped = image.rowRange(0, 399).colRange(0, 399);
QImage image(cropped.cols, cropped.rows, QImage::Format_Grayscale16);
for(int row = 0; row < cropped.rows; row++){
    memcpy(image.scanLine(row), cropped.ptr(row), cropped.cols * 2);
}

内容的提问来源于stack exchange,提问作者keven parent

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 05:54:03