一.

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&center,  //圆的输出圆心   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 =