一、函数
a.resize
函数:
(1)函数原型:
CV_EXPORTS_W void resize( InputArray src, OutputArray dst, Size dsize,
double fx = 0, double fy = 0, int interpolation = INTER_LINEAR );
(2)函数作用:
resize
函数用于放大或缩小图像src
到指定的大小。
(3) 目标图像 (dst
):
- 目标图像
dst
的类型和大小与源图像src
相同,除非明确指定了dsize
。
(4)缩放方式:
- 如果目标图像
dst
已经创建,可以通过设置dsize=dst.size()
并计算fx
和fy
来缩放图像。 - 如果想要按每个方向2倍的因子对图像进行降采样,可以指定
fx
和fy
并让函数计算目标图像的大小。
(5)缩放效果:
- 缩小图像时,通常使用
INTER_AREA
插值方法效果最佳。 - 放大图像时,通常使用
INTER_CUBIC
(速度慢)或INTER_LINEAR
(速度较快,效果也还不错)插值方法。
(6)参数说明:
src
:输入图像。dst
:输出图像,其大小和类型由src
、dsize
、fx
和fy
确定。dsize
:输出图像的大小。如果为零(Python 中为None
),则根据src.size()
、fx
和fy
计算。fx
:水平轴上的缩放因子。如果为0,则根据dsize.width/src.cols
计算。fy
:垂直轴上的缩放因子。如果为0,则根据dsize.height/src.rows
计算。interpolation
:插值方法,见InterpolationFlags
。
(7) 插值方法 (interpolation
):
- 定义了在缩放过程中如何处理像素的插值。不同的插值方法在速度和质量上有所不同。
(8) 相关函数:
warpAffine
:仿射变换。warpPerspective
:透视变换。remap
:根据给定的映射关系重新绘制图像。
b. split
函数:
(1)函数原型:
CV_EXPORTS void split(const Mat& src, Mat* mvbegin);
(2)函数作用:
split
函数将一个多通道数组分割成独立的单通道数组。
(3)分割公式:
- 分割操作的数学表达式为:
,其中 mv 是分割后的数组,c 是通道索引,I 是像素索引。
(4)使用场景:
- 当需要单独处理图像的每个通道时,可以使用
split
函数将多通道图像(如 RGB 图像)分割成三个单通道图像。
(5)参数说明:
src
:输入的多通道数组。mvbegin
:输出数组,其数量必须与src.channels()
相匹配,即源数组的通道数。输出数组在需要时会重新分配。
(6)相关函数:
merge
:与split
功能相反,它将多个单通道数组合并为一个多通道数组。mixChannels
:用于更复杂的通道排列或提取单个通道。cvtColor
:用于颜色空间转换,可能会改变图像的通道数。
(7)函数行为:
split
函数会根据源数组src
的通道数,将其分割成相应数量的单通道数组,并将这些数组存储在mvbegin
指向的数组中。
c. calcHist
函数:
(1)函数原型:
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 );
(2)函数作用:
calcHist
函数计算一个或多个数组的直方图。用于直方图的元素值是从相应输入数组中相同位置取出的。
(3)参数说明:
images
:源数组列表,它们必须具有相同的数据深度(CV_8U
、CV_16U
或CV_32F
)和大小,并且可以有任意数量的通道。nimages
:源数组的数量。channels
:用于计算直方图的通道列表。数组的通道从0开始编号,第二个数组的通道编号从第一个数组的通道数开始,以此类推。mask
:可选的掩码。如果提供,掩码必须是8位数组,与images[i]
大小相同。非零掩码元素标记了要计入直方图的数组元素。hist
:输出直方图,可以是密集或稀疏的dims
维数组。dims
:直方图的维度,必须是正数,并且不超过CV_MAX_DIMS
(当前 OpenCV 版本中等于32)。histSize
:每个维度的直方图大小数组。ranges
:每个维度的直方图 bin 边界数组。对于均匀直方图,每个维度i
只需要指定第0个直方图 bin 的下界L_0
(包含)和最后一个直方图 binhistSize[i]-1
的上界U
(不包含)。对于非均匀直方图,每个ranges[i]
包含histSize[i]+1
个元素。uniform
:标志,指示直方图是否均匀。accumulate
:累积标志。如果设置,当分配直方图时,它不会在开始时被清空。这允许你从多组数组计算一个单一的直方图,或者随时间更新直方图。
(4)直方图类型:
- 直方图可以是均匀分布的,也可以是非均匀分布的。均匀直方图在每个维度上使用相同的 bin 大小,而非均匀直方图允许每个 bin 具有不同的大小。
(5) 累积模式:
- 如果
accumulate
参数设置为true
,则可以在多次调用中累积直方图,这对于实时更新直方图很有用。
(6) 多维直方图:
calcHist
可以计算多维直方图,dims
参数指定直方图的维度数量。
(7) 应用场景:
- 该函数通常用于图像处理中的直方图分析,如颜色分布分析、直方图均衡化等。
d. normalize
函数:
(1)函数原型:
CV_EXPORTS_W void normalize( InputArray src, InputOutputArray dst, double alpha = 1,
double beta = 0, int norm_type = NORM_L2, int dtype = -1, InputArray mask = noArray());
(2)函数作用:
normalize
函数对输入数组src
的元素进行缩放和平移,以满足特定的范数或值范围条件。
(3)归一化条件:
- 当
normType
是NORM_INF
、NORM_L1
或NORM_L2
时,归一化后的数组的 Lp 范数等于alpha
。 - 当
normType
是NORM_MINMAX
时,归一化后的数组的最小值等于alpha
,最大值等于beta
。
(4)掩码操作:
- 可选的
mask
参数指定了要归一化的子数组。这意味着范数或最小-最大值是在子数组上计算的,然后这个子数组被修改为归一化的形式。
(5)稀疏矩阵处理:
- 对于稀疏矩阵,只有非零值被分析和转换。因此,不允许对稀疏矩阵进行范围变换,因为它可能会改变零点的位置。
(6)参数说明:
src
:输入数组。dst
:输出数组,其大小与src
相同。alpha
:归一化后数组的范数值,或在范围归一化时的下界。beta
:在范围归一化时的上界,对于范数归一化不使用。norm_type
:归一化类型,见cv::NormTypes
。dtype
:当为负数时,输出数组的类型与src
相同;否则,输出数组具有与src
相同数量的通道,数据深度为CV_MAT_DEPTH(dtype)
。mask
:可选的操作掩码。
(7) 相关函数:
norm
:计算数组的范数。Mat::convertTo
:将矩阵转换为不同的数据类型和归一化。SparseMat::convertTo
:稀疏矩阵的转换函数。
二、代码示例
#include <opencv2/core/utils/logger.hpp>
#include <opencv2/opencv.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/objdetect.hpp>
#include <opencv2/highgui/highgui_c.h>
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
utils::logging::setLogLevel(utils::logging::LOG_LEVEL_SILENT);
VideoCapture cap; // 定义主函数
cap.open(0);// 尝试打开摄像头,0是默认的摄像头设备索引
double scale = 0.5;// 定义缩放比例
while (1) // 进入无限循环,不断读取视频帧
{
Mat SrcImg;// 定义Mat对象用于存储原始图像
cap >> SrcImg;// 从摄像头捕获一帧图像到SrcImg
Size ResImgSiz = Size(SrcImg.cols*scale, SrcImg.rows*scale); // 根据缩放比例计算新的图像尺寸0.5
Mat matSrc = Mat(ResImgSiz, SrcImg.type());// 创建一个新的Mat对象用于存储缩放后的图像
//resize(srcMat,matSrc,ResImgsiz,INTER_LINEAR);INTER_LINEAR 函数插值方法
resize(SrcImg, matSrc, ResImgSiz, INTER_LINEAR);// 执行图像缩放操作
//双线性插值:一种在离散数据点之间进行插值的方法,通过使用四个最近的数据点来估计新点的值。
Mat matRGB[3];// 创建三个Mat对象用于存储RGB三个颜色通道
split(matSrc, matRGB); // 将缩放后的图像按照颜色通道分割
int Channels[] = { 0 }; // 定义一个数组,指定我们关心的颜色通道(这里是蓝色通道)
int nHistSize[] = { 256 };// 定义直方图的大小(0-255)
float range[] = { 0, 255 };// 定义直方图的范围
const float *fHistRanges[] = { range };// 将范围数组转换为const float* 类型,以满足calcHist函数的要求
Mat histR, histG, histB;// 分别定义三个Mat对象用于存储R、G、B三个颜色通道的直方图
// 计算每个颜色通道的一维直方图
calcHist(&matRGB[0], 1, Channels, Mat(), histB, 1, nHistSize, fHistRanges, true, false);
calcHist(&matRGB[1], 1, Channels, Mat(), histG, 1, nHistSize, fHistRanges, true, false);
calcHist(&matRGB[2], 1, Channels, Mat(), histR, 1, nHistSize, fHistRanges, true, false);
// 创建直方图画布,初始化为白色
int nHistWidth = 400;
int nHistHeight = 300;
int nBinWidth = cvRound((double)nHistWidth / nHistSize[0]);
Mat matHistImage(nHistHeight, nHistWidth, CV_8UC3, Scalar(255, 255, 255)); // 计算每个直方图柱子的宽度
// 归一化直方图,使其在图像中垂直方向上正确显示
normalize(histB, histB, 0.0, matHistImage.rows, NORM_MINMAX, -1, Mat());
normalize(histG, histG, 0.0, matHistImage.rows, NORM_MINMAX, -1, Mat());
normalize(histR, histR, 0.0, matHistImage.rows, NORM_MINMAX, -1, Mat());
// 在直方图画布上绘制三个颜色通道的直方图
for (int i = 1; i < nHistSize[0]; i++)
{
// 绘制蓝色通道直方图的一根柱子
line(matHistImage, // 目标图像,在其上绘制直线
Point(nBinWidth * (i - 1), nHistHeight - cvRound(histB.at<float>(i - 1))), // 柱子的起始点(上一柱子的顶部)
Point(nBinWidth * (i), nHistHeight - cvRound(histB.at<float>(i))), // 柱子的结束点(当前柱子的顶部)
Scalar(255, 0, 0), // 蓝色通道使用红色线条绘制(在BGR颜色空间中,红色对应蓝色通道)
2, // 线宽,这里是2个像素
8, // 线型,这里是8,表示抗锯齿线
0); // 绘制线尾的类型,这里是0,表示不绘制线尾
// 绘制绿色通道直方图的一根柱子
line(matHistImage, // 目标图像
Point(nBinWidth * (i - 1), nHistHeight - cvRound(histG.at<float>(i - 1))), // 绿色柱子的起始点
Point(nBinWidth * (i), nHistHeight - cvRound(histG.at<float>(i))), // 绿色柱子的结束点
Scalar(0, 255, 0), // 绿色通道使用绿色线条绘制
2, // 线宽
8, // 线型
0); // 线尾类型
// 绘制红色通道直方图的一根柱子
line(matHistImage, // 目标图像
Point(nBinWidth * (i - 1), nHistHeight - cvRound(histR.at<float>(i - 1))), // 红色柱子的起始点
Point(nBinWidth * (i), nHistHeight - cvRound(histR.at<float>(i))), // 红色柱子的结束点
Scalar(0, 0, 255), // 红色通道使用蓝色线条绘制(在BGR颜色空间中,蓝色对应红色通道)
2, // 线宽
8, // 线型
0); // 线尾类型
}
// 显示直方图
/*imshow("frame", matSrc);
imshow("histR", histR);
imshow("histG", histG);
imshow("histB", histB);*/
imshow("三色直方图", matHistImage);
if (waitKey(30) == 'q') {
break;
}
}
destroyAllWindows();
return 0;
}