一.
1.OpenCV读取视频并跳帧保存为图片
2.
二.
1.opencv 读取视频 VideoCapture类
(1)VideoCapture类的构造函数:
VideoCapture::VideoCapture(const string& filename) // filename – 打开的视频文件名。
VideoCapture::VideoCapture(int device) // device – 打开的视频捕获设备id ,如果只有一个摄像头可以填0,表示打开默认的摄像头。
(2) capture.open("dog.avi"); // 打开一个视频文件或者打开一个捕获视频的设备(也就是摄像头)
(3) capture.release(); // 关闭视频文件或者摄像头。
#include<opencv2\opencv.hpp>
using namespace cv;
int main()
{
VideoCapture capture("1.avi"); //读入视频
// 如果要读取摄像头,只需该这一句,其余都一样
// 改为: VideoCapture capture(0);
while(1) //循环显示每一帧
{
Mat frame; //定义一个mat变量,储存每一帧图像
capture>>frame; //读取当前帧
imshow(“读取视频”,frame); //显示当前帧
waitkey(30); //延时30秒
}
return 0;
}
2.Mat类 :用来保存图像和其他矩阵数据的数据结构
eg; Mat srcimage=imread("1.jpg"); //把“1.jpg”的图像载入到Mat类的一个变量srcimage中
3.imread() 图像的载入
imshow(name,"1.jpg") 图像的显示
imwrite(“name.jpg”,image) 输出图像到文件 //生成了一个图像image,把它保存为"name.jpg”文件
4.namedWindow(name,flags) 创建窗口
5 . 定义二维点 point2f p(2,3)
三维点 point3f p(2,3,4)
基于mat类的vector的: vector<float> v; v.push_back(3),.......
基于c++的vector:
vector<point2f> points(20);
for(size_t i=0;i<points.size();++i)
points[i]=point2f((float)(i*5),(float)(i%7);
cout<<points;
6. point类
Scalar类:颜色 如RGB三原色表示 Scalar(a,b,c) c,b,a分别为红绿蓝分量
Size类:尺寸 常用表宽度和高度 Size(5,5)
Rect类:矩形 成员变量有x,y,width,height
area()返回矩形面积, contains(Point)判断点是否在矩形内 inside(Rect)判断矩形是否在矩形内
tl()返回左上角的坐标, br()右下角坐标
矩形交集 rect1 & rect2 并集 rect1 | rect2
矩形平移&缩放
7.cvtColor() 颜色空间转换函数
void cvtColor(input src,output dst,int code ,int datcn=0)
input src 输入图像 output dst 输出图像 int code 颜色转换的标识符,查表 最后一个为目标图像的通道数,一般可省略
eg; cvtColor(srcimg,dstimg,COLOR_GRAY2BGR); //opencv3中标识符的CV_全被COLOR_代替
8.滑动条
创建:createTrackbar() int creatTrackbar(trackbar name,winname,int* value, int count, οnchange=0,0)
trackbar name 轨迹条的名字 ,winname 窗口的名字 , int* value, 指针,表示划块的位置 int count 表示滑块可以达到的最大位置 οnchange=0,默认值为0,其实是一个指向回调函数的指针
eg; createTrackbar("对比度",“效果窗口”,&g_nContrasrtValue ,300,on_change //是一个函数,要自己写)
9.鼠标操作
void SetMouseCallback( conststring&winname,...)
10.LUT函数
11.计时函数
time0 = ((double)getTickCount() - time0) / getTickFrequency();
12.访问图像中的像素
#include <opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
//全局函数声明
void colorReduce(Mat& inputImage, Mat& outputImage, int div);
int main()
{
Mat srcImage = imread("1.jpg");
Mat dstImage; //按原始图像的参数来创建效果图
dstImage.create(srcImage.rows, srcImage.cols, srcImage.type());
//记录起始时间 double time0 = static_cast<double>(getTickCount());
//调用颜色空间缩减函数
colorReduce(srcImage, dstImage, 32);
//计算运行时间并输出
time0 = ((double)getTickCount() - time0) / getTickFrequency();
imshow("效果图", dstImage);
waitKey(0);
return 0;
}
// colorReduce函数
// 【方法一】用指针访问像素
void colorReduce(Mat& inputImage, Mat& outputImage, int div)
{
outputImage = inputImage.clone(); //复制参数到临时变量
int rows = outputImage.rows;
int cols = outputImage.cols*outputImage.channels(); //列数*通道数=每一行元素的个数
for (int i = 0; i < rows; i++) //行循环
{
uchar* data = inputImage.ptr<uchar>(i); //获取第一行的首地址
for (int j = 0; j < cols; j++) //列循环
{ data[j] = data[j] / div*div + div / 2; //处理每一个像素
} } }
Mat的成员函数channels()返回图像的通道数 灰色图像为1 ,彩色为3
Mat类提供函数ptr可以得到图像任意行的首地址
// 【方法二】用迭代器
void colorReduce(Mat& inputImage, Mat& outputImage, int div)
{
outputImage=inputImage.clone();
//获取迭代器 <vec3b>三通道uchar类型的数组
Mat_<Vec3b>::iterator it=outputImage.begin<vec3b>(); //初始位置的迭代器
Mat_<vec3b>::iterator itend=outputImage.end<vec3b>(); //终止位置位置的迭代器
//存取彩色图像像素
for(;it!+itend;++it)
{ //处理每一个像素
(*it)[0]=(*it)[0]/div*div+div/2;
(*it)[1]=(*it)[0]/div*div+div/2;
(*it)[2]=(*it)[0]/div*div+div/2;
}
}
13.ROI区域图像叠加&混合
ROI:从图像中选取区域
// 【方法一】Rect
Mat imagePOI=image(Rect(500,200,logo.cols,logo.rows))
// 【方法二】range
Mat imageROI=image(Range(250,250+logo.rows),Range(200,200_logo.cols))
线性混合操作:addWeighted() 计算数组加权和函数
void addWeighted(input src1 //加权的第一个数组 ,double alpha //第一个数组权重 ,input src2 //加权的第二个数组 ,double beta //第二个权重 , double gamma // 加到权重总和上的标量值 ,output dst,int dtype=-1 //默认值-1,代表两个数组有相同的深度);
dst=src1[i]*alpha+src2[i]+gamma
bool ROI_LinearBlending()
{
double alphaValue=0.5;
double betaValue;
Mat src2,src3;
// 读取图像,两图像需为同样的类型和尺寸
src2=imread("2.jpg");
src3=imread("3.jpg");
if(!src2.data){print("读取src2错误\n");return false;}
if(!src3.data){print("读取src3错误\n");return false;}
//定义ROI区域
Mat imageROI;
imageROI=src3(rect(200,250,src2.cols,src2.rows));
// 做图像混合加权操作
betaValue=(1-alphaValue);
addWeight(imageROI,alphaValue,src3,betavalue,0.0,imageROI);
imshow......
return ture;
}
14.分离颜色通道:
void split(input m// 需要分离的多通道数组,output mv// 输出数组或vector);
通道合并:
void merge(input mv //输入要合并的矩阵 ,output dst //输出);
vector<Mat> channels;
Mat imgBlueChannel;
Mat imgGreenChannel;
Mat imgRedChannel;
src1=imread("1.jpg");
split(src1,channels);//分离色彩通道
imgBlueChannel=channels.at(0); //Mat::at对某个通道(数组)存取
imgGreenChannel=channels.at(1);
imgRedChannel=channels.at(2);
15.图像对比度,亮度值调整
理论依据:g(i,j)=a*f(i,j)+b; f(x)输入,g(x)输出。a增益,控制图像对比度,b偏置,控制图像亮度
// 全局函数声明
static void on_ContrastAndBright(int,void*);
static void ShowHelpText();
//全局变量
int g_nContrastValue; //对比度
int g_nBrightValue; //亮度值
Mat g_src,g_dst;
int main()
{
g_src=imread("1.jpg");
g_dst=Mat::zeros(g_src.size(),g_src.typr());
//设置初值
g_nContrastValue=80;
g_nBrightValue=80;
nameWindow("效果图窗口",1);
createTrackbar("对比度",“效果图窗口”,& g_nContrastValue,300,on_ContrastAndBright);
createTrackbar("亮度","效果图窗口",&g_nBrightValue,200,on_ContrastAndBright);
// 进行回调函数初始化
on_ContrastAndBright(g_nContrastValue,0);
on_ContrastAndBright(g_nBrightValue,0);
// 按下“q”键,程序退出
while(char(waitKey(1)!='q'){}
return 0;
}
//on_ContrastAndBright 改变图像对比度和亮度值的回调函数
static void on_ContrastAndBright(int,voud*)
{
nameWindow("原始窗口",1);
//三个for循环,执行运算g_dst(i,j)=a*g_src(i,j)+b;
for(int y=0;y<g_src.rows;y++)
{
for(int x=0;x<g_src.cols;x++)
{
g_dst.at<vec3b>(y,x)[c]=saturate_cast<uchar>((g_nContrastValue*0.01)*(g_src.at<vec3b>(y,x)[c])+g_nBrightValue);
} //image.at<vec3b>(y,x)[c] y,x 为像素所在的行和列, c为RGB(对应0 1 2)中之一
}
}
imshow...
saturate_cast 由于运算结果可能会溢出,还可能是非整数,用此对结果转换,保证为有效值
a 为对比度取0.0到3.0 但滑动条是整数,所以将g_nContrastValue参数设置为0到300之间,再*0.01
三. 图像处理
1. 方框滤波 (box Filter)
void boxFilter(input src, output dst ,int ddepth //输出图像的深度,-1为原图像深度 ,Size ksize //内核的大小,Size(w,h) w为像素宽度,h为像素的高度 ,Point anchor=Point(-1,-1) //锚点,即被平滑的那个点 ,boolnormalizae=true //表示内核是否被归一化 ,int borderType=BORDER_DEFAULT //一般不管)
eg..boxFilter(img,out,-1,size(5,5))
2.均值滤波 :boolnormalizae=true 被归一化的方框滤波
void bulr(input src, output dst ,Size ksize //内核的大小,Size(w,h) w为像素宽度,h为像素的高度
Point anchor=Point(-1,-1) //锚点,即被平滑的那个点 int borderType=BORDER_DEFAULT //一般不管)
eg.. blur(img,out,size(7,7))
3.高斯滤波
void GaussianBlur(input src,output dst,Szie ksize //必须为整数或者奇数,或是0,由 sigma算出 , double sigmaX //高斯核函数在X方向上的标准偏差 , double sigmaY=0, intborderType=BORDER_DEFAULT)
eg..GaussianBlur(img,ot,Size(3,3),0,0)
4.中值滤波
void medianBlur(src,dst,int ksize //孔径的线性尺寸,必须是大于1的奇数)
5.双边滤波
void bilaterFilter (src,dst, int d //每个像素邻域的直径 ,double sigmaColor // ,double sigmaSpace // , int borderType=BORDER_DEFAULT)
6.膨胀
void dilate(src,dst, kernel // 膨胀操作的核,一般配合函数getStructuringElement, Point anchor, int iteration=-1// 迭代器的使用次数,默认为1, )
getStructuringElement(内核形状,size 内核尺寸,point 锚点位置)
形状参数:MORPH_RECT 矩形
MORPH_CROSS 交叉形
MORPH_ELLIPSE 椭圆形
Mat element=getStructuringElement(MORPH_RECT,Szize(5,5));
dialte(img,out,element)
7.腐蚀
void erode(src,dst,,kernel,point...)
操作类膨胀
8.开运算:即先腐蚀后膨胀,可以用来消除小物体,在纤细点出分离物体
dst=open(src,element)=dilate(erode(src,element));
8.闭运算
dst=close(src,element)=erode(dilate(src,element));
9.形态学梯度
dst=
四. 图像变换
1.Canny边缘检测
void Canny(src,rdges // 输出的边缘图像,和原图一样的尺寸和类型 ,double threshold1 //第一个滞后性阀值 ,double threshold2 // 第二个, int apertureSize=3 //默认值3 ,bool...=false )
eg..canny(src,src,3,9,3)
2.sobel算子
void Sobel(src,dst, int ddepth// 图像深度,支持src.depth() , int dx// x上差分阶数 , int dy// y上, int ksize=3,// 默认值3 double scale=1. double delta=0,int border....// 后三个均为默认值)
当内核大小为3时,有较大误差,大多数情况下使用,取[xorder=1,yorder=0,ksize=3]来计算x方向的导数,[xorder=0,yorder=1,ksize=3]来计算y方向上的导数
//创建grad_x,y矩阵
Mat grad_x,grad_y;
Mat abs_grad_x,abs_grad_y,dst;
//求x方向上的导数
Sobel(src,grad_x,CV_16S,1,0,3,1,1,BORDER_DEFAULT);
convertScaleAbs(grad_x,abs_grad_x); //转换为8未uchar
imshow("X方向上的Sobel",abs_grad_x);
//求Y方向上的导数
Sobel(src,grad_y,CV_16S,0,1,3,1,1,BORDER_DEFAULT);
convertScaleAbs(grad_y,abs_grad_y); //转换为8未uchar
imshow("y方向上的Sobel",abs_grad_y);
//合并梯度
addWeighted(abs_grad_x,0.5,abs_grad_y,0.5,0.dst);
imshow("整体方向的Sobel",dst);
waitKey(0);
return 0;
}
3.Laplacian算子: 内部调用Sobel算子来计算x,y的导数
void Laplacian(src,dst,int ddepth, int ksize=1//默认值 ,double scale=1. double delta=0,int border....// 后三个均为默认值)
五. 图像轮廓
1.寻找轮廓 findContours()
void findContours(img, contours// 检测到的轮廓存在这里,每个轮廓储存为一个点向量, hierarchy// 可选的输出向量,int mode, // 轮廓检索模式 int method// 轮廓的近似方法 ,Point offset=Point ()// 默认值)
void drawContours(img, Contours, int ContourIdx // 轮廓绘制的指示变量,负值则绘制所有轮廓 , const Scalsr& color // 轮廓的颜色, int thickness=1// 线条的粗细程度 , int lineType=8, intput hierarchy=noArray(), int maxLevel=TNT_MAX,Point offset=Point ()// 后几个都默认值)
//载入图像,必须以二值图模式载入
Mat src=imread("1.jpg",0);
Mat dst=Mat:: zeros(src.rows,src.cols,CV_8UC3); //初始化结果图
src=src>119; //src取大于阀值119的部分
//定义轮廓和层次结构
vector<vector<Point>>Contours;
vector<vec4>hierarchy;
//查找轮廓
findContours(src,contours,hierarchy,RETR_CCOMP,CHAIN_APPROX_SIMPLE);
//遍历所有顶层轮廓
int index=0;
for(;index>=0;index=hierarchy[index][0])
{
Scalar color(rand()&255,rand()&255,rand()&255);
drawContours(dst,contours,index,color,FILLED,8,hierarchy);}
2. 凸包
寻找凸包 void convexHull(points// 输入的二维点集, hull // 调用后找到的凸包,bool clockwise=false //true 为顺时针,false则逆时针 ,bool returnPoints=true// 默认可忽略);
3. 使用多边形将轮廓包围
Rect boundingRect(input Points); //返回指定点集最外面的矩形边界
RotatedRect minAreaRect(input Point); //寻找可旋转的最小面积的包围矩形
void minEnclosingCircle(input points,Point2f¢er, //圆的输出圆心 float&radius// 圆的输出半径) //寻找最小包围圆形
void approxPolyDP(input curve //输入的二维点集 ,output approxCurve //多边形逼近的结果 , double epsilon // 逼近的精度, bool closed //如果为真则为封闭曲线 ) //逼近多边形曲线
// 全局变量的声明
Mat g_srcimg;
Mat g_grayimg;
int g_nThresh=50; //阀值
int g_nMaxThresh=255; //阀值最大值
RNG g_rng(12345); //随机数生成器
// 全局函数的声明
void on_ContoursChange(int ,void*);
static void ShowHelpText();
//得到原图的灰度图像并进行平滑
cvtColor (g_srcimg,g_grayimg,COLOR_BGR2GRAY);
blur(g_grayimg,g_grayimg,Size(3,3));
//创建原始窗口并显示
namedWindow("效果图",WINDOE——AUTOSIZE);
imshow("效果图", g_srcimg);
createTrackbar("阈值 ", "效果图", &g_nThresh, g_nMaxThresh,on_COntoursChange);
on_COntoursChange(0, 0);
waitKey(0);
return 0; }
//回调函数
void on_ContoursChange(int,void*)
{
Mat threshold_output;
vector<vector<Point>>contours;
vector<Vec4>hierarchy;
threshold(g_grayimg,threshold_output,g_nThresh,255,THRESH_BINARY); //使用threshold 检测边缘
findContours(threshold_output,contours,hierarchy,RETR_TREE,CHAIN_APPROX_SIMPLE,Point(0,0)); //找出轮廓
//多边形逼近轮廓 + 获取矩形和圆形边界框
vector<vector<Point>>contours_poly(contours.size());
vect<Rect>boundRect(contours.size());
vector<Point2f>center(contours.size());
vector<float>radius(contours.size());
//本程序最核心的操作,一个循环,遍历所有部分
for(unsigned int i=0;i<contours.size();i++)
{
approxPolyDP(Mat(contours[i],contours_poly[i],3,true); //用指定精度逼近多边形曲线
boundRect[i]=boundingRect(Mat(contours_poly[i])); //最外面的矩形界面
minEnclosingCircle(contours_poly[i],center[i],radius[i]);
//绘制多边形轮廓+包围的矩形框+圆形框
Mat drawing =