我们很容易利用opencv打开摄像头捕捉视频
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/core/core.hpp>
using namespace cv;
int main()
{
VideoCapture cap(0);
if(!cap.isOpened())
{
return -1;
}
Mat frame;
Mat edges;
bool stop = false;
while(!stop)
{
cap>>frame;
//cvtColor(frame, edges, CV_BGR2GRAY);
// GaussianBlur(edges, edges, Size(7,7), 1.5, 1.5);
//Canny(edges, edges, 0, 30, 3);
imshow("当前视频",frame);
if(waitKey(30) >=0)
stop = true;
}
return 0;
}
VideoCapture类有两种用法,一种是VideoCapture(const string& filename)用来打开视频文件,一种是VideoCapture(int device)用来打开设备。
根据自己的需要选择合适的参数,注释的部分就是如果你想得到的是一个边缘图像的话可以这样使用将其canny一下简单解决
opencv中间给出了很多对视频处理的函数,比如说我们关心的视频有多少帧以及fps等等
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/core/core.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
//打开视频文件:其实就是建立一个VideoCapture结构
VideoCapture capture("/usr/share/example-content/Ubuntu_Free_Culture_Showcase/How fast.ogg");
//检测是否正常打开:成功打开时,isOpened返回ture
if(!capture.isOpened())
cout<<"fail to open!"<<endl;
//获取整个帧数
long totalFrameNumber = capture.get(CV_CAP_PROP_FRAME_COUNT);
cout<<"整个视频共"<<totalFrameNumber<<"帧"<<endl;
//设置开始帧()
long frameToStart = 300;
capture.set( CV_CAP_PROP_POS_FRAMES,frameToStart);
cout<<"从第"<<frameToStart<<"帧开始读"<<endl;
//设置结束帧
int frameToStop = 400;
if(frameToStop < frameToStart)
{
cout<<"结束帧小于开始帧,程序错误,即将退出!"<<endl;
return -1;
}
else
{
cout<<"结束帧为:第"<<frameToStop<<"帧"<<endl;
}
//获取帧率
double rate = capture.get(CV_CAP_PROP_FPS);
cout<<"帧率为:"<<rate<<endl;
//定义一个用来控制读取视频循环结束的变量
bool stop = false;
//承载每一帧的图像
Mat frame;
//显示每一帧的窗口
namedWindow("Extracted frame");
//两帧间的间隔时间:
//int delay = 1000/rate;
int delay = 1000/rate;
//利用while循环读取帧
//currentFrame是在循环体中控制读取到指定的帧后循环结束的变量
long currentFrame = frameToStart;
//滤波器的核
int kernel_size = 3;
Mat kernel = Mat::ones(kernel_size,kernel_size,CV_32F)/(float)(kernel_size*kernel_size);
while(!stop)
{
//读取下一帧
if(!capture.read(frame))
{
cout<<"读取视频失败"<<endl;
return -1;
}
//这里加滤波程序
//imshow("Extracted frame",frame);
//filter2D(frame,frame,-1,kernel);
imshow("after filter",frame);
cout<<"正在读取第"<<currentFrame<<"帧"<<endl;
//waitKey(int delay=0)当delay ≤ 0时会永远等待;当delay>0时会等待delay毫秒
//当时间结束前没有按键按下时,返回值为-1;否则返回按键
int c = waitKey(delay);
//按下ESC或者到达指定的结束帧后退出读取视频
if((char) c == 27 || currentFrame > frameToStop)
{
stop = true;
}
//按下按键后会停留在当前帧,等待下一次按键
if( c >= 0)
{
waitKey(0);
}
currentFrame++;
}
//关闭视频文件
capture.release();
waitKey(0);
return 0;
}
如果你的视频有遭遇的话可以利用滤波将其平滑一下就可以
看了很多别人的博文以及书感觉对于LUT以及直方图均衡话不是很了解
这里转一下别人的博文看一看http://blog.csdn.net/thefutureisour/article/details/7532765
首先建立一个类:
- class Histogram1D
- {
- private:
- //直方图的点数
- int histSize[1];
- //直方图的范围
- float hranges[2];
- //指向该范围的指针
- const float* ranges[1];
- //通道
- int channels[1];
- public:
- //构造函数
- Histogram1D()
- {
- histSize[0] = 256;
- hranges[0] = 0.0;
- hranges[1] = 255.0;
- ranges[0] = hranges;
- channels[0] = 0;
- }
在OpenCV中,使用calcHist计算直方图
- Mat getHistogram(const Mat &image)
- {
- Mat hist;
- //计算直方图函数
- //参数为:源图像(序列)地址,输入图像的个数,通道数,掩码,输出结果,直方图维数,每一维的大小,每一维的取值范围
- calcHist(&image,1,channels,Mat(),hist,1,histSize,ranges);
- return hist;
- }
但是,返回的结果并不是我们希望的“直方图”,hist只是记录了每个bin下的像素个数。我们需要自己利用line函数画图:
- Mat getHistogramImage(const Mat &image)
- {
- //首先计算直方图
- Mat hist = getHistogram(image);
- //获取最大值和最小值
- double maxVal = 0;
- double minVal = 0;
- //minMaxLoc用来获得最大值和最小值,后面两个参数为最小值和最大值的位置,0代表不需要获取
- minMaxLoc(hist,&minVal,&maxVal,0,0);
- //展示直方图的画板:底色为白色
- Mat histImg(histSize[0],histSize[0],CV_8U,Scalar(255));
- //将最高点设为bin总数的90%
- int hpt = static_cast<int>(0.9*histSize[0]);
- //为每一个bin画一条线
- for(int h = 0; h < histSize[0];h++)
- {
- float binVal = hist.at<float>(h);
- int intensity = static_cast<int>(binVal*hpt/maxVal);
- //int intensity = static_cast<int>(binVal);
- line(histImg,Point(h,histSize[0]),Point(h,histSize[0]-intensity),Scalar::all(0));
- }
- return histImg;
- }
函数中对亮度进行了“压缩”,主要目的是让直方图能够更好的显示在画板上。
查找表,就是一个一对一或者多对一函数,指定了一个亮度经过查找表以后变成另外一个像素。在OpenCV中,使用LUT函数来实现
- Mat applyLookUp(const Mat& image,const Mat& lookup)
- {
- Mat result;
- LUT(image,lookup,result);
- return result;
- }
而变化的具体内容,依赖于你自己定义的查找表,比如,如果你想让查找表的结果为当前图像的翻转,可以在main函数中定义查找表为:
- //用查找表翻转图像灰度
- int dim(256);
- Mat lut(1,&dim,CV_8U);
- for(int i = 0; i < 256; i++)
- {
- lut.at<uchar>(i) = 255-i;
- }
- imshow("灰度翻转后的图像",h.applyLookUp(image,lut));
当你想让图像经过查找表以后直方图拉伸,变得效果好一点,可以这样:
将个数低于指定数目(默认为0)的bin舍去,剩下的最小值变为0,最大值变为255,中间的部分线性拉伸:
- Mat strech(const Mat &image,int minValue = 0)
- {
- //首先计算直方图
- Mat hist = getHistogram(image);
- //左边入口
- int imin = 0;
- for(;imin< histSize[0];imin++)
- {
- cout<<hist.at<float>(imin)<<endl;
- if(hist.at<float>(imin) > minValue)
- break;
- }
- //右边入口
- int imax = histSize[0]-1;
- for(;imax >= 0; imax--)
- {
- if(hist.at<float>(imax) > minValue)
- break;
- }
- //创建查找表
- int dim(256);
- Mat lookup(1,&dim,CV_8U);
- for(int i = 0; i < 256; i++)
- {
- if(i < imin)
- {
- lookup.at<uchar>(i) = 0;
- }
- else if(i > imax)
- {
- lookup.at<uchar>(i) = 255;
- }
- else
- {
- lookup.at<uchar>(i) = static_cast<uchar>(255.0*(i-imin)/(imax-imin)+0.5);
- }
- }
- Mat result;
- result = applyLookUp(image,lookup);
- return result;
- }
当然,这样的效果还不是最好的,最好的均衡应该使得直方图非常平缓,每个bin中的数目差不多,在OpenCV中,使用equalizeHist函数可以实现直方图均衡功能:
- Mat equalize(const Mat &image)
- {
- Mat result;
- equalizeHist(image,result);
- return result;
- }
有了上面定义的类,我们main函数就变得简单多了:
- #include "histogram.h"
- int main()
- {
- //以灰度方式读取图像
- Mat image = imread("D:/picture/images/group.jpg",0);
- imshow("源灰度图像",image);
- if (!image.data)
- return -1;
- Histogram1D h;
- imshow("直方图",h.getHistogramImage(image));
- //用查找表翻转图像灰度
- int dim(256);
- Mat lut(1,&dim,CV_8U);
- for(int i = 0; i < 256; i++)
- {
- lut.at<uchar>(i) = 255-i;
- }
- imshow("灰度翻转后的图像",h.applyLookUp(image,lut));
- //用查找表拉伸图像灰度值
- //忽略那些个数少于100个像素的bin
- Mat strech = h.strech(image,100);
- imshow("拉伸后的图像",strech);
- imshow("拉伸后的直方图",h.getHistogramImage(strech));
- //图像均衡
- Mat afterEqualize = h.equalize(image);
- imshow("均衡后的解果",afterEqualize);
- imshow("均衡后的直方图",h.getHistogramImage(afterEqualize));
- waitKey(0);
- return 0;
- }