OpenCV学习笔记之扫描图像

一、 图像在内存中存储方式

图像矩阵的大小取决于我们所用的颜色模型,确切地说,取决于所用通道数。如果是灰度图像,矩阵就会像这样:

OpenCV学习笔记之扫描图像_第1张图片

而对多通道图像来说,矩阵中的列会包含多个子列,其子列个数与通道数相等。例如,RGB颜色模型的矩阵:

OpenCV学习笔记之扫描图像_第2张图片

注意到,子列的通道顺序是反过来的:BGR而不是RGB。很多情况下,因为内存足够大,可实现连续存储,因此,图像中的各行就能一行一行地连接起来,形成一个长行。连续存储有助于提升图像扫描速度,我们可以使用 isContinuous() 来去判断矩阵是否是连续存储的. 相关示例会在接下来的内容中提供。

二、扫描图像几种方式

2.1 指针访问

/*!
 * \brief scanImagePtr
 * \param image
 * \return
 */
Mat& scanImagePtr(Mat &image){
    double start = static_cast(getTickCount());
    //! 行
    int rowNumber = image.rows;
    //! 每一行元素个数 = 列数 x 通道数
    int colNumber = image.cols * image.channels();
    for (int i = 0; i < rowNumber; i++)
    {
        //! 获取第i行的首地址
        uchar* data = image.ptr(i);
        for (int j = 0; j < colNumber; j++)
        {
            data[j] /= 2;
        }
    }
    double end = static_cast(getTickCount());
    double time = (end - start) / getTickFrequency();
    cout << "type1:" << time << "s" << endl;
    return image;
}

2.2 迭代器iterator

/*!
 * \brief scanImageiterator
 * \param image
 * \return
 */
Mat& scanImageiterator(Mat &image){
    double start = static_cast(getTickCount());
    //! 初始位置的迭代器
    Mat_::iterator it = image.begin();
    //! 终止位置的迭代器
    Mat_::iterator itend = image.end();
    for (; it != itend; it++)
    {
        //! 处理BGR三个通道
        (*it)[0] = 255;//B
        //(*it)[1] = 255;//G
        //(*it)[2] = 0;//R
    }
    double end = static_cast(getTickCount());
    double time = (end - start) / getTickFrequency();//计算时间
    cout << "type2:" << time << "s" << endl;
    return image;
}

2.3 动态地址计算

/*!
 * \brief scanImageAt
 * \param image
 * \return
 */
Mat& scanImageAt(Mat &image){
    double start = static_cast(getTickCount());
    int rowNumber = image.rows;
    int colNumber = image.cols;
    for (int i = 0; i < rowNumber; i++)
        for (int j = 0; j < colNumber; j++)
        {
            //! 处理BGR三个通道
            //image.at(i, j)[0] = 0;//B
            image.at(i, j)[1] = 255;//G
            //image.at(i, j)[2] = 0;//R
        }
    double end = static_cast(getTickCount());
    double time = (end - start) / getTickFrequency();//计算时间
    cout << "type3:" << time << "s" << endl;
    return image;
}

2.4 三种方法效能对比

type1:0.000189559s
type2:0.000832323s
type3:0.000424337s

 经典的C风格运算符[](指针)访问要更胜一筹。

代码详见《OpenCV扫描图像三种方式练习》

三、OpenCv坐标系

OpenCV中坐标体系中的零点坐标定义为图片的左上角,X轴为图像矩形的上面那条水平线,从左往右;Y轴为图像矩形左边的那条垂直线,从上往下。在Point(x,y)和Rect(x,y)中,第一个参数x代表的是元素所在图像的列数,第二个参数y代表的是元素所在图像的行数,而在at(x,y)中是相反的。

OpenCV学习笔记之扫描图像_第3张图片

参考资料:

  •  OpenCV坐标系与操作像素的四种方法
  • OpenCV如何扫描图像、利用查找表和计时
  • Opencv中三种操作像素的方法

你可能感兴趣的:(#,OpenCV学习之路)