通道合并与分离
cpp
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat src = imread("D:\\souse\\opencv_tutorial_data-master\\images\\WindowsLogo.jpg");
if (src.empty()) {
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
vector<Mat> mv;
//分离
split(src, mv);
imshow("input1", mv.at(0));
imshow("input2", mv.at(1));
imshow("input3", mv.at(2));
Mat des;
mv.at(0) = Scalar(0);
//合并操作
merge(mv, des);
imshow("des",des);
waitKey(0);
std::cout << "Hello World!\n";
return 0;
}
图像直方图统计

Bin:是直方图的基本统计单元,用于统计图像中特定范围内像素值的出现频率。
calcHist
cpp
CV_EXPORTS void calcHist( const Mat* images, int nimages,
const int* channels,
InputArray mask,
OutputArray hist, int dims,
const int* histSize,
const float** ranges,
bool uniform = true,
bool accumulate = false );
函数cv::calcHist
用于计算一个或多个数组的直方图。用于增加直方图 bin 的元组元素取自相应输入数组中相同位置的元素。下面的示例展示了如何为彩色图像计算二维色调 - 饱和度直方图:
@include snippets/imgproc_calcHist.cpp
@param images 源数组。它们都应该具有相同的深度,即CV_8U、CV_16U或CV_32F ,并且大小相同。每个数组可以有任意数量的通道。
@param nimages 源图像的数量。
@param channels 用于计算直方图的维度通道列表。第一个数组的通道从0到images[0].channels() - 1编号,第二个数组的通道从images[0].channels()到images[0].channels() + images[1].channels() - 1编号,依此类推。
@param mask 可选掩码。如果该矩阵不为空,它必须是与images[i]大小相同的8位数组。非零掩码元素标记在直方图中统计的数组元素。
@param hist 输出直方图,它是一个密集或稀疏的dims维数组。
@param dims 直方图维度,必须为正且不大于CV_MAX_DIMS(在当前OpenCV版本中等于32)。
@param histSize 每个维度的直方图大小数组。
@param ranges 每个维度的直方图 bin 边界的dims个数组的数组。
@param uniform 指示直方图是否均匀的标志。
@param accumulate 累加标志。如果设置了该标志,在分配直方图时,开始时不会将其清空。此功能使您能够从几组数组中计算单个直方图,或者及时更新直方图。
normalize
cv::normalize()
是 OpenCV 中用于归一化数组元素的函数,它可以将数组的值缩放到指定范围。以下是对该函数的详细解析:
cpp
void cv::normalize(
InputArray src, // 输入数组(如Mat)
InputOutputArray dst, // 输出数组(可与src相同,实现原地操作)
double alpha = 1, // 归一化后的最小值(或范数值,取决于norm_type)
double beta = 0, // 归一化后的最大值(仅用于NORM_MINMAX)
int norm_type = NORM_L2, // 归一化类型(如NORM_MINMAX、NORM_L1、NORM_L2等)
int dtype = -1, // 输出数组的类型(-1表示与输入相同)
InputArray mask = noArray() // 可选掩码,非零元素参与计算
);
参数详解
src 输入数组(如直方图数据 b),通常是 Mat 类型。
dst 输出数组,可与 src 相同(原地操作)。若不同,需保证尺寸和通道数一致。
alpha 对于 NORM_MINMAX:归一化后的最小值。
对于其他归一化类型(如 NORM_L2):目标范数值。
beta 仅用于 NORM_MINMAX,表示归一化后的最大值。
norm_type 常用取值:
NORM_MINMAX:线性映射到 [alpha, beta] 范围。
NORM_L1:L1 范数(绝对值之和)归一化。
NORM_L2:L2 范数(欧几里得距离)归一化。
NORM_INF:无穷范数(最大值)归一化。
dtype
输出数组的类型。-1 表示与输入类型相同。
mask
可选掩码,仅掩码中非零元素参与计算。
cpp
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat src = imread("D:\\souse\\opencv_tutorial_data-master\\images\\sp_noise.png");
if (src.empty()) {
cout << "读取失败"<<endl;
return -1;
}
namedWindow("src", WINDOW_AUTOSIZE);
imshow("src", src);
//分离通道
vector<Mat> mv;
split(src, mv);
//计算直方图
int histSize=256;
float range[] = { 0,255 };
const float* hisRanges = range;
Mat b, g, r;
//原图像 原图像数量 通道 掩码 输出 维度 每个维度的bin数量 每个维度的取值范围 bin是否均匀分布 是否累积计算
calcHist(&mv[0],1,0,Mat(),b,1,&histSize, &hisRanges);
calcHist(&mv[1], 1, 0, Mat(), g, 1, &histSize, &hisRanges);
calcHist(&mv[2], 1, 0, Mat(), r, 1, &histSize, &hisRanges);
//绘制直方图
Mat result= Mat::zeros(Size(600, 500), CV_8UC3);
int margin = 50;//边缘大小
int h = result.rows-2*margin;//最大高
normalize(b, b, 0, h, NORM_MINMAX, -1, Mat());
normalize(g, g, 0, h, NORM_MINMAX, -1, Mat());
normalize(r, r, 0, h, NORM_MINMAX, -1, Mat());
float step = 500.0 / 256;
for (int i = 0; i < 255; i++) {
// 绘制蓝色通道
line(result,
Point(step * i+50, 50 + h - b.at<float>(i, 0)),
Point(step * (i + 1)+50, 50 + h - b.at<float>(i + 1, 0)),
Scalar(255, 0, 0), 2, 8, 0);
// 修复:添加绿色和红色通道的绘制(颜色参数修正)
line(result,
Point(step * i+50, 50 + h - g.at<float>(i, 0)),
Point(step * (i + 1)+50, 50 + h - g.at<float>(i + 1, 0)),
Scalar(0, 255, 0), 2, 8, 0); // 绿色:(0,255,0)
line(result,
Point(step * i+50, 50 + h - r.at<float>(i, 0)),
Point(step * (i + 1)+50, 50 + h - r.at<float>(i + 1, 0)),
Scalar(0, 0, 255), 2, 8, 0); // 红色:(0,0,255)
}
imshow("result", result);
waitKey(0);
}

