0
点赞
收藏
分享

微信扫一扫

OpenCV + CPP 系列(三)图像矩阵创建、复制、像素访问,统计


文章目录

  • ​​一、创建图像​​
  • ​​Mat - 基本图像容器​​
  • ​​二、像素访问​​
  • ​​三、像素统计​​
  • ​​minMaxLoc​​
  • ​​meanStdDev​​

一、创建图像

Mat - 基本图像容器

关于 ​​Mat 图像容器​​ 详情,官网讲的非常清楚。

或者查看 ​​Mat函数文字​​

使用了矩阵创建函数: ​​Mat::ones()​​​, ​​Mat::zeros()​​​,​​Mat::eye​​​;
注意:Mat::ones()生成三通道矩阵时,只有第一个通道(蓝)全为1,其余两个通道为0;

若要全部赋值请使用 Scalar 模板类:
Scalar 功能:例如:Scalar(255, 255, 255) 对三个通道都赋值255。

若要对矩阵进行深拷贝可以使用 copyTo(), 或者 clone()。

头文件 ​​quick_opencv.h​​:用于声明类与公共函数

#pragma once
#include <opencv2\opencv.hpp>
using namespace cv;

class QuickDemo {
public:
void colorSpace_Demo(Mat& image);
void mat_create_Demo(Mat& image); // 新增方法:矩阵创建
};

源文件 ​​quick_demo.cpp​​:实现类与公共函数

#include <quick_opencv.h>


// 新增的方法实现
void QuickDemo::mat_create_Demo(Mat& image) {
Mat m1, m2;

m1 = Mat::ones(Size(4, 4), CV_8UC3);
m2 = Mat::zeros(Size(4, 4), CV_8UC3);

Mat m3 = Mat::zeros(Size(8, 8), CV_8UC1);
m2 = Scalar(255, 255, 255);
std::cout << "m1=\n" << m1 << std::endl;
std::cout << "m2=\n" << m2 << std::endl;

std::cout << m3 << std::endl;
std::cout << "m3.cols=" << m3.cols << "\t" << "m3.rows=" << m3.rows << std::endl;


Mat m00 = Mat::zeros(Size(240, 240), CV_8UC3);
Mat m4;
m00.copyTo(m4);
m4 = Scalar(0, 255, 255);

Mat m5 = m00.clone();
m5 = Scalar(255, 0, 0);
imshow("m00", m00);
imshow("m4", m4);
imshow("m5", m5);

Mat m10(4, 4, CV_32FC2, Scalar(1, 3));
std::cout << m10 << std::endl;
}

仍然在主函数调用该类的公共成员函数

#include <opencv2\opencv.hpp>
#include <quick_opencv.h>
#include <iostream>
using namespace cv;

int main(int argc, char** argv) {
Mat src = imread("D:\\Desktop\\pandas.jpg");
if (src.empty()) {
printf("Could not load images...\n");
return -1;
}
//namedWindow("input", WINDOW_AUTOSIZE);
//imshow("input", src);

QuickDemo qk; //实例化
//qk.colorSpace_Demo(src); //调用

qk.mat_create_Demo(src);
waitKey(0);
destroyAllWindows();
return 0;
}

OpenCV + CPP 系列(三)图像矩阵创建、复制、像素访问,统计_#include

二、像素访问

关于 ​​Mat 像素访问​​​ 详情,官网讲的非常清楚。
主要讲解像素访问:

cv::Mat有个at()方法,可以访问图像的单个像素,同时at()方法又是一个模板方法,所以在使用的时候需要传入图像像素的类型,而且这个类型不像C++中的运算类型一样可以自动转换,所以必须准确的传入图像元素类型。

对于单通道元素来说,元素类型为unsigned char的情况下,可以这样访问

image.at<uchar>(h, w)= value;

对于三通道元素彩色图像来说,那么可以这样;或者直接使用数组赋值

image.at<cv::Vec3b>(h, w)[channel]= value;
image.at<cv::Vec3b>(h, w) = cv::Vec3b(a, b, c);

指针访问:

uchar *data = image.ptr<uchar>(h);

关于Vec3b 以及相似的数据类型定义:

typedef Vec<uchar, 2> Vec2b;
typedef Vec<uchar, 3> Vec3b;
typedef Vec<uchar, 4> Vec4b;

typedef Vec<short, 2> Vec2s;
typedef Vec<short, 3> Vec3s;
typedef Vec<short, 4> Vec4s;

typedef Vec<ushort, 2> Vec2w;
typedef Vec<ushort, 3> Vec3w;
typedef Vec<ushort, 4> Vec4w;

typedef Vec<int, 2> Vec2i;
typedef Vec<int, 3> Vec3i;
typedef Vec<int, 4> Vec4i;
typedef Vec<int, 6> Vec6i;
typedef Vec<int, 8> Vec8i;

typedef Vec<float, 2> Vec2f;
typedef Vec<float, 3> Vec3f;
typedef Vec<float, 4> Vec4f;
typedef Vec<float, 6> Vec6f;

typedef Vec<double, 2> Vec2d;
typedef Vec<double, 3> Vec3d;
typedef Vec<double, 4> Vec4d;
typedef Vec<double, 6> Vec6d;

头文件 ​​quick_opencv.h​​:用于声明类与公共函数

#pragma once
#include <opencv2\opencv.hpp>
using namespace cv;

