Mat使用笔记

一.基本操作

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);//ones matlab方法
//矩阵间初值
matDes=cv::Mat(nImgH,nImgW,CV_8UC1,cv::Scalar(255));
//创建矩阵(不赋初值)
m_Mat.create(nRow, 1000, m_MatImg.type());//, cv::Scalar(0)
//数组方式
int sz[2] = { 3, 3 };
cv::Mat M2(2, sz, CV_8UC1, cv::Scalar::all(0));//2维

Mat灰度乘以系数(增强)

mat*=n;//方式一
img.convertTo(img, CV_32F, 0.5);//方式二
cv::Mat scalar = cv::Mat::ones(img.size(), CV_32F) * 0.5;//方式三
cv::multiply(img, scalar, img);

1.2 Mat读写

cv::imread(sPath,cv::IMREAD_GRAYSCALE|cv::IMREAD_ANYDEPTH);读灰度图//
cv::imread(sPath);读三通道图//

保存

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);//默认LZW压缩替换现有文件,.toLocal8Bit().data()可支持中文路径

1.3 遍历Mat

OpenCV Mat遍历的方法
a.通过Mat的ptr指针的[]操作符号,按照数组的方式遍历—>效率最高。
b. 通过迭代器 cv::MatIterator_进行访问—>效率次之,但是是安全的。
c. 不通过ptr指针,直接通过Mat(.at)进行访问—>效率最低, 不适合遍历操作,常用于随机位置的访问。

一般图像行与行之间往往存储是不连续的(ROI裁剪的Mat),但是有些图像可以是连续的(Mat的clone)

裁剪Mat(不连续)存到连续uchar数组/void*连续内存
1.rect裁剪后先clone,再memcpy(成功)或Mat::data.reshape(0,1)(失败)给data赋值。
猜测Mat(rect)后为const,不支持直接memcpy(条纹)、reshape(致崩)、Mat::data赋值给数组(条纹)等操作,需先clone,或直接用为其它Mat的Data。

2.指针逐个遍历,直接Data不行(猜测new后转为数组),用局部变量指针da或Data[]可以。
```cpp
unsigned char* data = new unsigned char[nByte]
unsigned char* da = data;
  uchar* ptr = matFile.ptr<uchar>(h);
    *da++ = ptr[w];
    //data[w+h*nCols] = ptr[w];

a.Mat的ptr指针(先取行,再取列)

int nRows = matSrc.rows,nCols = matSrc.cols;
if(matSrc.isContinuous())
{
    nCols *= nRows;
    nRows = 1;
}

    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]);//
                
                //auto c = matSrc.data[i*nCols+j];
                //matSrc.data[i*nCols+j]=255;
            }
        }
    }
    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]);//
            }
        }
    }

c.逐个点(读Mat值用float时,值异常偏大),暂一般用double

X.at<double>(i, j) = X.at<double>(i, j);//uchar,ushort, 
mat.at<Vec3b>(row, col)[0] = 255; //修改点(row, col)的B通道数据(Vec3b相当于vector<uchar,3>)
mat.at<Vec3b>(row, col);    //三通道,返回 <Vec3b>,即返回一个 uchar 数组,长度为 3
mat.at<Vec3b>(row, col)[1] = mat.at<uchar>(row, col)*k;//变小变形

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());

1.9

二.常见问题记录

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后缀会致崩

2.3 CV_32FC类型mat多线程中cv::imread/imshow异常

致崩ucrtbase.dll报错
opencv笔记(三十一)——Mat 矩阵数据类型转换convertTo

dstmat.convertTo(aa, CV_8U, 255);//测得仍然会致崩

信号槽参数(cv::Rect)时ucrtbase.dll致崩。

三.加载BigTif

修改opencv位限制长度。
BigTif右键不能看到具体属性信息,也看不到缩略图。
Debug BigTif8可打开,BigTif16可打开

DebugRelease
BigTif8可打开BigTif8可打开
BigTif16可打开BigTif16不可打开,借助相关库

四.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
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值