图像直方图均衡化

cpp
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat src = imread("D:\\souse\\opencv_tutorial_data-master\\images\\age_gender.jpg");
if (src.empty()) {
cout << "读取失败" << endl;
return -1;
}
namedWindow("src", WINDOW_AUTOSIZE);
imshow("src", src);
//=========================//
//转灰度图像
Mat gray, des;
cvtColor(src, gray, COLOR_BGR2GRAY);
imshow("gray", gray);
//均衡化
equalizeHist(gray, des);
imshow("des", des);
//=========================//
//分离通道
vector<Mat> mv;
split(src, mv);
//计算直方图
int histSize = 256;
float range[] = { 0,255 };
const float* hisRanges = range;
Mat b, g, r,g_z,d_z;
//原图像 原图像数量 通道 掩码 输出 维度 每个维度的bin数量 每个维度的取值范围 bin是否均匀分布 是否累积计算
calcHist(&mv[0], 1, 0, Mat(), b, 1, &histSize, &hisRanges);
calcHist(&mv[1], 1, 0, Mat(), g, 1, &histSize, &hisRanges);
calcHist(&mv[2], 1, 0, Mat(), r, 1, &histSize, &hisRanges);
calcHist(&gray, 1, 0, Mat(), g_z, 1, &histSize, &hisRanges);
calcHist(&des, 1, 0, Mat(), d_z, 1, &histSize, &hisRanges);
//绘制直方图
Mat result = Mat::zeros(Size(600, 500), CV_8UC3);
Mat result1 = Mat::zeros(Size(600, 500), CV_8UC3);
int margin = 50;//边缘大小
int h = result.rows - 2 * margin;//最大高
normalize(b, b, 0, h, NORM_MINMAX, -1, Mat());
normalize(g, g, 0, h, NORM_MINMAX, -1, Mat());
normalize(r, r, 0, h, NORM_MINMAX, -1, Mat());
normalize(g_z, g_z, 0, h, NORM_MINMAX, -1, Mat());
normalize(d_z, d_z, 0, h, NORM_MINMAX, -1, Mat());
float step = 500.0 / 256;
for (int i = 0; i < 255; i++) {
// 绘制蓝色通道
line(result,
Point(step * i + 50, 50 + h - b.at<float>(i, 0)),
Point(step * (i + 1) + 50, 50 + h - b.at<float>(i + 1, 0)),
Scalar(255, 0, 0), 2, 8, 0);
// 修复:添加绿色和红色通道的绘制(颜色参数修正)
line(result,
Point(step * i + 50, 50 + h - g.at<float>(i, 0)),
Point(step * (i + 1) + 50, 50 + h - g.at<float>(i + 1, 0)),
Scalar(0, 255, 0), 2, 8, 0); // 绿色:(0,255,0)
line(result,
Point(step * i + 50, 50 + h - r.at<float>(i, 0)),
Point(step * (i + 1) + 50, 50 + h - r.at<float>(i + 1, 0)),
Scalar(0, 0, 255), 2, 8, 0); // 红色:(0,0,255)
line(result1,
Point(step * i + 50, 50 + h - g_z.at<float>(i, 0)),
Point(step * (i + 1) + 50, 50 + h - g_z.at<float>(i + 1, 0)),
Scalar(0, 0, 255), 2, 8, 0); // 红色:(0,0,255)
line(result1,
Point(step * i + 50, 50 + h - d_z.at<float>(i, 0)),
Point(step * (i + 1) + 50, 50 + h - d_z.at<float>(i + 1, 0)),
Scalar(0, 255, 0), 2, 8, 0); // 红色:(0,0,255)
}
imshow("result", result);
imshow("result1", result1);
waitKey(0);
}
绿色是灰度图,红色是均衡化处理之后的