前言
在OpenCV中,图像的遍历有多种方法,其中常用的有:
1、最快速--ptr指针
2、最安全--迭代器
3、最便捷--at方法
下面引用大神的代码实验结果:很明显,指针的效率最高,迭代器的效率最低。
Time of scan_image_c (averaged for 100 runs): 2.04884 ms.
Time of scan_image_iterator (averaged for 100 runs): 4.77701 ms.
Time of scan_image_random (averaged for 100 runs): 3.64237 ms.
在此,我选择抄近路,着重学习效率最高的“指针遍历”。
代码示例
示例代码如下:
#include "widget.h"
#include "ui_widget.h"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//读取一张图片,将数据存储到mat3,然后进行处理
cv::Mat mat1 = imread("C:/opencv/123.jpg");
//复制图片(注意,如果是写mat2=mat1,那么结果是mat1和mat2指向同一片数据)
Mat mat2 = mat1.clone();
//遍历图像,将图像每一个像素点的色彩数值减半
for (int i=0;i<mat2.rows;i++)
{
Vec3b *ptr = mat2.ptr<Vec3b>(i);//指针ptr指向图像的第i行
for (int j =0;j<mat2.cols;j++)
{
ptr[j][0]=ptr[j][0]/2;//指针指向图像的第i行、第j列的第1通道
ptr[j][1]=ptr[j][1]/2;//指针指向图像的第i行、第j列的第2通道
ptr[j][2]=ptr[j][2]/2;//指针指向图像的第i行、第j列的第3通道
}
}
namedWindow("显示器1", WINDOW_AUTOSIZE );
imshow("显示器1", mat1 );
namedWindow("显示器2", WINDOW_AUTOSIZE );
imshow("显示器2", mat2 );
}
Widget::~Widget()
{
delete ui;
}
代码运行结果如下,很明显,处理后的图片比原先暗淡了许多。
知识点补充
1.关于Vec3b
在OpenCV中,使用imread读取的图像数据,都是uchar类型,存储到Mat矩阵中;矩阵中的每一个单位,对应图像的一个像素,包含一组数据,对应图像RGB三通道的数值。
将程序运行结果的图像放大,如下图:
实际上,Vec3b可以理解为Vector的二次封装。
Vec3b可以看做是vector<uchar,3>,即一个uchar类型,长度为3的vectro容器。
利用Vec3b将图像中每一个像素的RGB三通道数据分离出来。
示例代码如下:
//读取图像存储到mat矩阵
Mat mat = imread("test.jpg");
//row为行,col为列
mat.at<Vec3b>(row, col)[0] = 255; //修改 B 通道数据
mat.at<Vec3b>(row, col)[1] = 255; //修改 G 通道数据
mat.at<Vec3b>(row, col)[2] = 255; //修改 R 通道数据
2.关于cv::Mat.at 和 cv::Mat.ptr
at操作示例:
cv::Mat image(3,10,CV_32FC3);
for(int i=0; i<image.rows;i++)
{
for(int j=0; j<image.cols; j++)
{
image.at<Vec3f>(i,j)[0]=image.at<Vec3f>(i.j)[0] / 2;
image.at<Vec3f>(i,j)[1]=image.at<Vec3f>(i.j)[1] / 2;
image.at<Vec3f>(i,j)[2]=image.at<Vec3f>(i.j)[2] / 2;
}
};
ptr操作示例:
cv::Mat image(3,10,CV_32FC3);
for(int i=0; i<image.rows;i++)
{
Vect3b *ptr = image.ptr<Vec3b>(i);
for(int j=0; j<image.cols; j++)
{
ptr[j][0]=ptr[j][0] / 2;
ptr[j][1]=ptr[j][1] / 2;
ptr[j][2]=ptr[j][2] / 2;
}
};
ptr操作效率比较高,程序也比较安全,有越界判断,推荐使用。
参考:
图像数据cv::Mat.at和cv::MaT.ptr对单个像素的访问和操作