OpenCV基础: 图像矩阵Mat的数据类型与访问等
质量声明:原创文章,内容质量问题请评论吐槽。如对您产生干扰,可私信删除。主要参考:,Mat数据类型总结,像素值读取at()函数
文章目录Mat矩阵的定义独立定义引用定义(内存相同)复制定义(内存独立)特殊定义模板定义Mat矩阵的数据类型基本类型数据类型转换convertTo归一化cv::normalizeMat数组的访问独立访问数组元素区块访问与赋值区域替换摘要:随时更新完善opencv中Mat相关的定义,类型,访问和应用.
Mat矩阵的定义opencv中的cv::Mat类用于定义任意维度的稠密数组,所谓稠密,是指该数组任一位置的元素都有确定值,即使是0.
独立定义定义变量的同时进行初始化:
cv::Matimg(640,480,CV_8UC1,cv::Scalar(100));//定义单通道灰度图,640x480,100cv::Matsrc(800,640,CV_8UC3,cv::Scalar(70,160,70));//定义三通道彩色图,数据类型为8位无符号整型cv::Matdst(960,540,CV_32FC3,cv::Scalar(1.0f,0.0f,0.0f));//定义三通道彩色图,数据类型为32位浮点型先定义,再初始化:
cv::Matsrc;src.create(800,640,CV_8UC1);img.setTo(cv::Scalar(0));cv::Matsrc(800,640,CV_8UC3);src.setTo(cv::Scalar(255,0,0));引用定义(内存相同)cv::Matdst(src);cv::Matdst=src;cv::Mat&dst=src;cv::Matroi(src,cv::Rect(0,0,200,100));复制定义(内存独立)clone与copyTo:
cv::Matdst=src.clone();cv::Matdst;src.copyTo(dst);构造同型矩阵:
cv::Matdst(src.size(),CV_8UC1,cv::Scalar(0));独立提取ROI:
cv::Matroi=src(cv::Rect(0,0,200,100)).clone();cv::Rectroi_rect(0,0,200,100);cv::Matroi=src(roi_rect).clone();cv::Rectroi_rect(0,0,200,100);cv::Matroi;src(roi_rect).copyTo(roi);特殊定义零矩阵:
cv::Matzeros=cv::Mat::zeros(100,100,CV_8UC1);幺矩阵:
cv::Matones=cv::Mat::ones(100,100,CV_8UC1);单位阵:
cv::Mateye=cv::Mat::eye(100,100,CV_8UC1);特别注意:如果创建多通道数组,则只有第一通道被赋值,其余通道为全0.以下示例创建的是个蓝色图像,而不是纯白图像:
cv::Matblue=cv::Mat::ones(100,100,CV_8UC3)*255;模板定义(待完善)
cv::Matm(constcv::Vec&vec,bool=copyData=true);cv::Mat(constcv::Matx&vec,boolcopyData=true);cv::Mat(conststd::vector&vec,boolcopyData=true);Mat矩阵的数据类型基本类型明确矩阵元素的数据类型,对于访问数组元素和元素运算至关重要,选错数据类型会产生错误结果,误导后续处理.一个有效的数据类型需要同时指明数据的类型和通道数,格式为CV_{8U,8S,16U,16S,32S,32F,64F}C{1,2,3}数值位数bits具体类型取值范围等同C++变量CV_8U8位无符号整数(0……255)uchar,unsignedcharCV_8S8位带符号整数(-128……127)charCV_16U16位无符号整数(0……65535)ushort,unsignedshort,unsignedshortintCV_16S16位带符号整数(-32768……32767)short,shortintCV_32S32位带符号整数(-2147483648……2147483647)int,longCV_32F32位单精度浮点数±(1.18e-38……3.40e38)floatCV_64F64位双精度浮点数±(2.23e-308……1.79e308)double注:CV_USRTYPE1supporthasbeendroppedinOpenCV4.0.如何获取未知矩阵的数据类型,最直接的方法是查阅接口文档,熟记常用变量的数据类型也可以通过成员函数type()获得Mat矩阵元素的数据类型,不建议使用depth()获取通道中的元素类型.但type()函数返回的是int型数值,需进一步查表,才能得到对应的数据类型.类型C1C2C3C4CV_8U081624CV_8S191725CV_16U2101826CV_16S3111927CV_32S4122028CV_32F5132129CV_64F6142230提示:PNG格式的彩色图像除了BGR3个通道外,还有一个透明度通道,所以存在C4.示例:
cv::Matsrc=cv::Mat::ones(100,100,CV_8SC3);coutMat类型转换之int(阈值0
目录1、方式一、利用 IplImage数据类型转换2、利用 cvConvertScale进行阈值转换3、将 IplImage转换成Mat类型1、方式一、利用 IplImage数据类型转换1、声明一个 IplImage指针*dst,并进行数据深度转换dst的数据部分在数值上与src的值一致,而其深度转换成了64F。 其中深度指的是每一个像素的位数(bits),在opencv的Mat.depth()中得到的是一个0–6的数字,分别代表不同的位数:enum{CV_8U=0,CV_8S=1,CV_16U=2,CV_16S=3,CV_32S=4,CV_32F=5,CV_64F=6};可见0和1都代表8位,2和3都代表16位,4和5代表32位,6代表64位。
//dst的数据部分在数值上与src的值一致,而其深度转换成了64F,实现由int类型转换到double。
IplImage*dst=cvCreateImage(cvSize(src->width,src->height),IPL_DEPTH_64F,3);//IplImage类型的*src中存储的是转换前的数据2、利用 cvConvertScale进行阈值转换//将输入图像的像素点double类型值域由0-255转换成0-1
cvConvertScale(src,dst,1.0/255,0); 3、将 IplImage转换成Mat类型 dst_image=cv::cvarrToMat(dst);//dst_image存储转换后的Mat数据方式二、利用Mat矩阵数据类型转换cv::convertTo函数实现
src.convertTo(src,CV_64FC3,1.0/225);src的数据类型是CV_8UC3一般图像文件格式使用的是unsigned8bits,对应的整型数据类型有:CV_8UC1、CV_8UC2,CV_8UC3
其中,CV_8UC3表示3通道8位的unsignedchar型。
浮点数据类型说明:
float是32位,对应的CvMat数据结构类型是:CV_32FC1,CV_32FC2,CV_32FC3;其中,CV_32FC3表示32位的3通道float型
double是64位,对应的CvMat数据结构类型是:CV_64FC1,CV_64FC2,CV_64FC3;其中,CV_64FC3表示64位的3通道double型。
转载请注明:Allen101zhang的CSDN博客 Mat类型转换之int(阈值0-255)转double(阈值0-1)类型OpenCV实现_拾光夕拾的博客-CSDN博客_opencvmat0-255
关注公众号“拾光夕拾”,回复“1024”即可免费领取110本经典编程电子书。
opencv 图像类型(Mat、图像字节流、Bitmap、BITMAPINFO、CxImage、AVFrame)之间的转换
一、Mat与IplimageMatIplimage:直接赋值
IplImage*iplImg=cvLoadImage("greatwave.jpg",1);Matmtx(iplImg);//IplImage*->Mat共享数据//or:Matmtx=iplImg;cvReleaseImage(&iplImg);Iplimage ---> CvvImage:用“Copyof”
CvvImagecImg;Iplimagemyimg;cImg.Copyof(myimg,-1);Opencv2.2版本以上CvvImage类的使用,参考这篇文章Opencv2.2版本以上CvvImage类的使用-我自逍遥笑-博客园
二、Mat与图像数据
std::vectorMat2ImageData(constcv::Mat&img,std::stringimgType="jpg"){ std::vectorvecImgData; std::vectorvecCompression_params; vecCompression_params.push_back(CV_IMWRITE_JPEG_QUALITY); vecCompression_params.push_back(100); imgType="."+imgType; cv::imencode(imgType,img,vecImgData,vecCompression_params); returnvecImgData;}cv::MatImageData2Mat(std::vectorvecImageData){ cv::Matimg; img=cv::imdecode(vecImageData,CV_LOAD_IMAGE_COLOR); returnimg;}三、Mat转Bitmap
//获取图片宽度。绘制图片时,一定要保证Mat图片符合window图片要求(即每行字节数为4的倍数),如果不满足则要进行适当的转化,否则画出的图像会出现问题(图像不是标准图像,反而是斜的)。intGetSuiteableWidth(constintprewidth){ intnwidth=0; intnremainder=prewidth%4; if(nremainder==0) { returnprewidth;//宽度pix } else { return(prewidth/4+1)*4;//宽度pix } return0;}voidFillBitmapInfo(BITMAPINFO*bmi,intwidth,intheight,intbpp,intorigin){ BITMAPINFOHEADER*bmih=&(bmi->bmiHeader); memset(bmih,0,sizeof(*bmih)); bmih->biSize=sizeof(BITMAPINFOHEADER);//指定文件大小,包括这14个字节 /*32位的Windows操作系统处理4个字节(32位)的速度比较快,所以BMP的每一行颜色占用的字节数规定为4的整数倍。MyBmp.bmp中一行颜色有两个像素,共占用6字节,如果要补齐4*2=8字节,就要再加两个0字节。行补位的公式为:widthBytes=(width*biBitCount+31)/32*4*/ //width=(width*bpp+width)/32*4; bmih->biWidth=GetSuiteableWidth(width);//宽度pix bmih->biHeight=origin?abs(height):-abs(height);//高度 .bMP文件的数据从下到上,从左到右的。也就是说,从文件中最先读到的是图象最下面一行的左边第一个象素,然后是左边第二个象素……接下来是倒数第二行左边第一个象素,左边第二个象素……依次类推,最后得到的是最上面一行的最右一个象素。 bmih->biPlanes=1;//目标设备的级别,必须为1 bmih->biBitCount=(unsignedshort)bpp;//每个像素所需的位数,必须是1(双色),每个像素的位数 //1-黑白图,4-16色,8-256色,24-真彩色4(16色),8(256色)或24(真彩色)之一 bmih->biCompression=BI_RGB;//位图压缩类型,必须是0(不压缩),1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一// bmih->biSizeImage=bmih->biHeight*8*height; /*biSizeImage 指定实际的位图数据占用的字节数,其实也可以从以下的公式中计算出来: biSizeImage=biWidth’×biHeight 要注意的是:上述公式中的biWidth’必须是4的整倍数(所以不是biWidth,而是biWidth’, 表示大于或等于biWidth的,最接近4的整倍数。举个例子,如果biWidth=240,则biWidth’=240; 如果biWidth=241,biWidth’=244)。*/}CBitmap*Mat2CBitmap(constcv::MatimgTmp){ HDChDC=this->GetDC()->GetSafeHdc(); ucharbuffer[sizeof(BITMAPINFOHEADER)+1024]; BITMAPINFO*bmi=(BITMAPINFO*)buffer; intbmp_w=imgTmp.cols,bmp_h=imgTmp.rows; intnchannels=imgTmp.channels(); intbpp=(imgTmp.depth()+1)*nchannels; FillBitmapInfo(bmi,bmp_w,bmp_h,bpp*8,0); /* DWORDbiSizeImage;//位图的大小,以字节为单位 LONGbiXPelsPerMeter;//位图水平分辨率,每米像素数 LONGbiYPelsPerMeter;//位图垂直分辨率,每米像素数 DWORDbiClrUsed;//位图实际使用的颜色表中的颜色数 DWORDbiClrImportant;//位图显示过程中重要的颜色数72*8 */ char*pBits=NULL; HBITMAPhBitmap=CreateDIBSection(hDC,bmi,DIB_RGB_COLORS,(void**)&pBits,NULL,0); intpixelBytes=imgTmp.channels()*(imgTmp.depth()+1);//计算一个像素多少个字节 if(bmp_w%4==0) { memcpy(pBits,imgTmp.data,pixelBytes*bmp_w*bmp_h); } else { //原始图像宽度不是4的倍数,将实际图片数据一行一行拷贝过去 intntempW=GetSuiteableWidth(bmp_w); for(size_ti=0;iAttach(hBitmap); returnpBitmap;}四、Mat转BITMAPINFO
voidMat2BITMAPINFO(constcv::Matimage,BITMAPINFO*imgInfo){ //根据图像通道数建立图像信息(这里假定图像像素为24与32位或者8位(有颜色表的类似)) if(image.channels()==3||image.channels()==4) { imgInfo=(BITMAPINFO*)newBYTE[sizeof(BITMAPINFOHEADER)]; } else //8位,有颜色表 { imgInfo=(BITMAPINFO*)newBYTE[sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD)]; //颜色表赋值 for(inti(0);ibmiColors[i].rgbBlue=i; imgInfo->bmiColors[i].rgbGreen=i; imgInfo->bmiColors[i].rgbRed=i; imgInfo->bmiColors[i].rgbReserved=0; } } //头文件信息(注意由实际显示情况可得出图像原点显示在空间左下角) imgInfo->bmiHeader.biSize=sizeof(BITMAPINFOHEADER); imgInfo->bmiHeader.biBitCount=8*image.channels(); imgInfo->bmiHeader.biHeight=-image.rows; imgInfo->bmiHeader.biWidth=image.cols; imgInfo->bmiHeader.biPlanes=1; imgInfo->bmiHeader.biCompression=BI_RGB; imgInfo->bmiHeader.biSizeImage=image.channels()*image.cols*image.rows; imgInfo->bmiHeader.biXPelsPerMeter=0; imgInfo->bmiHeader.biYPelsPerMeter=0; imgInfo->bmiHeader.biClrUsed=0; imgInfo->bmiHeader.biClrImportant=0;}//测试代码voidCPointMatchDlg::OnPaint(){ CDC*pDC; pDC=GetDlgItem(IDC_MATCH_PICTURE_CONTROL)->GetDC(); CRecrimgCtrlRect; GetDlgItem(IDC_MATCH_PICTURE_CONTROL)->GetClientRect(&imgCtrlRect); pDC->SetStretchBltMode(COLORONCOLOR); ::StretchDIBits(pDC->GetSafeHdc(), 0,0, imgCtrlRect.Width(),m_imgCtrlRect.Height(), 0,0, m_image.cols,m_image.rows, m_image.data, m_imgInfo, DIB_RGB_COLORS, SRCCOPY); ReleaseDC(pDC);}注意:这里绘制图片时,一定要保证Mat图片符合window图片要求(即每行字节数为4的倍数),如果不满足则要进行适当的转化,否则画出的图像会出现问题(图像不是标准图像,反而是斜的)。如果图片行字节数不是4的倍数,修改为如下语句:
cv::MattempImg= cv::imread("d:\test.jpeg",cv::IMREAD_UNCHANGED); m_image=cv::Mat::zeros(tempImg.rows,(tempImg.cols+3)/4*4,m_image.type()); //转化行字节数为4的倍数tempImage.copyTo(m_image(cv::Rect(0,0,tempImg.cols,tempImg.rows)));五、Mat与CxImage
CxImageimg;img.Load("C:\f.jpg");uint8_t*buf=NULL;int32_tlen=0;boolrs=img.Encode(buf,len,CXIMAGE_FORMAT_BMP);cv::Mattemp2;vectorbuff2;buff2.resize(len);memcpy(&buff2[0],buf,len);temp2=cv::imdecode(buff2,1);delete[]buf;//要释放buf,这个buf在函数里分配了内存cv::imshow("111",temp2);cv::waitKey(); //toCximagevectorbuff;cv::imencode(".bmp",temp2,buff);CxImageimg2(&buff[0],buff.size(),CXIMAGE_FORMAT_BMP);img2.Blt(GetDlgItem(IDC_STATIC_P)->GetDC()->GetSafeHdc());六、Mat与AVFrame
Mat是opencv的图像格式,颜色空间为BGR,对应FFmpeg格式为AV_PIX_FMT_BGR24。AVFrame一般为YUV420P,以此格式为例。这个通过FFmpeg的格式转换函数就可以解决。
extern"C"{#include"libavutil/avutil.h"#include"libavcodec/avcodec.h"#include"libavformat/avformat.h"#include"libswscale/swscale.h"#include}#include//AVFrame转cv::matcv::MatavframeToCvmat(constAVFrame*frame){intwidth=frame->width;intheight=frame->height;cv::Matimage(height,width,CV_8UC3);intcvLinesizes[1];cvLinesizes[0]=image.step1();SwsContext*conversion=sws_getContext(width,height,(AVPixelFormat)frame->format,width,height,AVPixelFormat::AV_PIX_FMT_BGR24,SWS_FAST_BILINEAR,NULL,NULL,NULL);sws_scale(conversion,frame->data,frame->linesize,0,height,&image.data,cvLinesizes);sws_freeContext(conversion);returnimage;}//cv::Mat转AVFrameAVFrame*cvmatToAvframe(cv::Mat*image,AVFrame*frame){intwidth=image->cols;intheight=image->rows;intcvLinesizes[1];cvLinesizes[0]=image->step1();if(frame==NULL){frame=av_frame_alloc();av_image_alloc(frame->data,frame->linesize,width,height,AVPixelFormat::AV_PIX_FMT_YUV420P,1);}SwsContext*conversion=sws_getContext(width,height,AVPixelFormat::AV_PIX_FMT_BGR24,width,height,(AVPixelFormat)frame->format,SWS_FAST_BILINEAR,NULL,NULL,NULL);sws_scale(conversion,&image->data,cvLinesizes,0,height,frame->data,frame->linesize);sws_freeContext(conversion);returnframe;}cv::MatavframeToCvmat2(AVFrame*yuv420Frame){//得到AVFrame信息intsrcW=yuv420Frame->width;intsrcH=yuv420Frame->height;SwsContext*swsCtx=sws_getContext(srcW,srcH,(AVPixelFormat)yuv420Frame->format,srcW,srcH,(AVPixelFormat)AV_PIX_FMT_BGR24,SWS_BICUBIC,NULL,NULL,NULL);//生成Mat对象cv::Matmat;mat.create(cv::Size(srcW,srcH),CV_8UC3);//格式转换,直接填充Mat的数据dataAVFrame*bgr24Frame=av_frame_alloc();av_image_fill_arrays(bgr24Frame->data,bgr24Frame->linesize,(uint8_t*)mat.data,(AVPixelFormat)AV_PIX_FMT_BGR24,srcW,srcH,1);sws_scale(swsCtx,(constuint8_t*const*)yuv420Frame->data,yuv420Frame->linesize,0,srcH,bgr24Frame->data,bgr24Frame->linesize);//释放av_frame_free(bgr24Frame);sws_freeContext(swsCtx);returnmat;}AVFrame*cvmatToAvframe2(cv::Mat&inMat){//得到Mat信息AVPixelFormatdstFormat=AV_PIX_FMT_YUV420P;intwidth=inMat.cols;intheight=inMat.rows;//创建AVFrame填充参数注:调用者释放该frameAVFrame*frame=av_frame_alloc();frame->width=width;frame->height=height;frame->format=dstFormat;//初始化AVFrame内部空间intret=av_frame_get_buffer(frame,32);if(retdata[2],data+frame_size*5/4,frame_size/4);returnframe;}