Mat本质上是由两个数据部分组成的类: (包含信息有矩阵的大小,用于存储的方法,矩阵存储的地址等) 的矩阵头和一个指针,指向包含了像素值的矩阵(可根据选择用于存储的方法采用任何维度存储数据)。矩阵头部的大小是恒定的。然而,矩阵本身的大小因图像的不同而不同,通常是较大的数量级。
OpenCV
中表示图像的数据结构是cv::Mat
,Mat
对象本质上是一个由数值组成的矩阵。- 矩阵的每一个元素代表一个像素,对于灰度图像,像素是由8位无符号数来表示(0代表黑,255代表白);
- 对于彩色图像,每个像素是一个三元向量,即由三个8位无符号数来表示三个颜色通道(Opencv中顺次为蓝、绿、红)。
我们先来介绍下cv::Mat
类的获取像素的成员函数at()
,其函数原型如下:
template<typename _Tp> _Tp& at(int i, int j);
//由于Mat可以存放任意数据类型的元素,所以该函数是用模板函数来实现的
//它本身不会进行任何数据类型转换,在调用的过程中需要指明像素的数据类型
//即要与矩阵中的数据类型相匹配。如:
img.at<uchar>(i,j)=255
img.at<cv::Vec3b>(i,j)[0]=255
以下所有的示例都是In-place变换操作。
数组遍历
在这里我们通过操作像素的办法来实现图像的镜像变换,即实现flip_array(img)的功能。代码如下:
#include <opencv2/highgui.hpp>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
void flip_array(Mat &img)
{
int rows = img.rows;
int cols = img.cols;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols/2; j++) {
uchar t;
if (img.channels() == 1) {
t = img.at<uchar>(i, j);
img.at<uchar>(i, j) = img.at<uchar>(i, cols- 1 - i);
img.at<uchar>(i, cols - i - 1) = t;
}else if(img.channels() == 3){
for (int k = 0; k < 3; k++) {
t = img.at<Vec3b>(i, j)[k];
img.at<Vec3b>(i, j)[k] = img.at<Vec3b>(i, cols - 1 -j )[k];
img.at<Vec3b>(i, cols - 1 - j)[k] = t;
}
}
}
}
}
//
int main() {
Mat img = imread("logo.jpeg");
if (!img.data)
{
cout << "读取原始图失败!" << endl;
return -1;
}
imshow("src", img);
flip_array(img);
imshow("later", img);
waitKey();
return 0;
}
- 效果图
指针遍历
OpenCV中cv::Mat类提供了成员函数ptr得到图像任意行的首地址。ptr函数是一个模板函数,其原型为:
template<typename _Tp> _Tp* Mat::ptr(int i=0)
在这里我们通过操作像素的办法来实现图像的水平反转,即实现flip_pointer(img)的功能。代码如下:
#include <opencv2/highgui.hpp>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
void flip_pointer(Mat &img)
{
int rows=img.rows;
int cols=img.cols*img.channels();
for(int i=0; i<rows/2; i++)
{
uchar *p=img.ptr<uchar>(i);
uchar *q=img.ptr<uchar>(rows-1-i);
uchar t;
for(int j=0; j<cols;j++)
{
t=*p;
*p++=*q;
*q++=t;
}
}
}
int main() {
Mat img = imread("logo.jpeg");
if (!img.data)
{
cout << "读取原始图失败!" << endl;
return -1;
}
imshow("src", img);
flip_array(img);
imshow("later", img);
waitKey();
return 0;
}
- 效果如图