c++视频图像处理
打开视频或摄像头
打开指定视频
/*VideoCapture(const String &filename, apiPreference);
filename:读取的视频或者图像序列的名称
apiPreference:读取数据时设置的属性
*/
VideoCapture video; //定义一个空的视频对象
video.open("H:/BaiduNetdiskDownload/01.mp4");
// 判断视频有没有成功打开
if (!video.isOpened()) {
cout << "视频打开失败";
return -1;
}
打开摄像头
VideoCapture video(1); //打开一个摄像头
视频的相关操作
通过get获取视频数据
将视频流赋值给mat对象
Mat mat;
video >> mat;
bool isColor = (mat.type() == CV_8UC3); //判断视频是否为3通道彩色
输出视频的帧率
cout <<"视频的帧率"<< video.get(CAP_PROP_FPS);
VideoWriter 视频写入
filename:保存视频的地址和文件名,包含视频格式
fourcc:压缩帧的4字符编解码器代码
fps:保存视频的帧率,即视频中每秒图像的张数
framSize:视频帧的尺寸
isColor:保存视频是否为彩色视频
VideoWriter writer;
int codec = VideoWriter::fourcc('M', 'J', 'P', 'G'); //选择MJPG的编码格式
double fps = 25.0; //设置视频的帧率
string filename = "file.avi"; // 视频的名和格式
writer.open(filename, codec, fps, mat.size(),isColor); //创建保存文件的视频流
if (!writer.isOpened()) { // 判断视频流是否正常打开
cout << "视频打开失败";
return -1;
}
保存视频中的数据
while (1) {
// 检查是否执行完毕
if (!video.read(video)) // 判断能否从摄像头或者视频文件中读出一帧图像
{
cout<<"摄像头或者视频读取完成"<<endl;
break;
}
writer.write(video); //把图像写入视频流 writer<<mat
imshow('live', video); //显示图像
char c = waitKey(50);
if (c == 27) { //俺esc退出
break;
}
}
颜色空间转换
三种存取数据的区间
- 8U–存储0-255的数据类型
- 32F–存储0-1(将0-1区间映射为0-255,大于1的部分映射为白色,小于0的部分映射为黑色)
- 64F–存储0-1
convertTo
m:输出图像
rtype:转换后数据类型
alpha:缩放系数
beta:平移系数
转换公式:alpha*I(x,y)+ beta
// 将0-255的图像转为0-1
mat.convertTo(mat2, CV_32F, 1/255.0, 0);
RGB转灰度图公式:Gray=R0.3+G0.59+B*0.11
图像格式转换cvtColor
src:待转换颜色模型的原始图像
dst:转换颜色模型后的目标图像。
code:颜色空间转换的标志,如由RGB空间到HSV空间。
dstCn:目标图像中的通道数,如果参数为0,则从src和代码中自动导出通道数。
Mat HSV;
// 将RGB转为HSV
cvtColor(mat, HSV, COLOR_BGR2HSV);
通道管理
split多通道分离
split(
InputArray m, //可以输入mat型
OutputArrayOfArrays mv
)
m:待分离的多通道图像
mv:分离后的单通道图像,为向量vector形式
merge多通道合并
merge(
InputArrayOfArrays mv,
OutputArray dst )
mv:需要合并的图像向量vector,其中每个图像必须拥有相同的尺寸和数据类型
dst:合并后输出的图像,通道数等于所有输入图像的通道数的总和
合并两个矩阵,取同一位置中较小的值
min(
InputArray src1,
InoytArray sec2,
OutputArray dst )
合并两个矩阵,取同一位置中较大的值
max(
InputArray src1,
InoytArray sec2,
OutputArray dst )
找出矩阵中的最值
minMaxLoc(
InputArray src, //输入单通道矩阵
CV_OUT double* minVal, //指向最小值的指针,如果不需要,则使用NULL
CV_OUT double* maxVal =0, //指向最大值的指针,如果不需要,则使用NULL
CV_OUT Point* minLoc =0, //指向最小值位置的指针,如果不需要,则使用NULL
CV_OUT Point* maxLoc = 0, //指向最大值位置的指针,如果不需要,则使用NULL
InputArray mask =noArray() //掩码矩阵,用于标记寻找上述四个值的范围,参数默认值为noArray,表示寻找范围是矩阵中所有数据
)
与或非运算
bitwise_not( //非运算
InputArray src, //输入矩阵
OutputArray dst, //输出矩阵
InputArray mask = noArray() //掩码区域
)
bitwise_and( //与运算
InputArray src1, //输入矩阵1
InputArray src2, //输入矩阵2
OutputArray dst, // 输出矩阵
InputArray mask = noArray());//掩码矩阵
bitwise_or( //或运算
InputArray src1, //输入矩阵1
InputArray src2, //输入矩阵2
OutputArray dst, // 输出矩阵
InputArray mask = noArray());//掩码矩阵
)
阈值化(二值化)
threshold( //图像二值化
InputArray src, //待二值化图像,图像只能是CV_8U和CV_32F两种数据类型
OutputArray dst, //二值化后的图像
double thresh, //阈值
double maxval, //二值化过程中的最大值,非必须参数
int type //二值化方式
);
adaptiveThreshold( //自适应阈值化,只支持灰度图
InputArray src, //待二值化图像
OutputArray dst, //输出图像
double maxValue, //二值化的最大值
int adaptiveMethod, //自适应确定阈值的方法,分为均值法ADAPTIVE_THRESH_MEAN_C和高斯法ADAPTIVE_THRESH_GAUSSIAN_C
int thresholdType, //选择二值化方法
int blockSize, //自适应确定阈值的像素邻域大小
double C); //从平均值或者加权平均值中减去的常数
LUT查找表
LUT(
InputArray src, //输入图像,类型只能是8U
InputArray lut, //256个像素的查找表,如果为多通道,通道数必须和输入图像通道数相同
OutputArray dst //输出矩阵,数据类型和查找表相同
);
图像尺寸缩放、翻转、拼接
resize(
InputArray src, //输入图像
OutputArray dst, //输出图像
Size dsize, //输出图像的尺寸
double fx = 0, //水平轴的比例因子,变为原来的几倍
double fy = 0, //垂直轴的比例因子
int interpolation = INTER_LINEAR //插值方法,INTER_AREA最近邻插值,INTER_LINEAR双线性插值,INTER_CUBIC三线性插值
);
flip( 图像翻转
InputArray src, //输入图像
OutputArray dst, //输出图像
int flipCode //翻转方式标志,数值大于0表示绕y轴翻转,数值等于0表示围绕x轴翻转,数值小于0表示围绕两个轴翻转
);
resize(INTER_AREA,INTER_LINEAR,INTER_CUBIC)
hconcat(//横向拼接
InputArray src1, // 输入图像
InputArray src2, //输入图像,需要两个输入图像高度相同
OutputArray dst //输出图像
)
vconcat(//纵向拼接
InputArray src1, // 输入图像
InputArray src2, //输入图像,需要两个输入图像高度相同
OutputArray dst //输出图像
)
仿射变换和旋转
// 仿射变换:由平移,缩放,旋转,翻转和错切组合得到,也叫三点变换
warpAffine( 仿射变换
InputArray src, //输入图像
OutputArray dst, //输出图像
InputArray M, //2*3变换矩阵,仿射变换矩阵
Size dsize, //输出图像尺寸
int flags = INTER_LINEAR, //插值方法标志
int borderMode = BORDER_CONSTANT, //像素边界外推方法的标志
const Scalar& borderValue = Scalar()); //填充边界使用的数值,默认情况下为0
像素边界外推方法
BORDER_CONSTANT = 0,用特定值填充//!< iiiiii|abcdefgh|iiiiiii
BORDER_REPLICATE = 1,两端复制填充//!< aaaaaa|abcdefgh|hhhhhhh
BORDER_REFLECT = 2, 倒叙填充//!< fedcba|abcdefgh|hgfedcb
BORDER_WRAP = 3, 正序填充//!< cdefgh|abcdefgh|abcdefg
BORDER_REFLECT_101 = 4, 不包含边界值倒叙填充//!< gfedcb|abcdefgh|gfedcba
BORDER_TRANSPARENT = 5, //随机填充!< uvwxyz|abcdefgh|ijklmno
BORDER_REFLECT101 = BORDER_REFLECT_101, //!与BORDER_REFLECT_101相同
BORDER_DEFAULT = BORDER_REFLECT_101, //!与BORDER_REFLECT_101相同
BORDER_ISOLATED = 16 //!< 不关心感兴趣区域之外的部分
c++中并没有直接进行图像旋转的函数,需要求取一个旋转变换的仿射矩阵,通过仿射矩阵实现图像的旋转
getRotationMatrix2D( 图像旋转,返回一个2*3的矩阵
Point2f center, 图像旋转的中心位置
double angle, 图像旋转的角度,正值为逆时针旋转
double scale 两个轴的比例因子,可以实现旋转过程中的图像缩放,不缩放输入1
);
图像旋转的计算公式
三点对应方式计算仿射变换矩阵
getAffineTransform(
const Point2f src[], 原图像的三个点坐标
const Point2f dst[] 仿射变换后的三个点坐标
);
透视变换(透视投影,又叫四点变换)
从一个点出发把一个平面内人形状投影到另一个平面上
计算公式:
getPerspectiveTransform( 计算透视变换矩阵
const Point2f src[], 原图像中的三个坐标
const Point2f dst[], 目标图像中的三个像素坐标
int solveMethod = DECOMP_LU 计算透视变换矩阵的方法
);
计算透视变换矩阵的方法
DECOMP_LU = 0, 最佳主轴元素的高斯消元法
DECOMP_SVD = 1, 奇异值分解法
DECOMP_EIG = 2, 特征值分解法
DECOMP_CHOLESKY = 3, Cholesky分解法
DECOMP_QR = 4, QR分解法
DECOMP_NORMAL = 16 使用正规方程公式,可以去前面的标志一起使用
warpPerspective( 透视变换函数
InputArray src, 输入图像
OutputArray dst,
InputArray M, 3*3的透视变换矩阵
Size dsize, 输出图像尺寸
int flags = INTER_LINEAR, 插值方式
int borderMode = BORDER_CONSTANT, 像素边界外推方法的标志
const Scalar& borderValue = Scalar() 填充边界使用的数值,默认为0
);
绘制图形
绘制直线
line(
InputOutputArray img, //绘制的图像
Point pt1, //起点坐标
Point pt2, //终点坐标
const Scalar& color, //颜色
int thickness = 1, //宽度
int lineType = LINE_8, //边界类型
int shift = 0 //中心坐标的半径数值中的小数点数
);
边界类型:
FILLED = -1, 填充型
LINE_4 = 4, //!< 4-connected line 四连接
LINE_8 = 8, //!< 8-connected line 8连接
LINE_AA = 16 //!< antialiased line
绘制圆形
circle(
InputOutputArray img,
Point center,
int radius, 半径长度
const Scalar& color,
int thickness = 1, 线的宽度,-1为绘制实心圆
int lineType = LINE_8,
int shift = 0
);
绘制椭圆
ellipse(InputOutputArray img,
Point center,
Size axes,
double angle, //椭圆旋转的角度
double startAngle, 起始角度
double endAngle, 终止角度
const Scalar& color,
int thickness = 1,
int lineType = LINE_8,
int shift = 0);
矩形绘制
rectangle(
InputOutputArray img,
Point pt1,
Point pt2,
const Scalar& color,
int thickness = 1,
int lineType = LINE_8,
int shift = 0);
绘制多边形
fillPoly(
InputOutputArray img,
const Point** pts, 所有顶点坐标(可以是多重数组,绘制多个多边形)
const int* npts, 定点数
int ncontours, 绘制的多边形的个数
const Scalar& color,
int lineType = LINE_8,
int shift = 0,
Point offset = Point()
);
绘制文字
putText(
InputOutputArray img,
const String& text,
Point org, //文字字符串左下角像素的坐标
int fontFace,
double fontScale,
Scalar color,
int thickness = 1,
int lineType = LINE_8,
bool bottomLeftOrigin = false
);
ROI分割和拷贝
img(
Range(
int start, //区间的开始
int end; //区间的结束
),
Range(
int start, //区间的开始
int end; //区间的结束
)
)
Rect_(
_Tp _x, //左上角x坐标
_Tp _y, //左上角y坐标
_Tp _width, //宽
_Tp _height) //高
矩阵存储图
浅拷贝:只拷贝矩阵头
mat1=mat2
深拷贝:拷贝所有内容
cv::copyTo
copyTo(
InputArray src,
OutputArray dst,
InputArray mask
);
Mat::copyTo
Mat mat1;
mat.copyTo(
OutputArray dst,
InputArray mask
) const
图像金字塔
高斯图像金字塔:不断下采样
拉普拉斯金字塔:第k层的高斯图像下采样,再上采样,然后上采样和第k层的高斯图像求和得到拉普拉斯金字塔
pyrDown( //下采样
InputArray src,
OutputArray dst,
const Size& dstsize = Size(),
int borderType = BORDER_DEFAULT //填充方式
);
pyrUp( 上采样
InputArray src,
OutputArray dst,
const Size& dstsize = Size(),
int borderType = BORDER_DEFAULT
);
创建滑动条和鼠标监控
创建滑动条
createTrackbar(
const String& trackbarname,
const String& winname, //创建滑动条的窗口的名称
int* value, //反应当前滑块的位置
int count, //最大值
TrackbarCallback onChange = 0, //回调函数
void* userdata = 0 //传递给回调函数的参数
);
案例代码
Mat img;
void callBack(int value, void*) {
float a = value / 100;
Mat img2 = img * a;
imshow("img", img2);
}
int main()
{
img = imread("H:/1732413934315.png");
namedWindow("img");
imshow("img", img);
int value = 100;
createTrackbar(
"滑动条名称",
"img",
&value,
200,
callBack,
0
);
waitKey(0);
return 0;
}
鼠标监控
setMouseCallback( 鼠标时间响应函数
const String& winname,
MouseCallback onMouse,
void* userdata = 0
)
MouseCallback(
int event, 鼠标响应事件标志,瞬间动作
int x,
int y,
int flags, 鼠标相应标识,长时间的操作
void* userdata 传递给回调函数的可选参数
)
鼠标响应时间标志
enum MouseEventTypes {
EVENT_MOUSEMOVE = 0, //!< 鼠标指针再窗口上移动
EVENT_LBUTTONDOWN = 1, //!<按下鼠标左键
EVENT_RBUTTONDOWN = 2, //!< 按下鼠标右键
EVENT_MBUTTONDOWN = 3, //!< 按下鼠标中键
EVENT_LBUTTONUP = 4, //!< 释放鼠标左键
EVENT_RBUTTONUP = 5, //!< 释放鼠标右键
EVENT_MBUTTONUP = 6, //!< 释放鼠标中键
EVENT_LBUTTONDBLCLK = 7, //!< 双击鼠标左键
EVENT_RBUTTONDBLCLK = 8, //!< 双击鼠标右键
EVENT_MBUTTONDBLCLK = 9, //!< 双击鼠标中键
EVENT_MOUSEWHEEL = 10,//!< 正值表示向前滚动,负值表示向后滚动
EVENT_MOUSEHWHEEL = 11 //!< 正值表示向左滚动,负值表示向右滚动
鼠标相应标识
EVENT_FLAG_LBUTTON = 1, //!< 按住左键拖拽
EVENT_FLAG_RBUTTON = 2, //!< 按住右键拖拽
EVENT_FLAG_MBUTTON = 4, //!< 按住中键拖拽
EVENT_FLAG_CTRLKEY = 8, //!< 按下ctrl键
EVENT_FLAG_SHIFTKEY = 16,//!< 按下SHIFT键
EVENT_FLAG_ALTKEY = 32 //!< 按下ALT键
normalize( 归一化
InputArray src,
OutputArray dst,
double alpha = 0,
double beta = 1,
int norm_type = NORM_MINMAX,
int dtype = -1,
InputArray mask = noArray()
);
NORM_MINMAX: 数组的数值被线性变换到alpha和beta之间(通常是0到1)。
NORM_L2 : :归一化后的值 = 像素值 / sqrt(所有像素值平方和)
NORM_INF : 归一化后的值 = 像素值 / 最大绝对值像素值
NORM_L1 : 归一化后的值 = 像素值 / (所有像素值绝对值的和)
calcHist( 统计图像像素
const Mat* images,
int nimages,
const int* channels, //需要统计哪些区域
InputArray mask,
SparseMat& hist,
int dims,
const int* histSize,
const float** ranges, //每个图像通道中灰度值的取值范围
bool uniform = true, //直方图是否均匀
bool accumulate = false //是否累积统计直方图,是否分别统计每个通道
);
equalizeHist( 直方图均衡化
InputArray src, 输入图像必须是8UC1
OutputArray dst
);
LUTLUT(图像直方图匹配,将图像分布映射为指定分布
InputArray src,
InputArray lut, 变换矩阵
OutputArray dst
);
matchTemplate(
InputArray image, 只能为8U或32F格式,两个输入图像类型必须相同
InputArray templ,
OutputArray result,
int method, 匹配方法
InputArray mask = noArray());
匹配方法
TM_SQDIFF = 0, 平方差匹配法
TM_SQDIFF_NORMED = 1, 归一化平方差匹配法
TM_CCORR = 2, 相关匹配法
TM_CCORR_NORMED = 3, 归一化相关匹配法
TM_CCOEFF = 4, 系数匹配法
TM_CCOEFF_NORMED = 5 归一化相关系数匹配法