OpenCV笔记之几种遍历图像操作

By AverageJoeWang
 标签:

Mat本质上是由两个数据部分组成的类: (包含信息有矩阵的大小,用于存储的方法,矩阵存储的地址等) 的矩阵头和一个指针,指向包含了像素值的矩阵(可根据选择用于存储的方法采用任何维度存储数据)。矩阵头部的大小是恒定的。然而,矩阵本身的大小因图像的不同而不同,通常是较大的数量级。

  • OpenCV中表示图像的数据结构是cv::MatMat对象本质上是一个由数值组成的矩阵。
  • 矩阵的每一个元素代表一个像素,对于灰度图像,像素是由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;
    }
  • 效果如图