一.基本操作
1.1 创建
cv::Mat初识和它的六种创建方法
cv::Mat matDes(nHEIGHT,nWID,CV_8UC1, cv::Scalar(0));//创建 row(高),col(宽)
cv::Mat matDes = cv::Mat::zeros(nHEIGHT,nWID,CV_8UC1);//创建 黑色矩阵 matlap方法
m_Mat.create(nRow, 1000, m_MatImg.type());//, cv::Scalar(0)
matDes=cv::Mat(nImgH,nImgW,CV_8UC1,cv::Scalar(255));
1.2 Mat保存
std::vector <int> compression_params;
compression_params.push_back(259);
if(0 == m_nImgType){
compression_params.push_back(1);//1-无压缩
}
else if(1 == m_nImgType){
compression_params.push_back(5);//5-COMPRESSION_LZW
}
cv::imwrite(sPath.toStdString(),mat,compression_params);//默认替换现有文件
1.2 遍历Mat
int nRows = matSrc.rows,nCols = matSrc.cols;
int nMatType = matSrc.type();
if(0 == nMatType){//CV_8UC1
uchar* pDataSrc = NULL;
for (int i = 0; i< nRows; i++)
{
pDataSrc = matSrc.ptr<uchar>(i);
if(pDataSrc ==NULL) continue;
for (int j = 0; j < nCols; j++)
{
pDataSrc[j]=cv::saturate_cast<uchar>(m_nMax-pDataSrc[j]);//
}
}
}
else if(2 == nMatType){//CV_16UC1
ushort* pDataSrc = NULL;
for (int i = 0; i< nRows; i++)
{
pDataSrc = matSrc.ptr<ushort>(i);
if(pDataSrc ==NULL) continue;
for (int j = 0; j < nCols; j++)
{
pDataSrc[j]=cv::saturate_cast<ushort>(m_nMax-pDataSrc[j]);//
}
}
}
1.4 Mat的部分赋值剪贴
cv::Mat DesROIMat =matDes(cv::Rect(nX2,nY2,nWid,nHeight)); //范围时 宽,高
matSrc.copyTo(DesROIMat);//深复制? 位数不一致会导致copy失败
1.5 判断Mat有效性/是否加载成功
matFile.empty()
nullptr==matFile.data
1.6 16位Mat转8位
void oeThread_LS::Mat16ToMat8(cv::Mat &mat16,cv::Mat &mat8)
{
Mat tmp;
mat8 = Mat::zeros(mat16.size(), CV_8U);
normalize(mat16, tmp, 0, 255, NORM_MINMAX);
convertScaleAbs(tmp, mat8);
}
1.7 Mat旋转90度-逆时针
//顺时针90度+沿y轴翻转
transpose(matFileCut, matCopy);//顺时针90度+沿y轴翻转
//flip(matCopy, matCopy, 0);//逆时针90度
//flip(matCopy, matCopy, 1);//顺时针90度
//flip(matFile, matCopy,-1);//顺时针90度+沿y轴翻转 / 逆时针90度+沿x轴翻转
//沿y轴翻转
transpose(matFileCut, matCopy);//顺时针90度+沿y轴翻转
flip(matCopy, matCopy, 1);//顺时针90度
1.8 Mat的缩放
int nRow = matSrc.rows*fScale;
int nCol = matSrc.cols*fScale;
cv::Mat matDes(nRow,nCol,CV_8UC3,cv::Scalar(0));//先分配内存,否则无效Mat致崩
cv::resize(matSrc,matDes,matDes.size());
二.常见问题记录
2.1 Mat致崩
如cv::resize范围不合理致崩,但不明确定位报错。
2.2 cv::imread读取异常
A.Debug下无带d的cv库。
B.读、写16位tif得到图片全白(读取图片类型、默认灰度值,文件后缀保存时一致)。
C.|与||,按位或与逻辑或,结果分别为二进制数和bool,此处用前者|。
D.读取中文路径,sPath.toLocal8Bit().toStdString(),cv::imwrite类似。
cv::Mat matSrc=cv::imread(sJpgPath.toStdString(),cv::IMREAD_GRAYSCALE|cv::IMREAD_ANYDEPTH);
//0 pow(256,matSrc.type())-1
cv::Mat matDes(nHEIGHT,nWID,matSrc.type(),cv::Scalar(0));//CV_8UC1创建 0黑255白 row,col
cv::Mat DesROIMat =matDes(cv::Rect(nX2,nY2,nWid,nHeight));//越界致崩
matSrc.copyTo(DesROIMat);//深复制? Mat的部分赋值(剪贴)
QString sDesPath = m_sPathOut + "/"+fileInfo.baseName()+'.'+fileInfo.suffix();
cv::imwrite(sDesPath.toStdString(),matDes);//无.jpg后缀会致崩
三.加载BigTif
修改opencv位限制长度。
BigTif右键不能看到具体属性信息,也看不到缩略图。
Debug BigTif8可打开,BigTif16可打开
Debug |
Release |
BigTif8可打开 |
BigTif8可打开 |
BigTif16可打开 |
BigTif16不可打开,借助相关库 |
cv::Mat oeToolMat::ReadBigTif(QString sPath)
{
cv::Mat ImageMat;
int i, nret, nw, nh, nbpp, npage = 1;
TIFF* tif;
tif = TIFFOpen(sPath.toStdString().c_str(), "r");
if (tif)
{
TIFFSetDirectory(tif, 1); // 跳到指定的页数1
int iRett = TIFFIsBigTIFF(tif);//
int iRow, iCol, iBitsPerChannel, iChannels, iComp;
nret = TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &iCol); // 获取图像长、宽
nret = TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &iRow);
nret = TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &iBitsPerChannel);
nret = TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &iChannels);
nret = TIFFGetField(tif, TIFFTAG_COMPRESSION, &iComp);//5 LZW
int scanlineSize = TIFFStripSize(tif);
int nStrip = TIFFNumberOfStrips(tif);
uint32* bc; // wrong size??
nret = TIFFGetField(tif, TIFFTAG_STRIPBYTECOUNTS, &bc);
int iDepth = CV_8UC1;
if (iBitsPerChannel == 8)
{
iDepth = CV_8UC1;
}
else if (iBitsPerChannel == 16)
{
iDepth = CV_16UC1;
}
npage = TIFFNumberOfDirectories(tif); // 读取页数
ImageMat.create(iRow, iCol, iDepth);
tdata_t buf;
uint32 row;
buf = _TIFFmalloc(TIFFScanlineSize(tif));
for (row = 0; row < iRow; row++)
{
TIFFReadScanline(tif, buf, row);
memcpy(ImageMat.data + ImageMat.step * row, buf, scanlineSize);
}
_TIFFfree(buf);
TIFFClose(tif);
}
return ImageMat;
}
四.Mat传参
4.1 Qt信号槽需先注册Mat
#include <QMetaType>
qRegisterMetaType< cv::Mat >("cv::Mat&");//()内cv::Mat&或cv::Mat皆可
传cv::Mat&正常。
传cv::Mat异常
void RunProcess::Rotate(cv::Mat& ImageSrc)
{
cv::imwrite(QString("D:/1.tif").toStdString(),ImageSrc);
transpose(ImageSrc,ImageSrc);//顺时针90度+沿y轴翻转
flip(ImageSrc,ImageSrc,0);//逆时针90度
flip(ImageSrc,ImageSrc,1);//顺时针90度
cv::imwrite(QString("D:/2.tif").toStdString(),ImageSrc);
}
4.2 传入Mat修改
传cv::Mat&/cv::Mat失败,return cv::Mat成功。
猜测
1.形参image为临时副本,只读不修改。
2.warpAffine造成。
cv::Mat RunProcess::Rotate(cv::Mat image, int degree)
{
cv::Mat M,dst= image.clone();//猜测该函数结束后会释放
int h = image.rows;
int w = image.cols;
M = getRotationMatrix2D(cv::Point2f(w / 2, h / 2), degree, 1.0);//定义变换矩阵M 45
double cos = abs(M.at<double>(0, 0)); //求cos值
double sin = abs(M.at<double>(0, 1)); //求sin值
int nw = cos * w + sin * h; //计算新的长、宽
int nh = sin * w + cos * h;
M.at<double>(0, 2) += (nw / 2 - w / 2); //计算新的中心
M.at<double>(1, 2) += (nh / 2 - h / 2);
warpAffine(image, dst,M,cv::Size(nw, nh), cv::INTER_LINEAR, 0, cv::Scalar(255));//,255,255
image = dst.clone();
return dst;
}
//传cv::Mat &image 成功
void RunProcess::Rotate3(cv::Mat &image, int degree)
{
cv::Mat M;//dst,
int h = image.rows;
int w = image.cols;
M = getRotationMatrix2D(cv::Point2f(w / 2, h / 2), degree, 1.0);//定义变换矩阵M 45
double cos = abs(M.at<double>(0, 0)); //求cos值
double sin = abs(M.at<double>(0, 1)); //求sin值
int nw = cos * w + sin * h; //计算新的长、宽
int nh = sin * w + cos * h;
M.at<double>(0, 2) += (nw / 2 - w / 2); //计算新的中心
M.at<double>(1, 2) += (nh / 2 - h / 2);
warpAffine(image, image, M, cv::Size(nw, nh), cv::INTER_LINEAR, 0, cv::Scalar(0));//,255,255
}