在opencv中,图像是以啥数据类型存储的
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在opencv中,图像是以啥数据类型存储的相关的知识,希望对你有一定的参考价值。
图像内容在计算机内存中是如何存储的,程序中如何访问图像中的某一个像素,RGB图像如何存储,灰度图像如何存储
参考技术A 这个问题分情况,因为opencv的版本在变化,在2.3X之前基本上都是IplImage格式的,这个是Intel的图像格式,但是后来有大神将opencv改成了C++的了,引入了MAT格式,更加贴近MATLAB,这样省略了诸如图像完成之后的destroy,free等等操作,much方便。剩下的就相当简单了追问那图像内容在计算机内存中是如何存储的啊?
追答这个建议你看下计算机图形学的书,我只能这样说,图像是个矩阵,拿简单的二维的来说,也就是行和列,但是计算机的内存没有提供二维数组的存储,都是转换成一维数组来搞定的,至于每一个二维数组的元素存放的是图像的是什么,简单的是RGB值等等
参考技术B uchar 类型RGB 3个字节 每个字节8位 表示0-255 黑色(0,0,0);白色(255,255,255);第一个字节B蓝色通道,蓝色为(255,0,0),第二个字节G绿色通道,绿色为(0,255,0);第三个字节R红色通道,红色为(0,0,255);
灰度 1个字节 0-255 0:黑色 255:白色本回答被提问者采纳
Opencv系列1.4--图像和大型数据类型
//用cv::Mat直接实例化,此时数组无大小无数据类型
cv::Mat m;
//可用create()分配数据,行数3,列数10,数据类型三通道32位单精度,表示二维对象
m.create(3,10,CV_8UC1);
//数组类型决定其元素类型,有效的数组类型需确定元素种类和通道数
//所有类型已通过头文件预定义CV_{8U,16S,16U,32F,32S,64F}C{1,2,3}
//例如CV_32FC3,表示32为单精度三通道数组;
//设定第一通道的值1.0,第二通道0.0,第三通道1.0
m.setTo(cv::Scalar(1.0f,0.0f,1.0f));
//等同于cv::Mat m(3,10,CV_32FC3,cv::Scalar(1.0f,0.0f,1.0f));
通过从另一个cv::Mat复制数据构造,通过行列感兴趣范围构建,或通过cv::Rect指定感兴趣范围构建;
//cv::Mat(const Mat& mat)
//复制构造数组
const cv::Mat img=cv::imread("a.jpg");
cv::imshow("Original Img",img);
cv::waitKey(0);
cv::Mat img_copy(img); //复制构造
cv::imshow("copy img",img_copy);
cv::waitKey(0);
//cv::Mat(const Mat& mat, const cv::Range rows, cv::Range cols);
//获取数组的子数组
const cv::Mat img=cv::imread("a.jpg");
cv::imshow("Original Img",img);
cv::waitKey(0);
//利用cv::Range构造数组
int height=img.cols;
int width = img.rows;
std::cout<<"cols"<<height<<"rows"<<width;
const cv::Range rows=cv::Range(100,800);
const cv::Range cols=cv::Range(100,800);
cv::Mat img_sub(img, cols, rows);
cv::imshow("Sub Img",img_sub);
cv::waitKey(0);
//利用Rect构造数组
cv::Rect rec1=cv::Rect(400,400,600,600);
cv::Mat img_rect(img,rec1);;
cv::imshow("Rect Img",img_rect);
cv::waitKey(0);
cv::Mat m(cv::Mat::zeros(5,5,CV_8UC1));
std::cout<<"Matrix zeros:"<<std::endl<<m<<std::endl;
cv::Mat m1(cv::Mat::ones(4,6,CV_8UC1));
std::cout<<"Matrix ones:"<<std::endl<<m1<<std::endl;
cv::Mat m2(cv::Mat::eye(4,6,CV_8UC1));
std::cout<<"Matrix eye:"<<std::endl<<m2<<std::endl;
访问单个元素的两个主要方法是通过位置或遍历;
直接访问的方法是根据成员函数,at<数据类型>(位置);
cv::Mat m2(cv::Mat::eye(4,6,CV_32FC1));
std::cout<<"Matrix eye:"<<std::endl<<m2<<std::endl;
std::cout<<m2.at<float>(3,3);
//at<数据类型>(位置)
对于多通道数组,方法是类似的:多通道时建议使用cv::Vec<>
cv::Mat img=cv::imread("a.jpg",1);
std::cout<<"img channels: "<<img.channels()<<std::endl;
std::cout<<"value is: "<<img.at<cv::Vec3b>(10,10)[0];
std::cout<<"value is: "<<img.at<cv::Vec3b>(10,10)[1];
std::cout<<"value is: "<<img.at<cv::Vec3b>(10,10)[2];
通过指针函数ptr<>()进行访问,速度最快:
为访问二维数组,我们可以提取一个指向数组具体行的指针,ptr<>()就是cv::Mat中的模板函数。ptr<>()用一个类型名进行实例化,整数参数表示你想访问并且指针指向的行数,函数返回一个指针,指向所建数组中元素类型,也就是说,如果数组类型是CV_32FC3,那么返回值是类型float*。因此,若给定一个三通道矩阵mtx,元素类型float,构造mtx.ptr<Vec3f>(3)返回一个指针,指向矩阵mtx第三行中第一个元素的第一个通道,这是访问数组最快的方式。
int sz[3]={4,4,4};
cv::Mat m(3,sz,CV_32FC3);
cv::randu(m,-1.0f,1.0f);
float max=0.0f;
cv::MatConstIterator<cv::Vec3f> it=m.begin();
while (it!=m.end()){
len2=(*it)[0]*(*it)[0]+(*it)[1]*(*it)[1]+(*it)[2]*(*it)[2];
if(len2>max)max=len2;
it++;
}
需要注意的是,当我调用这些函数时,数组中的数据并未复制到新数组。
Opencv中,进行操作时可能出现溢出等情况,尤其是无符号类型数据进行减法时,因此构建cv::saturate_cast<>()。例如:
uchar& Vxy = m0.at<uchar>(y,x);
Vxy = cv::saturate_cast<uchar>((Vxy-128)*2+128);
在该例子中,我们首先分配一个引用Vxy直向一个8位数组m0中的元素。当我们从这个数组减去128,然后乘以2,在增加128时,C算法规则会对Vxy-128分配32位有符号整数,然后进行乘法和加法。如果Vxy的原始值是10,那么最后结果是-108,将不满足Vxy 8位无符号数据类型,因此必须使用cv::saturate_casts<uchar>(),当低于无符号数据下限时,变为0。
通常用于0项远多于非零项的数组,一般出现在线性代数的稀疏矩阵或者直方图。稀疏数组仅存储那些存在的数据,所以节省空间,实际中稀疏对象太大很难以稠密数组表示;稀疏表示方法的缺点是,计算太慢。
cv::SparseMat类似于cv::Mat,它采用哈希表方式存储数据。
稀疏数组和稠密数组最大的区别在于,如何访问元素。
稀疏数组提供四种访问方法:cv::SparseMat::ptr(),cv::SparseMat::ref(),cv::SparseMat::value(),cv::SparseMat::find();
cv::SparseMat_<>和cv::Mat_<>,通过模板类则不需要使用他们成员的模板;
例如,定义矩阵cv::Mat m(10,10,CV_32FC2);则访问每个元素都需指定矩阵的类型,m.at<Vec2f>(i0,i1)=cv::Vec2f(x,y);
如果用模板类定义m,则不需要具体指明类型使用at(),
cv::Mat_<Vec2f> m(10,10);
m.at(i0,i1)=cv::Vec2f(x,y);
这种模板结构简化了代码;
以上两种方法,效率上相同,但是更建议第二种方法;
以上是关于在opencv中,图像是以啥数据类型存储的的主要内容,如果未能解决你的问题,请参考以下文章