1.图像矩阵在内存中的储存方式
我们可以在OpenCV文档中找到图像在内存中的储存方式。矩阵的大小取决于所使用的颜色系统。更准确地说,它取决于使用的通道数量。在灰度图像的情况下,我们有类似的东西:
对于多通道图像,列包含与通道数一样多的子列。例如在 BGR 颜色系统的情况下:
因为在许多情况下,内存足够大,可以以连续的方式存储行,这些行可能会一个接一个地跟随,从而创建一个长行。因为所有东西都在一个地方一个接一个地放在一个地方,这可能有助于加快扫描过程。
我们同时可以得到如下结论:在我们访问像素时,包含灰度图像的cv::Mat返回的是一个值,而彩色图像每个像素对应三个通道,因此包含彩色图像的cv::Mat类会返回一个向量
2.访问像素
利用cv::Mat类中的at(int y,int x)可以访问元素,其中y是行号,x是列号。使用该类需要指定返回值的预期类型(指定类型必须与矩阵内类型一致)。对于彩色图像返回的短向量类型,OpenCV定义了cv::Vec3b,我们可以利用它访问某个像素的某个通道值,也可以同时访问三个通道值。
int i, j;
image.at<uchar>(j,i) = 255;//访问灰度图像像素
image.at<cv::Vec3b>(j, i)[0] = 255;//访问彩色图像像素的通道B
image.at<cv::Vec3b>(j, i) = cv::Vec3b(255, 255, 255);//访问彩色图像像素的三个通道
如果我们已经知道矩阵的类型,可以使用cv::Mat类的模板子类cv::Mat_类,以避免代码冗长。
//使用Mat模板操作图像
cv::Mat_<uchar>img(image);
img(50, 100) = 0;//访问第50行第100列的值
3.应用:为图像加入椒盐噪声
#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>
#include <random>
using namespace std;
using namespace cv;
void salt(cv::Mat image, int n) {
//C++随机数生成器
std::default_random_engine generator;
std::uniform_int_distribution<int>
randomRow(0, image.rows - 1);
std::uniform_int_distribution<int>
randomCol(0, image.cols - 1);
int i, j;
for (int k = 0; k < n; k++) {
//随机生成图形位置
i = randomCol(generator);
j = randomRow(generator);
if (image.type() == CV_8UC1) {//灰度图像
//单通道8位图像
image.at<uchar>(j, i) = 255;
}
else if (image.type()==CV_8UC3)//彩色图像
{
//3通道图像
image.at<cv::Vec3b>(j, i) = cv::Vec3b(255, 255, 255);
}
}
}
int main() {
cv::Mat image = cv::imread("1.bmp");
salt(image, 3000);
cv::namedWindow("Image");
cv::imshow("Image", image);
cv::waitKey(0);
return 0;
}