cv::Mat接受tiff格式图片并转换为Qimage格式

文章讲述了如何使用OpenCV的Mat类和Qt的QImage类进行数据转换,具体包括Mat的构造方法,涉及图像的高度、宽度、类型以及步长信息,以及如何将QImage转换为Mat进行处理,转换时注意QImage的格式如ARGB32。

记录一下,以备以后查阅

// Mat构造:行数,列数,存储结构,数据,step每行多少字节
cv::Mat image = cv::Mat(image.height(), image.width(), CV_8UC1, (void*)image.constBits(), image.bytesPerLine());
QImage allImage((uchar*)image.data,image.cols,image.rows,image.step,QImage::Format_ARGB32);

#include "stereomatch2_main.h" #include "ui_stereomatch2_main.h" #include "stereomatch2_utils.h" #include <QDir> #include <QDebug> #include <QFile> #include <QTextStream> #include <algorithm> #include <opencv2/imgcodecs.hpp> // 获取目录下的图像文件(Qt化,跨平台) int get_file_names(const QString& imgPath, QVector<QString>& fileNames) { fileNames.clear(); QDir dir(imgPath); if (!dir.exists()) { qWarning() << "[提示] 图像目录不存在:" << imgPath; return -1; } // 筛选jpg/png文件(不区分大小写) QStringList filters; filters << "*.jpg" << "*.JPG" << "*.png" << "*.PNG"; dir.setNameFilters(filters); QFileInfoList infoList = dir.entryInfoList(QDir::Files); for (const QFileInfo& info : infoList) { fileNames.append(info.fileName()); // 仅存文件名(后续拼接路径) } return 0; } // 匹配左右图像对 QVector<QPair<QString, QString>> matchImagePairs( const QVector<QString>& allFiles, const QString& imgPath, const QString& leftPrefix, const QString& rightPrefix) { QVector<QPair<QString, QString>> imagePairs; QVector<QString> leftFiles, rightFiles; QString lowerLeft = leftPrefix.toLower(); QString lowerRight = rightPrefix.toLower(); // 1. 筛选左图/右图 for (const QString& fileName : allFiles) { QString lowerName = fileName.toLower(); if (lowerName.contains(lowerLeft)) { leftFiles.append(imgPath + "/" + fileName); // 完整路径 } else if (lowerName.contains(lowerRight)) { rightFiles.append(imgPath + "/" + fileName); } } // 2. 按序号匹配(如Left_001 → Right_001) for (const QString& leftPath : leftFiles) { // 提取左图前缀后的后缀(如"Left_001.jpg" → "_001.jpg") int leftPrefixPos = leftPath.indexOf(leftPrefix, 0, Qt::CaseInsensitive); if (leftPrefixPos == -1) continue; QString leftSuffix = leftPath.mid(leftPrefixPos + leftPrefix.length()); // 遍历右图找匹配后缀 for (auto it = rightFiles.begin(); it != rightFiles.end(); ++it) { const QString& rightPath = *it; int rightPrefixPos = rightPath.indexOf(rightPrefix, 0, Qt::CaseInsensitive); if (rightPrefixPos == -1) continue; QString rightSuffix = rightPath.mid(rightPrefixPos + rightPrefix.length()); if (leftSuffix == rightSuffix) { imagePairs.append(qMakePair(leftPath, rightPath)); rightFiles.erase(it); // 避免重复匹配 break; } } } return imagePairs; } // 创建结果子文件夹(Qt跨平台) QString createResultDir( const QString& baseDir, const QString& leftFileName, const QString& rightFileName) { // 提取简化文件名(去掉路径和后缀) QFileInfo leftInfo(leftFileName); QString leftShort = leftInfo.baseName(); // 如"Left_001" QFileInfo rightInfo(rightFileName); QString rightShort = rightInfo.baseName(); // 结果文件夹路径 QString resultDir = baseDir + "/Result_" + leftShort + "_" + rightShort; QDir dir(resultDir); // 若不存在则创建 if (!dir.exists()) { if (!dir.mkpath(".")) { qWarning() << "[错误] 创建文件夹失败:" << resultDir; return ""; } } return resultDir; } // 保存点云数据 void saveXYZ(const QString& filename, const cv::Mat& mat) { const double max_z = 1.0e4; QFile file(filename); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { qWarning() << "[错误] 无法打开点云文件:" << filename; return; } QTextStream out(&file); for (int y = 0; y < mat.rows; ++y) { for (int x = 0; x < mat.cols; ++x) { cv::Vec3f point = mat.at<cv::Vec3f>(y, x); if (fabs(point[2] - max_z) < FLT_EPSILON || fabs(point[2]) > max_z) continue; out << point[0] << " " << point[1] << " " << point[2] << "\n"; } } file.close(); qInfo() << "[提示] 点云已保存至:" << filename; } // OpenCV Mat 转 Qt QImage(支持灰度/彩色) QImage cvMatToQImage(const cv::Mat& mat) { // 灰度图(CV_8UC1) if (mat.type() == CV_8UC1) { return QImage(mat.data, mat.cols, mat.rows, mat.step, QImage::Format_Grayscale8); } // 彩色图(CV_8UC3,BGR转RGB) else if (mat.type() == CV_8UC3) { cv::Mat rgbMat; cv::cvtColor(mat, rgbMat, cv::COLOR_BGR2RGB); return QImage(rgbMat.data, rgbMat.cols, rgbMat.rows, rgbMat.step, QImage::Format_RGB888); } return QImage(); } // 读取双目内参(yml文件) bool readStereoIntrinsics( const QString& filename, cv::Mat& M1, cv::Mat& D1, cv::Mat& M2, cv::Mat& D2) { cv::FileStorage fs(filename.toStdString(), cv::FileStorage::READ); if (!fs.isOpened()) { qWarning() << "[错误] 内参文件打开失败:" << filename; return false; } fs["M1"] >> M1; fs["D1"] >> D1; fs["M2"] >> M2; fs["D2"] >> D2; fs.release(); return true; } // 读取双目外参(yml文件) bool readStereoExtrinsics( const QString& filename, cv::Mat& R, cv::Mat& T, cv::Mat& R1, cv::Mat& R2, cv::Mat& P1, cv::Mat& P2, cv::Mat& Q, cv::Rect& roi1, cv::Rect& roi2) { cv::FileStorage fs(filename.toStdString(), cv::FileStorage::READ); if (!fs.isOpened()) { qWarning() << "[错误] 外参文件打开失败:" << filename; return false; } fs["R"] >> R; fs["T"] >> T; fs["R1"] >> R1; fs["R2"] >> R2; fs["P1"] >> P1; fs["P2"] >> P2; fs["Q"] >> Q; // 读取ROI(若文件中存在) if (fs["validRoi1"].isNone() || fs["validRoi2"].isNone()) { roi1 = cv::Rect(0, 0, 0, 0); roi2 = cv::Rect(0, 0, 0, 0); } else { std::vector<int> roi1Vec, roi2Vec; fs["validRoi1"] >> roi1Vec; fs["validRoi2"] >> roi2Vec; roi1 = cv::Rect(roi1Vec[0], roi1Vec[1], roi1Vec[2], roi1Vec[3]); roi2 = cv::Rect(roi2Vec[0], roi2Vec[1], roi2Vec[2], roi2Vec[3]); } fs.release(); return true; } ui界面文件写哪些内容
最新发布
09-27
1.该程序用QT开发,实现图片导入、显示、缩放、拖动及处理(冷暖色、灰度、亮度、饱和、模糊、锐化)。 经实测,我写的这个软件在导入10000*7096像素的超大图片的时候,缩放的速度比2345看图软件还快,2345缩放超大图会卡顿,但本软件不会^_^ 关于程序中缩放拖动部分的说面参见我的博客https://blog.youkuaiyun.com/weixin_43935474/article/details/89327314; 2.载入图片后,鼠标移动的时候可以显示鼠所在点的图像的坐标以及灰度; 3.缩放的时候,图片右上角可以显示当前图片的缩放比例; 4.用户可导入16位深的tiff灰度图文件(一般来说是由相机拍摄的灰度图数据),导入16位深的tiff的时候,用户需要先点击界面左上角的checkbox,然后再导入tiff图片,否则图片解析不出来。 注:Qt自带的QImage只能导入8位深的tiff灰度图,如果用qt的QImage导入16位深的灰度图,图像数据会被强制转换成argb格式的图像,数据就被更改了,所以我自己编写一个解析tiff文件的功能,我翻阅了很多博客,其中如下链接给我的帮助最大: https://blog.youkuaiyun.com/chenlu5201314/article/details/56276903 上述博客作为详细解析tiff文件结构的说明文档,写的非常详细,我也是根据上面的内容,自己编写了一个解析tiff文件的类(当然功能很少,只能解析符合特定条件的tiff文件) //************************************************************ //by Bruce Xu //注:解析tiff的类只解析特定的tiff文件! //1.解析的tiff文件中只存在一幅图,如果文件中存在多幅图,本类不支持解析! //2.图像数据为8位或16位深度的灰度图,如果是其他类型的图片,本类不支持解析! //3.图片没有被压缩过! //************************************************************
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值