OpenCv图像处理之Mat类使用

Opencv简介

opencv是一个非常优秀的图像处理工具库,底层由C++编写,故本教程的编程语言选择的是C++。
在生活中到处都是唯美的图像组成的一幅幅生动美丽的画面,但是这些画面经过计算机剖析之后,其实是一系列数字组成。比如下面的这幅图
在这里插入图片描述
在我们眼里,是一只非常可爱的小猫咪,但是在计算机眼里,它只是一些亮度不同的点而已,这副图片的大小是746 * 745,也就是一个746 * 745的2维矩阵,矩阵中的每一个元素表示这个位置上像素的亮度,像素值越大表示该点的亮度越亮。这些点的亮度其实就是rgb的值,一般的图像文件格式使用的是unsigned 8bits,即3维无符号8位数(uchar),故一个像素点为3维数组,分别对应rgb的值。但是需要注意的是,在opencv中3维数组存储的rgb值顺序并不是rgb,而是bgr。Mat矩阵对应的参数类型是CV_8UC1,CV_8UC2,CV_8UC3(C(n),n表示的是通道数,RGB3对应的参数类型就是CV_8UC3)

矩阵类cv::Mat

下面简单介绍了一下Mat类中某些关键的成员变量,详细的可以看源码

#include <iostream>
#include <opencv2/highgui.hpp>
#include <opencv2/imgcodecs.hpp>

using namespace std;
using namespace cv;

//Mat类副本
class MatTest {
public:
    //flags参数包含许多关于矩阵的信息,比如Mat标识,数据是否连接,深度,通道数目
    int flags;
    //矩阵维度,至少2维,1维为向量
    int dims;
    //矩阵的行列数,若为n维矩阵(n>2),那么rows=-1,cols=-1
    int rows, cols;
    //无符号字符串指针,指向数据(files,images..)
    uchar *data;
};
int main(){

	return 0;
}

下面来看一下源码中数据的类型

Matrix TypeType
CV_8Uuchar
CV_8Sschar
CV_16Uushort
CV_16Sshort
CV_32Sint
CV_32Ffloat
CV_64Fdouble

源码中封装了各种矩阵函数,这里简单介绍几种,顺便增加熟练度

#include <iostream>
#include <opencv2/highgui.hpp>
#include <opencv2/imgcodecs.hpp>
#include <d2d1.h>
#include <vector>

using namespace std;
using namespace cv;

int main() {
    //cv::Mat
    //默认构造函数
    Mat mat;
    //拷贝构造函数
    Mat mat1(const Mat &mat1);
    //指定行列范围的拷贝构造函数
    Mat mat2(const Mat &mat2, const Range &row, const Range &cols);
    //指定ROI的拷贝构造函数
    Mat mat3(const Mat &mat3, const Rect &roi);
    //使用多维数组中指定范围内的数据的拷贝构造函数
    Mat mat5(const Mat &mat5, Range *ranges);
    //指定类型和大小(行列)的2维数组(行在前,列在后)
    Mat mat6(int rows, int cols, int type);
    //有初始化值的置顶类型和大小的2维数组
    Mat mat7(int rows, int cols, int type, const Scalar &scalar);
    //指定大小和类型的2维数组
    Mat mat8(Size size, int type, const Scalar &scalar);
    //指定类型的多维数组
    Mat mat9(int ndims, const int *sizes, int type);
    //使用cv::Vec定义相同类型大小为n的1维向量
    Mat mat10(const Vec<T, n> &vec, bool copy_data = true);
    //使用cv::Matx定义相同类型大小为m*n的2维数组
    Mat mat11(const Matx<T, m, n> &vec, bool copy_data = true);
    //使用STL vector定义相同类型的1维数组
    Mat mat12(const vector<T> &vec, bool copy_data = true);
    //使用zeros()定义指定大小和类型的全零矩阵
    Mat::zeros(int rows,int cols,int type);
    //使用ones()定义指定大小和类型的全1矩阵
    Mat::ones(int rows,int cols,int type);
    return 0;
}

遍历图像,设置像素值

在图像处理中,设置像素值是很常见的事情,如何设置呢,通常是对图像中的全部像素进行遍历来设置

使用at(int x,int y)