class QuickDemo {
public:
void pixel_visit_Demo(Mat& image);
void pixel_visiter_Demo(Mat& image);
void pixel_statistic_Demo(Mat& image);
};

主函数调用该类的公共成员函数

#include <opencv2\opencv.hpp>
#include <quick_opencv.h>
#include <iostream>
using namespace cv;

int main(int argc, char** argv) {
Mat src = imread("D:\\Desktop\\pandas.jpg");
if (src.empty()) {
printf("Could not load images...\n");
return -1;
}
//namedWindow("input", WINDOW_AUTOSIZE);
//imshow("input", src);

QuickDemo qk; //实例化
//qk.colorSpace_Demo(src); //调用
//qk.mat_create_Demo(src);
//qk.pixel_visit_Demo(src);
qk.pixel_visiter_Demo(src);
waitKey(0);
destroyAllWindows();
return 0;
}

源文件 ​​quick_demo.cpp​​:实现类与公共函数

#include <quick_opencv.h>


// 新增的方法实现
// 通过下标访问像素
void QuickDemo::pixel_visit_Demo(Mat& image) {
int width = image.cols;
int height = image.rows;
int channel = image.channels();
for (int h = 0; h < height; h++) {
for (int w = 0; w < width; w++) {
// gray image
if (channel == 1) {
int px = image.at<uchar>(h, w);
image.at<uchar>(h, w) = 255 - px;
}
// 3 channel image
if (channel == 3) {
Vec3b bgr = image.at<Vec3b>(h, w);
image.at<Vec3b>(h, w)[0] = 255 - bgr[0];
image.at<Vec3b>(h, w)[1] = 255 - bgr[1];
image.at<Vec3b>(h, w)[2] = 255 - bgr[2];
};
}
}
imshow("image反色",image);
}

// 通过指针访问像素
void QuickDemo::pixel_visiter_Demo(Mat& image) {
int width = image.cols;
int height = image.rows;
int channel = image.channels();
if (channel == 1) {
for (int h = 0; h < height; h++) {
uchar* current_row = image.ptr<uchar>(h);
for (int w = 0; w < width; w++) {
int px = *current_row;
*current_row++ = 255 - px;
}
}
}
if (channel == 3) {
for (int h = 0; h < height; h++) {
uchar* current_row = image.ptr<uchar>(h);
for (int w = 0; w < width; w++) {
*current_row++ = 255 - *current_row;
*current_row++ = 255 - *current_row;
*current_row++ = 255 - *current_row;
}
}
}
imshow("image反色", image);
}

OpenCV + CPP 系列(三)图像矩阵创建、复制、像素访问,统计_#include_02

关于像素访问速度比较1:​​javascript:void(0)​​​ 关于像素访问速度比较2:​​javascript:void(0)​​ 多通道图:​​javascript:void(0)​​ 将整张图首地址遍历:​​javascript:void(0)​​

在图像数据的运算中,使用指针 *p++ 与 位运算符 算是快的,最好是使用Mat自带重载符进行像素整块操作。 在这方面与python的矩阵操作思想类似,python中关于数据运算,几乎全部使用numpy,不写for循环遍历的。

三、像素统计

minMaxLoc

在图像中(矩阵/数组)中找到全局最小和最大值

void minMaxLoc(InputArray src, CV_OUT double* minVal,
CV_OUT double* maxVal = 0, CV_OUT Point* minLoc = 0,
CV_OUT Point* maxLoc = 0, InputArray mask = noArray());

  • src,输入图像,单通道图像。
  • minVal,返回最小值的指针。若无需返回,此值设为 NULL。
  • maxVal,返回最大值的指针。若无需返回,此值设为 NULL。
  • minLoc,返回最小值位置的指针(二维情况下)。若无需返回,此值设为 NULL。
  • maxVal,返回最大值位置的指针(二维情况下)。若无需返回,此值设为 NULL。
  • mask,可选的掩膜操作,非零掩码元素用于标记待统计元素,需要与输入图像集有相同尺寸。

meanStdDev

void meanStdDev(InputArray src, OutputArray mean, OutputArray stddev,
InputArray mask=noArray());

  • InputArray src 一般的彩色图,灰度图都可
  • mean:输出参数,计算均值
  • stddev:输出参数,计算标准差
  • mask:可选参数

void QuickDemo::pixel_statistic_Demo(Mat& image) {
double min_v, max_v;
Point minLoc, maxLoc;
std::vector<Mat> mv;
split(image, mv);
for (int i = 0; i < mv.size(); i++) {
minMaxLoc(mv[i], &min_v, &max_v, &minLoc, &maxLoc, Mat());
std::cout << "No.channel:" << i << "\tmin_value=" << min_v << "\tmax_value=" << max_v << std::endl;
std::cout << "No.channel:" << i << "\tminLoc.x=" << minLoc.x << "\tmaxLoc.y=" << minLoc.y << std::endl;
}
Mat mean, stddev;
meanStdDev(image, mean, stddev);
std::cout << "mean=" << mean.at<double>(0) <<"\t"<< mean.at<double>(1) << "\t" << mean.at<double>(2) << std::endl;
std::cout << "stddev=" << stddev.at<double>(0) << "\t" << stddev.at<double>(1) << "\t" << stddev.at<double>(2) << std::endl;
}

OpenCV + CPP 系列(三)图像矩阵创建、复制、像素访问,统计_#include_03


举报

相关推荐

0 条评论