文章目录
- 一、创建图像
- 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;
}
二、像素访问
关于 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);
}
关于像素访问速度比较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;
}