#include <iostream>
#include <opencv2/highgui.hpp>
#include <opencv2/imgcodecs.hpp>
#include <d2d1.h>
#include <vector>

using namespace std;
using namespace cv;


int main() {
    //单通道灰度图
    Mat gray_image = cv::imread("D://cat.jpg", CV_8UC1);
    //rgb
    Mat rgb_image = cv::imread("D://cat.jpg");
    //遍历gray_image所有像素,设置像素值
    for (int i = 0; i < gray_image.rows; ++i) {
        for (int j = 0; j < gray_image.cols; ++j) {
            gray_image.at<uchar>(i, j) = (i + j) % 255;
        }
    }
    cv::imshow("gray_image", gray_image);
    //遍历rgb_image所有像素,设置像素值
    for (int i = 0; i < rgb_image.rows; ++i) {
        for (int j = 0; j < rgb_image.cols; ++j) {
        	//cv::Vec3b
            Vec3b pixel;
            //Blue
            pixel[0] = i % 255;
            //Green
            pixel[1] = j % 255;
            //Red
            pixel[2] = (i + j) % 255;
            rgb_image.at<Vec3b>(i, j) = pixel;
        }
    }
    cv::imshow("rgb_cat", rgb_image);
    cv::waitKey(0);
    return 0;
}

上述代码中Vec3b还可以写成cv::Vec<uchar,3> vec;定义一个uchar类型,长度为3的数组。opencv中封装好的类型如8U类型rgb彩色图像用的是<Vec3b>,float类型的矩阵使用<Vec3f>。对于Vec对象而言,可以使用[]符号像操作数据般读写Vec数据,如上述程序中的Vec3b pixel;对象>。
效果图
在这里插入图片描述
在这里插入图片描述
上述程序中多次用到了at<>(int x,int y);它是cv::mat的成员函数,at()可以用来存取图像中对应坐标为(x,y)的像素坐标,使用的时候要注意标明数据类型,比如单通道的灰度图可以写成img.at<uchar>(1,2) = 10;而三通道的彩色图则可以这样写img.at<Vec3b>(1,2)[0] = 10; img.at<Vec3b>(1,2)[1] = 20;img.at<Vec3b>(1,2)[2] = 30;这样是对三通道对应的像素进行了修改,opencv中对应的三原色的顺序是bgr,上面也提到过。

使用MatIterator_迭代器

#include <iostream>
#include <opencv2/highgui.hpp>
#include <vector>
#include <random>

using namespace std;
using namespace cv;

int main() {

    Mat rgb_img = imread("D:/cat.jpg");

    //定义迭代器对象
    MatIterator_<Vec3b> rgb_start, rgb_end;
    //随机数对象定义
    default_random_engine random;
    for (rgb_start = rgb_img.begin<Vec3b>(), rgb_end = rgb_img.end<Vec3b>();
         rgb_start != rgb_end; ++rgb_start) {
        //B-G-R
        (*rgb_start)[0] = random();
        (*rgb_start)[1] = random();
        (*rgb_start)[2] = random();
    }
    imshow("rgb_iter", rgb_img);
    waitKey(0);
    return 0;
}

选择指定区域

使用构造函数截取指定区域

#include <iostream>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <vector>

using namespace std;
using namespace cv;

int main() {

    Mat rgb_img = imread("D:/cat.jpg");
    //Rect(x,y,width,height)
    Mat roi(rgb_img, Rect(101, 201, 501, 500));
    imshow("roi_img", roi);
    waitKey(0);
    return 0;
}

效果显示
在这里插入图片描述

使用operator()运算符进行截取

#include <iostream>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <vector>

using namespace std;
using namespace cv;

int main() {

    Mat rgb_img = imread("D:/cat.jpg");
    //第一个Range()表示rowRange(代表高度,行是竖着)
    //第二个Range()表示colRange(代表宽度,列是横着)
    Mat roi = rgb_img(Range(100, 550), Range(100, 600));
    imshow("roi_img", roi);
    waitKey(0);
    return 0;
}

需要注意的是截取的范围是有界限的,若截取不当,则会报错

Assertion failed (0 <= roi.x && 0 <= roi.width && roi.x + roi.width <= m.cols && 0 <= roi.y && 0 <=
 roi.height && roi.y + roi.height <= m.rows) in Mat

效果显示
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值