1、图像的加载、修改与保存
1.1 imread函数
- 读取(加载)
对于图像的读取,使用imread()函数
来进行读取,
Mat imread( const String& filename, int flags )
第一个参数 filename: 表示图像的路径。
第二个参数 flags:表示读取图像的方式。
IMREAD_UNCHANGED = -1,读取原图,默认原图读取
IMREAD_GRAYSCALE = 0,以灰度图方式读取
IMREAD_COLOR = 1,以RGB方式读取原图
1.2 imshow函数
imshow通常用来显示图像,函数如下
void imshow(const String& winname, InputArray mat);
//参数1 : winname表示窗口名称
//参数2 : mat表示输入的mat图像
一般来说,imshow可以搭配namedWindow()函数
一起使用
有时候,用imshow打开的图片的大小窗口非常大,是按图片的原始比例显示的,所以namedWindow()可以选择多种方式打开并显示图片
#include <opencv2/opencv.hpp>
using namespace cv;
int main()
{
Mat img=imread("图片路径");
nameWindow("原图",WINDOW_FREERATIO);//窗口大小自适应比例
imshow("原图",img); //这里的字符串 "原图",就是namedWindow所定义的窗口
waitKey(0); //等待时间,如果参数是0,那么一直阻塞,ms为单位
destroyAllWindows() ;//执行到这里时候,对所有的窗口都销毁
}
第二个参数,标志参数,代表要创建的窗口的属性
标志参数 | 作用 |
---|---|
WINDOW_NORMAL | 显示图像后,允许用户随意调整窗口大小 |
WINDOW_AUTOSIZE | 根据图像大小显示窗口,不允许用户调整大小 |
WINDOW_FREERATIO | 窗口大小自适应比例 |
WINDOW_KEEPRATIO | 保持图像的比例 |
1.3 cvtColor函数
图像颜色转换,各种类型之间相互转换函数
void cvtColor(InputArray src,outputArray dst,int code,int dstCn=0);
//第一个参数为输入图像;
//第二个参数为输出图像;
//第三个参数为颜色空间转换的标识符(具体见表);;
//第四个参数为目标图像的通道数,若该参数是0,表示目标图像取源图像的通道数。
1.4 imwrite函数
bool cv::imwrite(const String & filename,InputArray img,const std::vector<int> & params = std::vector<int>() )
参数:
- filename:需要保存图像的文件名,要保存图片为哪种格式,就带什么后缀。
- img:要保存的图像。
- params:表示为特定格式保存的参数编码。
2、矩阵的掩膜操作
- 什么是图像掩膜操作,掩膜操作实现的是图像对比度调整
opencv提供的掩膜操作(对比度提高)API:filter2D
定义掩膜矩阵:
Mat kernel = (Mat_<char>(3,3)<< 0,-1,0,-1,5,-1,0,-1,0);
API调用举例:filter2D(img, dst, img.depth(), kernel);
说明:第一个参数是操作对象名,第二个参数保存操作后对象名,第三个参数图像深度(使用depth()函数获取了原图像深度),第三个参数是掩膜方法(对应掩膜矩阵)
如何初始化一个零时Mat对象用于存储原图像?
3、Mat对象
Mat对象构造函数
Mat()
Mat(int rows, int cols, int type)
Mat(Size size, int type)
Mat(int rows, int cols, int type, const Scaler &s)
// 说明:前两个参数分别表示行和列,第三个参数是类型参数
//(比如CV_8UC3中8表示每个通道占8位,U表示无符号,C表示Char类型,3表示三个通道数),第四个参数是向量表示初始化每个像素值为多少,向量长度对应通道数目一致。
Mat(Size size, int type, const Scaler &s) //Scaler()用来给像素赋值
Mat(int ndims, const int *sizes, int type)
Mat(int ndims, const int *sizes, int type, const Scaler &s)
OpenCv里的拷贝构造函数其实并没有复制一份,其实是进行浅拷贝,就是将原来的存放数据的地址让另一个通过拷贝构造的也指向这个地方,类似共享指针一样
- 初始化全0的图像:
Mat m = Mat::zeros(img.size(), img.type());
Mat m = Mat::zeros(2, 2, CV_8UC1);
4、图像操作
- 获取图像像素指针:
Mat img=imread("/path",flags);
uchar* p=img.ptr<unchar>(row);//获取第row行所指向的指针
-
读取一个RGB像素点的像素值
Vec3b
是 OpenCV 中一个非常常用的数据类型,它表示一个包含三个无符号字节(unsigned char
,也就是 8 位无符号整数)的向量。常用于存储图像中每个像素的颜色信息,例如 RGB 或 BGR 值。
// 设置 (1,1) 像素点的 BGR 值
img.at<Vec3b>(1, 1) = Vec3b(255, 0, 0); // 蓝色 (BGR: 255, 0, 0)
// 获取 (1,1) 像素点的值
Vec3b pixel = img.at<Vec3b>(1, 1);
uchar B_color=pixel[0];
uchar G_color=pixel[1];
uchar R_color=pixel[2];
return 0;
}
- 像素范围处理
saturate_cast<unchar>(num);
uchar c1=saturate_cast<uchar>(-5);
uchar c2=saturate_cast<uchar>(100);
uchar c2=saturate_cast<uchar>(258);
// c1=0 c2=100 c3=255
此函数的功能是确保RGB值的范围在0~255之间
eg: 调整图片的整体亮度
void Demo::testMaskOperator(const Mat& src)
{
Mat srcImg = src.clone();
int row = srcImg.rows;
int col = srcImg.cols;
for (size_t i = 0; i < row; i++)
{
uchar* p = srcImg.ptr<uchar>(i);
for (int j = 0; j < col; j++)
{
//因为是三通道,调整亮度都得加一样的值
*p++ = saturate_cast<uchar>(20 + *p);
*p++ = saturate_cast<uchar>(20 + *p);
*p++ = saturate_cast<uchar>(20 + *p);
}
}
namedWindow("掩膜后图片", WINDOW_AUTOSIZE);
imshow("掩膜后图片", srcImg);
}
修改像素:
· 灰度图像
img.at<uchar>(row, col) = 123;
· RGB图像
img.at<Vec3b>(row, col)[0] = 123; //修改参数B
img.at<Vec3b>(row, col)[1] = 123; //修改参数G
img.at<Vec3b>(row, col)[2] = 123; //修改参数R
##4.1 ROI选择
ROI的概念
ROI (Region of Interest) 指图像中的“感兴趣区域”,是矩阵的一部分。通过选取图像的一部分区域进行处理,可以方便地对局部图像操作,例如剪裁、修改局部像素值、特定区域处理等。
ROI选择的方法
-
定义一个矩形区域: 使用 OpenCV 的
Rect
类,指定感兴趣区域的起始点和宽高。cpp 复制代码 Rect r(x, y, width, height);
-
裁剪或操作该区域: 使用
Mat
的构造函数或重载操作符()
,直接获得该区域对应的子图。
5、通道分离与合并
- 对于RGB图来说,具有三个通道即R,G,B三个通道,比如一个苹果的图片,分为三个通道分离后
如图,因为红色在苹果分布较多,所以,R的值比较高
所谓的通道分离其实就是把三个通道分成三个单通道的图片,但是各个单通道图片的值是R,G,B的值
所以,提取后,我们可以对R通道进行操作,从而使红色没有那么鲜艳,或者更鲜艳
- merge()函数
OpenCV 中,merge
函数用于将多个单通道图像(或矩阵)合并成一个多通道图像(或矩阵)。这个函数在处理图像时非常有用,尤其是在需要将多个单通道图像组合成一个彩色图像时。
void cv::merge(
const cv::Mat* mv, // 输入的单通道矩阵数组
size_t count, // 输入矩阵的数量
cv::Mat& dst // 输出的多通道矩阵
);
eg:
vector<Mat> channels;
split(src, channels);
namedWindow("R", WINDOW_FREERATIO);
namedWindow("G", WINDOW_FREERATIO);
namedWindow("B", WINDOW_FREERATIO);
channels[2] -= 40;
channels[0] += 20;
imshow("R", channels[2]);//3,cv是BGR
imshow("G", channels[1]);
imshow("B", channels[0]);
Mat rgbImage;
merge(channels, rgbImage);
namedWindow("RGB", WINDOW_FREERATIO);
imshow("RGB", rgbImage);
imwrite("./rgbSubImage.jpg", rgbImage);
waitKey(0);
6、图像色彩空间转换
- cvtColor函数
将图片的类型转换为想要的
void cvtColor(InputArray src, OutputArray dst, int code, int dstCn = 0);
cvtColor
是 OpenCV 中用于图像颜色空间转换的函数。它可以将图像从一个颜色空间转换到另一个颜色空间,例如从 BGR 到灰度、从 BGR 到 HSV、从 BGR 到 RGB 等。颜色空间转换在图像处理中非常常见,尤其是在需要特定颜色表示或处理时。
InputArray src
: 输入图像,可以是Mat
类型,表示需要转换颜色空间的源图像。OutputArray dst
: 输出图像,转换后的图像会被存储在这里。int code
: 颜色空间转换的代码,指定从哪个颜色空间转换到哪个颜色空间。常见的转换代码包括:cv::COLOR_BGR2GRAY
: 将 BGR 图像转换为灰度图像。cv::COLOR_BGR2HSV
: 将 BGR 图像转换为 HSV 颜色空间。cv::COLOR_BGR2RGB
: 将 BGR 图像转换为 RGB 颜色空间。cv::COLOR_GRAY2BGR
: 将灰度图像转换为 BGR 图像。cv::COLOR_HSV2BGR
: 将 HSV 图像转换为 BGR 颜色空间。- 更多转换代码可以在 OpenCV 文档中找到。
int dstCn = 0
: 输出图像的通道数。如果设置为 0,则根据转换代码自动确定输出图像的通道数。
6.1inRange函数
inRange
是 OpenCV 中用于图像颜色范围检测的函数。它可以根据指定的颜色范围,生成一个二值掩码(mask),掩码中值为 255 的像素表示该像素的颜色在指定的范围内,值为 0 的像素表示不在范围内。inRange
函数常用于颜色分割、目标检测等任务。
void inRange(InputArray src, InputArray lowerb, InputArray upperb, OutputArray dst);
Mat hsvMat;
cvtColor(src, hsvMat, COLOR_BGR2HSV);
Mat maskMat;
//这里获取的是所有蓝色区域的部分,最后所有属于蓝色范围内的像素值都变为255,即黑色
inRange(hsvMat, Scalar(100, 43, 46), Scalar(124, 255, 255), maskMat);
//此时进行取反,0就变成了255,255就变成了0,此时原图片蓝色区域的部分变为白色,不是蓝色的区域变为黑色
bitwise_not(maskMat, maskMat);
//创建一个红色背景的画布
Mat back = Mat::zeros(hsvMat.size(), hsvMat.type());
back = Scalar(40, 40, 180);
Mat dest;
//将原图src拷贝到back中,第三个参数为掩码矩阵。只有掩码中对应位置为非零的像素才会被复制
src.copyTo(back, maskMat);
//此时就将蓝色背景的证件照变为红色背景了
namedWindow("cutImg", WINDOW_FREERATIO);
imshow("cutImg", back);
//bitwise_not(maskMat, maskMat);
waitKey(0);
eg:提取转换证件照颜色
##6.2HSV颜色值对照表
minMaxLoc
函数
minMaxLoc
是 OpenCV 库中的一个函数,用于在图像或矩阵中找到最小值和最大值,并返回它们的位置。这个函数在处理图像时非常有用,尤其是在需要找到图像中最亮或最暗的区域时。
void minMaxLoc(InputArray src,
double* minVal,
double* maxVal = 0,
Point* minLoc = 0,
Point* maxLoc = 0,
InputArray mask = noArray());
src: 输入的单通道数组(图像或矩阵)。可以是 CV_8U, CV_16U, CV_16S, CV_32F, 或 CV_64F 类型的矩阵。
minVal: 指向最小值的指针。如果不需要最小值,可以传入 nullptr。
maxVal: 指向最大值的指针。如果不需要最大值,可以传入 nullptr。
minLoc: 指向最小值位置的指针。如果不需要最小值的位置,可以传入 nullptr。
maxLoc: 指向最大值位置的指针。如果不需要最大值的位置,可以传入 nullptr。
mask: 可选的掩码矩阵,用于指定在哪些区域中查找最小值和最大值。只有掩码中对应位置为非零的元素才会被考虑。如果不需要掩码,可以传入 noArray()。
meanStdDev
函数
meanStdDev
函数是 OpenCV 库中的一个函数,用于计算矩阵或图像的均值(mean)和方差(标准差)(standard deviation)。这个函数在图像处理和计算机视觉中非常有用,尤其是在需要分析图像的亮度分布或对比度时。
void meanStdDev(InputArray src,
OutputArray mean,
OutputArray stddev,
InputArray mask = noArray());
** 参数说明**
- src: 输入的矩阵或图像。可以是单通道或多通道的矩阵。
- mean: 输出的均值矩阵。对于单通道图像,
mean
是一个Scalar
类型的值;对于多通道图像,mean
是一个包含每个通道均值的Scalar
数组。 - stddev: 输出的标准差矩阵。对于单通道图像,
stddev
是一个Scalar
类型的值;对于多通道图像,stddev
是一个包含每个通道标准差的Scalar
数组。 - mask: 可选的掩码矩阵,用于指定在哪些区域中计算均值和标准差。只有掩码中对应位置为非零的元素才会被考虑。如果不需要掩码,可以传入
noArray()
。
返回值
该函数没有返回值,均值和标准差通过传入的 mean
和 stddev
参数返回。
7.图像几何形状绘制
在OpenCv中,坐标和Qt一样,左上角起始坐标为(0,0)
- 绘制矩形函数rectangle()
OpenCV中,rectangle
函数用于在图像上绘制矩形。这个函数非常常用,尤其是在图像处理和计算机视觉任务中,用于标记感兴趣的区域(ROI)或进行可视化。
void rectangle(
cv::Mat& img, // 目标图像
cv::Point pt1, // 矩形的左上角点
cv::Point pt2, // 矩形的右下角点
const cv::Scalar& color, // 矩形的颜色
int thickness = 1, // 线的粗细(负值表示填充矩形)
int lineType = cv::LINE_8, // 线的类型
int shift = 0 // 坐标精度(通常为0)
);
//重载的另一个,功能一样
void rectangle(
InputOutputArray img,
Rect rec,
const Scalar& color,
int thickness = 1,
int lineType = LINE_8,
int shift = 0);
int thickness = 1, // 线的粗细(负值表示填充矩形)
为负数时候,填充矩形
创建一个和原图大小一致的Mat,然后在同一个位置画一个框,合并两个图片,按权重比,如图
7.1几何相关的函数
1. addWeighted函数
是 OpenCV 中用于图像加权叠加的函数。它可以将两幅图像按照一定的权重进行混合,生成一幅新的图像。这个函数在图像融合、图像叠加、图像增强等场景中非常有用。
void cv::addWeighted(
InputArray src1, // 第一幅图像
double alpha, // 第一幅图像的权重
InputArray src2, // 第二幅图像
double beta, // 第二幅图像的权重
double gamma, // 偏移量(标量值)
OutputArray dst, // 输出图像
int dtype = -1 // 输出图像的数据类型(可选)
);
与几何相关的函数还有画椭圆,画圆函数
2. circle 函数
cv::circle
函数用于在图像上绘制一个圆形。这个函数非常常用,尤其是在图像处理和计算机视觉任务中,用于标记感兴趣的区域(ROI)或进行可视化。
void cv::circle(
cv::Mat& img, // 目标图像
cv::Point center, // 圆心坐标
int radius, // 圆的半径
const cv::Scalar& color, // 圆的颜色
int thickness = 1, // 线的粗细(负值表示填充圆形)
int lineType = cv::LINE_8, // 线的类型
int shift = 0 // 坐标精度(通常为0)
);
lineType
:
- 线的类型,类型为
int
。 - 常用的值有:
cv::LINE_4
: 4连通线。cv::LINE_8
: 8连通线(默认值)。cv::LINE_AA
: 抗锯齿线。
3. line函数
line
函数用于在图像上绘制一条直线。这个函数非常常用,尤其是在图像处理和计算机视觉任务中,用于标记边界、绘制辅助线或进行可视化。
void cv::line(
cv::Mat& img, // 目标图像
cv::Point pt1, // 直线的起点
cv::Point pt2, // 直线的终点
const cv::Scalar& color, // 直线的颜色
int thickness = 1, // 线的粗细
int lineType = cv::LINE_8, // 线的类型
int shift = 0 // 坐标精度(通常为0)
);
lineType
:
- 线的类型,类型为
int
。 - 常用的值有:
cv::LINE_4
: 4连通线。cv::LINE_8
: 8连通线(默认值)。cv::LINE_AA
: 抗锯齿线。
7.2多边形填充与绘制
- fillPoly函数
cv::fillPoly
函数用于在图像上绘制一个或多个填充的多边形。这个函数非常常用,尤其是在图像处理和计算机视觉任务中,用于标记感兴趣的区域(ROI)或进行可视化。
void cv::fillPoly(
cv::Mat& img, // 目标图像
const std::vector<std::vector<cv::Point>>& pts, // 多边形的顶点集合
const cv::Scalar& color, // 多边形的颜色
int lineType = cv::LINE_8, // 线的类型
int shift = 0, // 坐标精度(通常为0)
cv::Point offset = cv::Point(0, 0) // 顶点偏移量(可选)
);
- polylines函数
cv::polylines
函数用于在图像上绘制一个或多个多边形的轮廓(即不填充的多边形)。这个函数非常常用,尤其是在图像处理和计算机视觉任务中,用于标记边界或进行可视化。
void cv::polylines(
cv::Mat& img, // 目标图像
const std::vector<std::vector<cv::Point>>& pts, // 多边形的顶点集合
bool isClosed, // 是否闭合多边形
const cv::Scalar& color, // 多边形的颜色
int thickness = 1, // 线的粗细
int lineType = cv::LINE_8, // 线的类型
int shift = 0 // 坐标精度(通常为0)
);
- drawContours函数
cv::
函数用于在图像上绘制轮廓。这个函数非常常用,尤其是在图像处理和计算机视觉任务中,用于可视化检测到的轮廓。
void cv::drawContours(
cv::Mat& image, // 目标图像
const std::vector<std::vector<cv::Point>>& contours, // 轮廓集合
int contourIdx, // 要绘制的轮廓索引
const cv::Scalar& color, // 轮廓的颜色
int thickness = 1, // 线的粗细
int lineType = cv::LINE_8, // 线的类型
const std::vector<cv::Vec4i>& hierarchy = std::vector<cv::Vec4i>(), // 轮廓层次结构(可选)
int maxLevel = INT_MAX, // 最大绘制层级(可选)
cv::Point offset = cv::Point(0, 0) // 轮廓偏移量(可选)
);
参数说明
image
:- 目标图像,类型为
cv::Mat
。 - 这是你想要绘制轮廓的图像。
- 目标图像,类型为
contours
:- 轮廓集合,类型为
std::vector<std::vector<cv::Point>>
。 - 每个轮廓是一个
std::vector<cv::Point>
,表示轮廓的顶点。
- 轮廓集合,类型为
contourIdx
:- 要绘制的轮廓索引,类型为
int
。 - 如果
contourIdx
为负数(如-1
),则绘制所有轮廓。
- 要绘制的轮廓索引,类型为
color
:- 轮廓的颜色,类型为
cv::Scalar
。 - 可以使用
cv::Scalar(B, G, R)
来指定颜色,其中B
、G
、R
分别表示蓝色、绿色和红色的强度(0-255)。
- 轮廓的颜色,类型为
thickness
:- 线的粗细,类型为
int
。 - 如果
thickness
为正数,表示线的宽度;如果thickness
为负数(如-1
),则填充轮廓。
- 线的粗细,类型为
lineType
:- 线的类型,类型为
int
。 - 常用的值有:
cv::LINE_4
: 4连通线。cv::LINE_8
: 8连通线(默认值)。cv::LINE_AA
: 抗锯齿线。
- 线的类型,类型为
hierarchy
:- 轮廓的层次结构,类型为
std::vector<cv::Vec4i>
。 - 通常在调用
cv::findContours
时生成。
- 轮廓的层次结构,类型为
maxLevel
:- 最大绘制层级,类型为
int
。 - 用于控制绘制轮廓的层次结构。
- 最大绘制层级,类型为
offset
:- 轮廓偏移量,类型为
cv::Point
。 - 用于将所有轮廓偏移指定的值。
- 轮廓偏移量,类型为
8. 像素归一化
像素归一化(Pixel Normalization)是图像处理中的一种常见操作,用于将图像的像素值转换到一个特定的范围,通常是 [0, 1] 或 [-1, 1]。归一化的目的是为了消除不同图像之间的尺度差异,使得图像数据在后续处理(如神经网络训练)中更加稳定和一致。
归一化是一种数理统计中常用的数据预处理手段,在机器学习中归一化通常将数据向量每个维度的数据映射到(0,1)或(-1,1)之间的区间或者将数据向量的某个范数映射为1,归一化好处有两个:
消除数据单位的影响:其一可以将有单位的数据转为无单位的标准数据,如成年人的身高150-200cm、成年人体重50-90Kg,身高的单位是厘米而体重的单位是千克,不同维度的数据单位不一样,造成原始数据不能直接代入机器学习中进行处理,所以这些数据经过特定方法统一都映射到(0,1)这个区间,这样所有数据的取值范围都在同一个区间里的。
首先,需要知道的是,对于大多数图像数据,像素值是介于0和255之间的整数。
在深度神经网络训练时一般使用较小的权重值来进行拟合,而当训练数据的值是较大整数值时,可能会减慢模型训练的过程。因此,一般需要图像的像素进行归一化,使得图像的每个像素值都在0-1之间。当图像的像素处于0-1范围时,由于任然介于0~255之间,所以图像依旧是有效的,并且可以正常查看图像。
像素的归一化可以通过将所有像素值除以最大像素值来实现,最大像素值一般为255。需要注意的是,不管图片是单通道的黑白图片还是多通道的彩色图片,都可以使用这种方法;不管图片的最大像素值是否有255,都除以255
比如将一个CV_8UC3的一个图像和另一个其他类型的,可以都转化为0-1之间的浮点数
9. 图像的放缩和插值
cv::resize
是 OpenCV 库中用于调整图像大小的函数。它可以将图像缩放到指定的尺寸,或者按照给定的比例因子进行缩放。cv::resize
函数支持多种插值方法,以适应不同的缩放需求。
函数原型
void cv::resize(
InputArray src,
OutputArray dst,
Size dsize,
double fx = 0,
double fy = 0,
int interpolation = INTER_LINEAR
);
参数说明
src
: 输入图像,类型为cv::InputArray
,通常是一个cv::Mat
对象。dst
: 输出图像,类型为cv::OutputArray
,缩放后的图像将存储在这里。dsize
: 输出图像的尺寸,类型为cv::Size
。如果设置为Size(0, 0)
,则根据fx
和fy
计算输出图像的大小。fx
: 水平方向上的缩放比例因子。如果为 0,则根据dsize.width
和输入图像的宽度自动计算。fy
: 垂直方向上的缩放比例因子。如果为 0,则根据dsize.height
和输入图像的高度自动计算。interpolation
: 插值方法,用于确定如何计算输出图像的像素值。常用的插值方法包括:INTER_NEAREST
: 最近邻插值,速度最快,但质量较差。INTER_LINEAR
: 双线性插值(默认),速度较快,质量较好。INTER_CUBIC
: 双三次插值,速度较慢,但质量更高。INTER_AREA
: 区域插值,适用于图像缩小,能够避免波纹效应。INTER_LANCZOS4
: Lanczos 插值,质量最高,但速度最慢。
使用示例
- 示例 1: 指定输出图像尺寸
#include <opencv2/opencv.hpp>
int main() {
cv::Mat src = cv::imread("input.jpg");
if (src.empty()) {
std::cerr << "Could not open or find the image!" << std::endl;
return -1;
}
cv::Mat dst;
cv::resize(src, dst, cv::Size(640, 480)); // 将图像缩放为 640x480
cv::imshow("Resized Image", dst);
cv::waitKey(0);
return 0;
}
- 示例 2: 使用比例因子缩放图像
#include <opencv2/opencv.hpp>
int main() {
cv::Mat src = cv::imread("input.jpg");
if (src.empty()) {
std::cerr << "Could not open or find the image!" << std::endl;
return -1;
}
cv::Mat dst;
cv::resize(src, dst, cv::Size(), 0.5, 0.5); // 将图像缩小为原来的一半
cv::imshow("Resized Image", dst);
cv::waitKey(0);
return 0;
}
- 示例 3: 使用不同的插值方法
#include <opencv2/opencv.hpp>
int main() {
cv::Mat src = cv::imread("input.jpg");
if (src.empty()) {
std::cerr << "Could not open or find the image!" << std::endl;
return -1;
}
cv::Mat dst;
cv::resize(src, dst, cv::Size(640, 480), 0, 0, cv::INTER_CUBIC); // 使用双三次插值
cv::imshow("Resized Image", dst);
cv::waitKey(0);
return 0;
}
- 注意事项
- 如果
dsize
设置为Size(0, 0)
,则fx
和fy
必须为非零值,否则函数无法确定输出图像的尺寸。 - 插值方法的选择会影响输出图像的质量和计算速度。通常情况下,
INTER_LINEAR
是一个不错的选择,它在速度和质量之间取得了良好的平衡。 - 当缩小图像时,
INTER_AREA
插值方法通常能产生更好的结果,因为它能够避免波纹效应。
10. 图像的翻转
cv::flip
是 OpenCV 中用于翻转图像的函数。它可以沿水平轴、垂直轴或同时沿两个轴翻转图像。这个函数在处理图像数据时非常有用,例如在数据增强、图像校正或简单的图像变换中。
函数原型
void cv::flip(
InputArray src,
OutputArray dst,
int flipCode
);
参数说明
src
: 输入图像,类型为cv::InputArray
,通常是一个cv::Mat
对象。dst
: 输出图像,类型为cv::OutputArray
,翻转后的图像将存储在这里。flipCode
: 控制翻转方式的标志:flipCode = 0
: 沿水平轴(X 轴)翻转,即上下翻转。flipCode > 0
: 沿垂直轴(Y 轴)翻转,即左右翻转。flipCode < 0
: 同时沿水平轴和垂直轴翻转,即上下左右同时翻转。
使用示例
- 示例 1: 沿水平轴翻转(上下翻转)
#include <opencv2/opencv.hpp>
int main() {
cv::Mat src = cv::imread("input.jpg");
if (src.empty()) {
std::cerr << "Could not open or find the image!" << std::endl;
return -1;
}
cv::Mat dst;
cv::flip(src, dst, 0); // 沿水平轴翻转
cv::imshow("Flipped Image", dst);
cv::waitKey(0);
return 0;
}
- 示例 2: 沿垂直轴翻转(左右翻转)
#include <opencv2/opencv.hpp>
int main() {
cv::Mat src = cv::imread("input.jpg");
if (src.empty()) {
std::cerr << "Could not open or find the image!" << std::endl;
return -1;
}
cv::Mat dst;
cv::flip(src, dst, 1); // 沿垂直轴翻转
cv::imshow("Flipped Image", dst);
cv::waitKey(0);
return 0;
}
- 示例 3: 同时沿水平轴和垂直轴翻转
#include <opencv2/opencv.hpp>
int main() {
cv::Mat src = cv::imread("input.jpg");
if (src.empty()) {
std::cerr << "Could not open or find the image!" << std::endl;
return -1;
}
cv::Mat dst;
cv::flip(src, dst, -1); // 同时沿水平轴和垂直轴翻转
cv::imshow("Flipped Image", dst);
cv::waitKey(0);
return 0;
}
- 注意事项
-
cv::flip
函数不会改变图像的深度(即数据类型),输出图像的类型与输入图像相同。 -
如果需要在原地翻转图像(即不创建新的输出图像),可以将
dst
设置为与src
相同的对象,例如:cv::flip(src, src, 1); // 原地左右翻转
-
cv::flip
函数支持多通道图像(如彩色图像),每个通道都会独立地进行翻转。
11. 图像旋转
对于图像的旋转,首要要实现一个旋转矩阵
cv::getRotationMatrix2D
是 OpenCV 中用于生成二维旋转矩阵的函数。这个矩阵可以用于图像的旋转操作,通常与 cv::warpAffine
函数结合使用来实现图像的旋转。
函数原型
cv::Mat cv::getRotationMatrix2D(
Point2f center,
double angle,
double scale
);
参数说明
center
: 旋转中心的坐标,类型为cv::Point2f
。旋转是围绕这个点进行的。angle
: 旋转角度,单位为度。正值表示逆时针旋转,负值表示顺时针旋转。scale
: 缩放比例因子。在旋转的同时可以对图像进行缩放。如果不需要缩放,可以设置为1.0
。
返回值
- 返回一个
2x3
的仿射变换矩阵,类型为cv::Mat
。这个矩阵可以用于cv::warpAffine
函数来实现图像的旋转和缩放。
仿射变换矩阵的形式
返回的 2x3
矩阵形式如下:
[ α β center.x ]
[ -β α center.y ]
其中:
α = cos(angle)
β = sin(angle)
即sin和cos的值,
center.x = 中心点的x坐标
center.y = 中心点的Y坐标
旋转函数warpAffine()
cv::warpAffine
是 OpenCV 中用于执行仿射变换的函数。仿射变换是一种线性变换,包括旋转、缩放、平移和剪切等操作。cv::warpAffine
通过一个 2x3 的变换矩阵对图像进行变换,生成一个新的图像。
void cv::warpAffine(
InputArray src,
OutputArray dst,
InputArray M,
Size dsize,
int flags = INTER_LINEAR,
int borderMode = BORDER_CONSTANT,
const Scalar& borderValue = Scalar()
);
参数说明
参数 | 说明 |
---|---|
src | 输入图像,类型为 cv::InputArray ,通常是一个 cv::Mat 对象。 |
dst | 输出图像,类型为 cv::OutputArray ,变换后的图像将存储在这里。 |
M | 2x3 的仿射变换矩阵,类型为 cv::InputArray 。可以通过 cv::getRotationMatrix2D 或其他方法生成。 |
dsize | 输出图像的大小,类型为 cv::Size 。 |
flags | 插值方法,用于计算输出图像的像素值。默认值为 INTER_LINEAR (双线性插值)。其他可选值包括 INTER_NEAREST 、INTER_CUBIC 等。 |
borderMode | 边界填充模式,用于处理图像边界外的像素。默认值为 BORDER_CONSTANT 。其他可选值包括 BORDER_REPLICATE 、BORDER_REFLECT 等。 |
borderValue | 当 borderMode 为 BORDER_CONSTANT 时,用于填充边界像素的值。默认值为 Scalar() (黑色)。 |
所以,想要旋转,想要输入一个放射变换矩阵,这个矩阵要手动输入,当旋转后,实际要的图像大小也要改变
新的图像的大小应为
void tese_rotateImg(Mat &image) {
Mat dst, M;
int w = image.cols;
int h = image.rows;
M = getRotationMatrix2D(Point2f(w / 2, h / 2), 45, 1.0);
double cos = abs(M.at<double>(0, 0));
double sin = abs(M.at<double>(0, 1));
int nw = cos*w + sin*h;
int nh = sin*w + cos*h;
M.at<double>(0, 2) += (nw / 2 - w / 2);
M.at<double>(1,2) += (nh / 2 - h / 2);
warpAffine(image, dst, M, Size(nw, nh), INTER_LINEAR, 0, Scalar(255, 255, 0));
imshow("旋转演示", dst);
}
相关博客:旋转矩阵讲解
12. 视频以及摄像头使用
在OpenCv中,视频处理或者摄像头处理的类为cv::videoCapture
cv::VideoCapture
是 OpenCV 中用于从视频文件、摄像头或网络流中捕获视频帧的类。它提供了许多常用的函数来操作视频流。以下是 cv::VideoCapture
的常用函数及其详细说明:
cv::VideoCapture
是 OpenCV 中用于从视频文件、摄像头或网络流中捕获视频帧的类。它提供了许多常用的函数来操作视频流。以下是 cv::VideoCapture
的常用函数及其详细说明:
1.1构造函数
函数原型
cv::VideoCapture::VideoCapture();
cv::VideoCapture::VideoCapture(const String& filename, int apiPreference = CAP_ANY);
cv::VideoCapture::VideoCapture(int index, int apiPreference = CAP_ANY);
说明
- 默认构造函数: 创建一个未初始化的
VideoCapture
对象。 - 从文件或 URL 打开视频:
filename
: 视频文件的路径或 URL。apiPreference
: 使用的后端 API(如CAP_FFMPEG
、CAP_OPENCV_MJPEG
等),默认值为CAP_ANY
。
- 从摄像头打开视频:
index
: 摄像头的索引(例如,0 表示默认摄像头)。apiPreference
: 使用的后端 API,默认值为CAP_ANY
。
示例
cv::VideoCapture cap("video.mp4"); // 从文件打开
cv::VideoCapture cap(0); // 从默认摄像头打开
2.打开视频源
函数原型
bool cv::VideoCapture::open(const String& filename, int apiPreference = CAP_ANY);
bool cv::VideoCapture::open(int index, int apiPreference = CAP_ANY);
说明
- 打开视频文件、摄像头或网络流。
- 参数与构造函数相同。
- 返回
true
表示成功打开,false
表示失败。
示例
cv::VideoCapture cap;
cap.open("video.mp4"); // 打开视频文件
3.检查是否打开
函数原型
bool cv::VideoCapture::isOpened() const;
说明
- 检查视频源是否成功打开。
- 返回
true
表示已打开,false
表示未打开。
示例
if (!cap.isOpened()) {
std::cerr << "Failed to open video source!" << std::endl;
return -1;
}
4. 读取帧
函数原型
bool cv::VideoCapture::read(OutputArray image);
说明
- 从视频源中读取下一帧,并将其存储在
image
中。 - 返回
true
表示成功读取,false
表示失败(例如视频结束)。
示例
cv::Mat frame;
while (cap.read(frame)) {
cv::imshow("Frame", frame);
if (cv::waitKey(30) == 27) break; // 按下 ESC 键退出
}
5.抓取帧
函数原型
bool cv::VideoCapture::grab();
说明
- 抓取下一帧,但不解码。
- 通常与
retrieve()
配合使用,用于高效抓取帧或多摄像头同步。 - 返回
true
表示成功抓取,false
表示失败。
示例
if (cap.grab()) {
cv::Mat frame;
cap.retrieve(frame); // 解码并获取帧数据
cv::imshow("Frame", frame);
}
总结
cv::VideoCapture
提供了丰富的函数来操作视频流,包括打开视频源、读取帧、获取和设置视频属性等。掌握这些函数可以高效地处理视频数据,适用于视频处理、摄像头捕获等场景。
7.获取视频属性
函数原型
double cv::VideoCapture::get(int propId) const;
说明
- 获取视频的属性值,例如帧率、宽度、高度等。
propId
是属性标识符,常用值包括:CAP_PROP_FRAME_WIDTH
: 帧的宽度。CAP_PROP_FRAME_HEIGHT
: 帧的高度。CAP_PROP_FPS
: 帧率。CAP_PROP_FRAME_COUNT
: 总帧数(仅适用于视频文件)。
示例
double width = cap.get(cv::CAP_PROP_FRAME_WIDTH);
double height = cap.get(cv::CAP_PROP_FRAME_HEIGHT);
double fps = cap.get(cv::CAP_PROP_FPS);
std::cout << "Width: " << width << ", Height: " << height << ", FPS: " << fps << std::endl;
8.设置视频属性
函数原型
bool cv::VideoCapture::set(int propId, double value);
说明
- 设置视频的属性值。
propId
是属性标识符,value
是要设置的值。- 返回
true
表示成功设置,false
表示失败。
示例
cap.set(cv::CAP_PROP_FRAME_WIDTH, 640); // 设置帧宽度为 640
cap.set(cv::CAP_PROP_FRAME_HEIGHT, 480); // 设置帧高度为 480
9.释放资源
函数原型
void cv::VideoCapture::release();
说明
- 释放视频源占用的资源。
- 通常在程序结束时调用。