欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

opencv读取图像数据的方式总结

程序员文章站 2024-03-15 09:04:29
...

引言

opencv是计算机视觉中使用最广泛同时也是功能最全的一个开源库,为图像处理以及计算机视觉工作者提供了极大的方便,本文就opencv读取图像数据文件做一个总结,高年级同学以及大牛请无视。

opencv中图像的结构

图像的结构可以看作是一个2维矩阵,opencv在对图像的结构定义中也采用了这一方式。在总结之前,有必要对opencv中图像结构定义的一些成员变量意义进行说明,更详细的请参考opencv官方文档。
nChannels:图像通道数,可取1、2、3、4;
widthStep:可理解成相邻行,同列数据之间的字节数,为了高速的处理效率,图像在存储时会进行填充,保证每行是一个固定字节数,且通常维4的倍数;
width:图像宽;
height:图像高;

数据读取

1.点读取

// 单通道
uchar value = grayim.at<uchar>(i,j);
for( int i = 0; i < grayim.rows; ++i)
    for( int j = 0; j < grayim.cols; ++j )
        grayim.at<uchar>(i,j) = (i+j)%255;


//3通道 Vec3b可看作一个结构体,包含三个元素,分别对应彩色图像的B\G\R,且只能对8U的数据类型使用,如果是float数据的值,可以用Vec3f

for( int i = 0; i < colorim.rows; ++i)
    for( int j = 0; j < colorim.cols; ++j )
    {
        Vec3b pixel;
        pixel[0] = i%255; //Blue
        pixel[1] = j%255; //Green
        pixel[2] = 0; //Red
        colorim.at<Vec3b>(i,j) = pixel;
}

2.图像迭代器

// 单通道
cv::MatIterator_<uchar> grayit, grayend;
for( grayit = grayim.begin<uchar>(), grayend =
grayim.end<uchar>(); grayit != grayend; ++grayit)
    *grayit = rand()%255;

//3通道
cv::MatIterator_<Vec3b> colorit, colorend;
for( colorit = colorim.begin<Vec3b>(), colorend = colorim.end<Vec3b>(); colorit!=colorend; colorit++)
{
    (*colorit)[0]=rand()%255; //B
    (*colorit)[1]=rand()%255; //G
    (*colorit)[2]=rand()%255; //R
}

3.指针读取

for( int i = 0; i < grayim.rows; ++i)
{
    //获取第 i 行首像素指针
    uchar * p = grayim.ptr<uchar>(i);
    //对第 i 行的每个像素(byte)操作
    for( int j = 0; j < grayim.cols; ++j )
    p[j] = (i+j)%255;
}

4.按结构读取

opencv读取图像数据的方式总结

addr(Mi0,i1,…im-1) = M.data + M.step[0] * i0 + M.step[1] * i1 + … +
M.step[m-1] * im-1 (其中 m = M.dims M的维度)

扩展到3维
opencv读取图像数据的方式总结

单通道:
opencv读取图像数据的方式总结

3通道:
opencv读取图像数据的方式总结

5.Mat_读取

考虑下面一段代码:

// 由于数据类型转换,最后的像素值会发生改变
Mat M(600, 800, CV_8UC1);
for( int i = 0; i < M.rows; ++i)
{
    uchar * p = M.ptr<uchar>(i);
    for( int j = 0; j < M.cols; ++j )
    {
        double d1 = (double) ((i+j)%255);
        M.at<uchar>(i,j) = d1;
        double d2 = M.at<double>(i,j);
    }
}

如果采用Mat_模板类则可以避免这种情况:

Mat_<uchar> M1 = (Mat_<uchar>&)M; // 内存地址共享
for( int i = 0; i < M1.rows; ++i)
{
    uchar * p = M1.ptr(i);
    for( int j = 0; j < M1.cols; ++j )
    {
        double d1 = (double) ((i+j)%255);
        M1(i,j) = d1;
        double d2 = M1(i,j);
    }
}