如题:使用opencv打开摄像头或视频文件,实时显示原始视频,将视频每一帧依次做灰度转换、高斯滤波、canny边缘检测处理(原始视频和这3个中间步骤处理结果分别在一个窗口显示),最后将边缘检测结果保存为一个视频avi文件。

这里问题综合性比较大,这里进行分治。

该类问题可分为四个方面的处理:

(1)打开 视频或者是摄像头,并播放视频

(2)对视频的每一帧做处理

(3)同窗体显示四个结果

(4)保存视频文件

以下分为这三个方面进行处理:

(1)打开 视频或者摄像头,并播放视频

这个利用opencv来说算是非常简单的操作了:

步骤分为四步:(简单操作,播放效果不是最佳的,适用于入门)

a.创建摄像头/播放器

b.将视频文件赋值给播放器

c.逐帧播放

d.释放播放器和文件

这里直接给上源码(面向对象的方法):

 /******************************************************
文件名 :main.cpp
描 述 :灰度转换、高斯滤波、canny边缘检测处理视频,并存储canny边缘处理的视频
语 言 :c++
作 者 :重交亲爸爸
修 改 :
日 期 :2018-05-10
说 明 :opencv的支持
******************************************************/
#include <cv.h>
#include <stdio.h>
#include <stdarg.h>
#include <time.h>
#include<opencv2\highgui\highgui.hpp>
#include<opencv2\imgproc\imgproc.hpp>
#include<opencv2\core\core.hpp>
using namespace cv;
using namespace std;
/******************************************************
类 名 :Myclass
描 述 :灰度转换、高斯滤波、canny边缘检测处理视频,并存储canny边缘处理的视频
语 言 :
作 者 :
修 改 :
日 期 :2018-05-10
说 明 :
******************************************************/
class MyClass
{
public:
MyClass(char* argv);
~MyClass();
void play();//播放
private:
CvCapture* capture;//视频播放器
};
/******************************************************
函数名称: MyClass
函数功能: 初始化
传入参数:
返 回 值:
建立时间: 2018-05-10
修改时间:
建 立 人:
修 改 人:
其它说明:
******************************************************/
MyClass::MyClass(char* argv)
{
//capture = cvCreateFileCapture(argv[1]);
capture = cvCreateFileCapture(argv);
if (!cvGetCaptureProperty(capture, CAP_PROP_FRAME_COUNT))
{
exit();
}
}
/******************************************************
函数名称: ~MyClass
函数功能: 释放空间
传入参数:
返 回 值:
建立时间: 2018-05-10
修改时间:
建 立 人:
修 改 人:
其它说明:very important
******************************************************/
MyClass::~MyClass()
{
cvReleaseCapture(&capture);
capture = NULL;
}
/******************************************************
函数名称: play
函数功能: 播放
传入参数:
返 回 值:
建立时间: 2018-05-10
修改时间:
建 立 人:
修 改 人:
其它说明:
******************************************************/
void MyClass::play(){
cvNamedWindow("播放页面", );
IplImage* frame;
while (true)
{
frame = cvQueryFrame(capture);
if (!frame)break;
cvShowImage("播放页面",(frame));
char c = cvWaitKey();
if (c == )break;//Esc的编码为27
}
}
int main(int argc,char** argv){
//char* a = "F:\\Pictures\\fcq.avi";
//char* b = "F:\\Pictures\\fcq2.avi";
if (argc > ){
MyClass *myclass = new MyClass(argv[]);
myclass->play();
delete myclass;
}
else{
printf("无视频或者录像存储空间");
exit();
}
return ;
}

使用vs2013生成解决方案后,打开window power shell进行测试。寻找到文件夹,打开相应的可执行文件

测试结果:

ok.你已经成功完成第一步了。^.^

(2)对视频的每一帧做处理

a.高斯滤波

百度百科的解释:高斯滤波是一种线性平滑滤波,适用于消除高斯噪声,广泛应用于图像处理的减噪过程。通俗的讲,高斯滤波就是对整幅图像进行加权平均的过程,每一个像素点的值,都由其本身和邻域内的其他像素值经过加权平均后得到。高斯滤波的具体操作是:用一个模板(或称卷积、掩模)扫描图像中的每一个像素,用模板确定的邻域内像素的加权平均灰度值去替代模板中心像素点的值。

这里有opencv封装好的方法可以直接操作,这里采用的是cvSmooth的方法,然后填入核函数CV_GAUSSIAN,设置图像源和转变后的接收源。

 /******************************************************
函数名称: R_Gussian
函数功能: 返回高斯滤波处理
传入参数:
返 回 值:
建立时间: 2018-05-10
修改时间:
建 立 人:
修 改 人:
其它说明:
******************************************************/
IplImage* MyClass::R_Gussian(IplImage* frame){
//IplImage* edges = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, image->nChannels);
IplImage* edges = cvCreateImage(cvGetSize(frame), frame->depth, frame->nChannels);
cvSmooth(frame, edges, CV_GAUSSIAN, , frame->nChannels); // Gauss平滑滤波,核大小为7x7
return edges;
}

按照(1)中进行测试,结果:

看上去有点模糊了。

b.灰度变换

百度百科的解释:灰度变换是指根据某种目标条件按一定变换关系逐点改变源图像中每一个像素灰度值的方法。目的是为了改善画质,使图像的显示效果更加清晰。 图像的灰度变换处理是图像增强处理技术中的一种非常基础、直接的空间域图像处理方法,也是图像数字化软件和图像显示软件的一个重要组成部分。

同理,opencv也提供的灰度变化的函数,这里要注意的是转变的时候都是通道变成1

/******************************************************
函数名称: R_Gray
函数功能: 返回灰度处理
传入参数:
返 回 值:
建立时间: 2018-05-10
修改时间:
建 立 人:
修 改 人:
其它说明:由于需要在同一个窗体显示,需要将通道数目统一,不能使用单通道
******************************************************/
IplImage* MyClass::R_Gray(IplImage* frame){
//IplImage* edges = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1);
//IplImage *frame_gray = cvCreateImage(cvGetSize(image), frame->depth, 1);
/*IplImage* edges = cvCreateImage(cvGetSize(imagesrc), imagesrc->depth, imagesrc->nChannels);
cvCvtColor(frame, edges, CV_BGR2GRAY);
return edges;*/ IplImage *frame_gray = cvCreateImage(cvGetSize(frame), frame->depth, );
IplImage *frame1 = cvCreateImage(cvGetSize(frame), frame->depth, frame->nChannels);
cvCvtColor(frame, frame_gray, CV_RGB2GRAY);
cvCvtColor(frame_gray, frame1, CV_GRAY2BGR);//见说明
return frame1;
}

这里多一步的目的是为了后面多个图像显示在一块窗口上(如果不考虑同窗体显示的话就不需要统一通道数)

结果测试:

灰度效果显示出来了。

c.Canny边缘检测

百度百科的解释:Canny 算法使用 4 个 mask 检测水平、垂直以及对角线方向的边缘。原始图像与每个 mask 所作的卷积都存储起来。对于每个点我们都标识在这个点上的最大值以及生成的边缘的方向。

这里使用cvCanny的方法进行转变,但是这个cvCanny边缘检测还需要弄成灰度图。

 /******************************************************
函数名称: R_Canny
函数功能: 返回Canny边缘处理
传入参数:
返 回 值:
建立时间: 2018-05-10
修改时间:
建 立 人:
修 改 人:
其它说明: 由于需要在同一个窗体显示,需要将通道数目统一,不能使用单通道
******************************************************/
IplImage* MyClass::R_Canny(IplImage* frame){
//IplImage* edges = cvCreateImage(cvGetSize(grayimage), IPL_DEPTH_8U, 1);
IplImage *frame_gray = cvCreateImage(cvGetSize(frame), frame->depth, );
IplImage *frame1 = cvCreateImage(cvGetSize(frame), frame->depth, frame->nChannels);
cvCanny(frame, frame_gray, , , );
cvCvtColor(frame_gray, frame1, CV_GRAY2BGR);
return frame1;
}

同样也要统一通道数。

测试结果:

这样我们三个图像处理就完成了。^.^

(3)同窗体显示四个结果

这里参考了CSDN上的一个方法https://blog.csdn.net/augusdi/article/details/9019473

作者稍作整理了下,站在巨人的肩膀上。

 /******************************************************
函数名称: cvShowManyImages
函数功能: 展示多个图片
传入参数: const char* title, int nArgs
返 回 值:
建立时间: 2018-05-10
修改时间:
建 立 人: CSDN Augusdi
修 改 人:
其它说明:
******************************************************/
void MyClass::cvShowManyImages(const char* title, int nArgs, ...){
// img - Used for getting the arguments
IplImage *img; // DispImage - the image in which input images are to be copied
IplImage *DispImage; int size;
int i;
int m, n;
int x, y; // w - Maximum number of images in a row
// h - Maximum number of images in a column
int w, h; // scale - How much we have to resize the image
float scale;
int max; // If the number of arguments is lesser than 0 or greater than 12
// return without displaying
if (nArgs <= ) {
printf("Number of arguments too small....n");
return;
}
else if (nArgs > ) {
printf("Number of arguments too large....n");
return;
}
// Determine the size of the image,
// and the number of rows/cols
// from number of arguments
else if (nArgs == ) {
w = h = ;
size = ;
}
else if (nArgs == ) {
w = ; h = ;
size = ;
}
else if (nArgs == || nArgs == ) {
w = ; h = ;
size = ;
}
else if (nArgs == || nArgs == ) {
w = ; h = ;
size = ;
}
else if (nArgs == || nArgs == ) {
w = ; h = ;
size = ;
}
else {
w = ; h = ;
size = ;
} // Create a new 3 channel image
DispImage = cvCreateImage(cvSize( + size*w, + size*h), , ); // Used to get the arguments passed
va_list args;
va_start(args, nArgs); // Loop for nArgs number of arguments
for (i = , m = , n = ; i < nArgs; i++, m += ( + size)) { // Get the Pointer to the IplImage
img = va_arg(args, IplImage*); // Check whether it is NULL or not
// If it is NULL, release the image, and return
if (img == ) {
printf("Invalid arguments");
cvReleaseImage(&DispImage);
return;
} // Find the width and height of the image
x = img->width;
y = img->height; // Find whether height or width is greater in order to resize the image
max = (x > y) ? x : y; // Find the scaling factor to resize the image
scale = (float)((float)max / size); // Used to Align the images
if (i % w == && m != ) {
m = ;
n += + size;
} // Set the image ROI to display the current image
cvSetImageROI(DispImage, cvRect(m, n, (int)(x / scale), (int)(y / scale))); // Resize the input image and copy the it to the Single Big Image
cvResize(img, DispImage); // Reset the ROI in order to display the next image
cvResetImageROI(DispImage);
} // Create a new window, and show the Single Big Image
//cvNamedWindow( title, 1 );
cvShowImage(title, DispImage); //cvDestroyWindow(title); // End the number of arguments
va_end(args); // Release the Image Memory
cvReleaseImage(&DispImage);
}

这里加入一个多视频播放处理:

/******************************************************
函数名称: Multi_play
函数功能: 播放
传入参数:
返 回 值:
建立时间: 2018-05-10
修改时间:
建 立 人:
修 改 人:
其它说明:
******************************************************/
void MyClass::Multi_play(){
IplImage *frame;
cvNamedWindow("播放页面按Esc退出", );
cvResizeWindow("播放页面按Esc退出", , );
while (true)
{
frame = cvQueryFrame(capture);
if (!frame)break;
IplImage* grayimage = R_Gray(frame);
IplImage* gsimage = R_Gussian(frame);
IplImage* cnimage = R_Canny(frame);
//IplImage *frame_not = cvCreateImage(cvGetSize(frame), frame->depth, frame->nChannels);//负片
//cvNot(frame, frame_not);
//cvShowImage("播放页面按Esc退出", R_Canny(R_Gray(frame)));
//cvWriteFrame(writer, cnimage);
cvShowManyImages("播放页面按Esc退出", , frame, grayimage, gsimage, cnimage);
char c = cvWaitKey();
if (c == )break; cvReleaseImage(&grayimage);
cvReleaseImage(&gsimage);
cvReleaseImage(&cnimage);
//cvReleaseImage(&frame_not);
}
}

结果测试:

成功生成,这里注意一点就是如果放入的图片不是同一通道的话,会报错。

(4)保存视频文件

保存视频就比较简单了。

a.创建视频记录器              CvVideoWriter* writer;

b.初始化视频记录器           如初始化代码所示

c.视频记录器记录每一帧    如播放功能代码所示

d.释放视频记录器              如释放代码所示

 /******************************************************
函数名称: MyClass
函数功能: 初始化
传入参数:
返 回 值:
建立时间: 2018-05-10
修改时间:
建 立 人:
修 改 人:
其它说明:
******************************************************/
MyClass::MyClass(char* argv,char* filepath)
{
//capture = cvCreateFileCapture(argv[1]);
capture = cvCreateFileCapture(argv);
if (!cvGetCaptureProperty(capture, CAP_PROP_FRAME_COUNT))
{
exit();
}
double fps = cvGetCaptureProperty(capture, CV_CAP_PROP_FPS);
CvSize size = cvSize(
(int)cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH),
(int)cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT)
);
writer = cvCreateVideoWriter(
filepath,
CV_FOURCC('M', 'J', 'P', 'G'),
fps,
size
);
}
/******************************************************
函数名称: ~MyClass
函数功能: 释放空间
传入参数:
返 回 值:
建立时间: 2018-05-10
修改时间:
建 立 人:
修 改 人:
其它说明:
******************************************************/
MyClass::~MyClass()
{
cvReleaseVideoWriter(&writer);
cvReleaseCapture(&capture);
writer = NULL;
capture = NULL;
}
/******************************************************
函数名称: Multi_play
函数功能: 播放
传入参数:
返 回 值:
建立时间: 2018-05-10
修改时间:
建 立 人:
修 改 人:
其它说明:
******************************************************/
void MyClass::Multi_play(){
IplImage *frame;
cvNamedWindow("播放页面按Esc退出", );
cvResizeWindow("播放页面按Esc退出", , );
while (true)
{
frame = cvQueryFrame(capture);
if (!frame)break;
IplImage* grayimage = R_Gray(frame);
IplImage* gsimage = R_Gussian(frame);
IplImage* cnimage = R_Canny(frame);
IplImage *frame_not = cvCreateImage(cvGetSize(frame), frame->depth, frame->nChannels);
cvNot(frame, frame_not);
//cvShowImage("播放页面按Esc退出", R_Canny(R_Gray(frame)));
cvWriteFrame(writer, cnimage);
cvShowManyImages("播放页面按Esc退出", , frame, grayimage, gsimage, cnimage);
char c = cvWaitKey();
if (c == )break; cvReleaseImage(&grayimage);
cvReleaseImage(&gsimage);
cvReleaseImage(&cnimage);
cvReleaseImage(&frame_not);
}
}

ok,在window power shell输入的时候要加上保存地址了

视频停止或者终止后,在相应文件下就生成了新文件.avi了

如需要源码请转移至码云:https://gitee.com/cjqbaba/MediaTest/tree/Capture_show进行源码克隆下载

如有问题请留言评论。转载请注明出处,谢谢。

基于opencv下对视频的灰度变换,高斯滤波,canny边缘检测处理,同窗体显示并保存的更多相关文章

  1. c++开发ocx入门实践三--基于opencv的简易视频播发器ocx

    原文:http://blog.csdn.net/yhhyhhyhhyhh/article/details/51404649  利用opencv做了个简易的视频播放器的ocx,可以在c++/c#/web ...

  2. 基于opencv网络摄像头在ubuntu下的视频获取

     基于opencv网络摄像头在ubuntu下的视频获取 1  工具 原料 平台 :UBUNTU12.04 安装库  Opencv-2.3 2  安装编译运行步骤 安装编译opencv-2.3  参 ...

  3. 基于OpenCv和swing的图片/视频展示Java实现

    基于OpenCv和swing实现图片/视频的展示 图片的展示 swing展示图片,多为操作BufferedImage,这里要关注的核心是将Mat转为BufferedImage. 代码如下: publi ...

  4. 基于opencv将视频转化为字符串Java版

    基于opencv将视频转化为字符串Java版 opencv java  先上一个效果图吧 首先,弄清一下原理 我们要将视频转化为字符画,那么就需要获取画面的每一帧,也就是每一张图片,然后将图片进行转化 ...

  5. 基于opencv在摄像头ubuntu根据视频获取

     基于opencv在摄像头ubuntu根据视频获取 1  工具 原料 平台 :UBUNTU12.04 安装库  Opencv-2.3 2  安装编译执行步骤 安装编译opencv-2.3  參考h ...

  6. 基于OpenCV实现对图片及视频中感兴趣区域颜色识别

    基于OpenCV实现图片及视频中选定区域颜色识别 近期,需要实现检测摄像头中指定坐标区域内的主体颜色,通过查阅大量相关的内容,最终实现代码及效果如下,具体的实现步骤在代码中都详细注释,代码还可以进一步 ...

  7. 基于OpenCV之视频读取,处理和显示框架的搭建(一)

    主要包括以下内容: 1.使用的主要函数的说明. 2.两个实例:视频读取和显示.搭建视频读取和处理框架,调用canny函数提取边缘并显示. 3.一些注意事项和代码说明. 一.使用的主要函数 1.延时函数 ...

  8. 基于Opencv的简单图像处理

    实验环境 本实验均在笔记本电脑完成,电脑的配置如表1所示: 系统 Windows 10 家庭版 处理器 英特尔 Core i5-6200 @ 2.30GHz 双核 主板 宏碁 Zoro_SL 内存 1 ...

  9. 基于OpenCV的火焰检测(一)——图像预处理

    博主最近在做一个基于OpenCV的火焰检测的项目,不仅可以检测图片中的火焰,还可以检测视频中的火焰,最后在视频检测的基础上推广到摄像头实时检测.在做这个项目的时候,博主参考了很多相关的文献,用了很多种 ...

随机推荐

  1. Linux IPC实践(2) --匿名PIPE

    管道概念 管道是Unix中最古老的进程间通信的形式,我们把从一个进程连接到另一个进程的一个数据流称为一个"管道", 管道的本质是固定大小的内核缓冲区; 如:ps aux | gre ...

  2. VB.NET版机房收费系统---异常处理

    异常处理,英文名为Exceptional Handling, 那时年少,还记得那年一起学习过的VB6.0的时候,常常使用ONError的错误语句.与传统VB6.0中的OnError语句相比.NET平台 ...

  3. 开源项目管理系统:ProjectForge

    ProjectForge是一个Java编写的开源的基于Web的项目管理解决方案.包括:工时表(Timesheet).费用管理.项目甘特图,控制和管理工程分解结构.集成JiRA做为问题管理系统. 使用的 ...

  4. How To Get Log, Trace Files In OA Framework Pages And Concurrent Request Programs

    Goal   Solution   References APPLIES TO: Oracle Supplier Lifecycle Management - Version 12.1.2 and l ...

  5. Unity3D学习笔记(五)C#与JavaScript组件访问的比较

    由于之前用JavaScript用的比较多,因此总是想用以前的方法来访问组件,却屡遭失败,经过查阅资料发现,二者存在较大的不同. 下面以调用3D Text组件HurtValue为例,来比较二者的不同 J ...

  6. saiku中文查询(鉴于有人提问:saiku执行mdx,有中文报错)

    有人问我saiku的中文查询问题: saiku默认执行英文,很多人,在mysql里录入了中文,使用sql语言查询没有问题. 可是,用saiku的mdx查询,就会报错. 这是因为mysql默认支持中文查 ...

  7. SpriteBuilder中时间线播放音效的弊端

    当你美滋滋的在时间线中播放音效的时候,你要想到音效时间线并不适于播放同步于游戏事件的声音,比如碰撞和加速时. 它同样不能被用来播放背景循环的声音,这就本质上拒绝了通过timeline播放背景音乐.甚至 ...

  8. 【面试笔试算法】Problem 8: 然而沼跃鱼早就看穿了一切(hiho题库)

    时间限制:1000ms 单点时限:1000ms 内存限制:256MB 描述 fjxmlhx每天都在被沼跃鱼刷屏,因此他急切的找到了你希望你写一个程序屏蔽所有句子中的沼跃鱼("marshtom ...

  9. 我所理解的Android 启动模式

    首先,这是从 一个开源网站转载的,觉得写得不错,对我们之前理解的activity的启动模式是一个新的理解方式,并给出实际的应用场景. 任务栈是什么 任务栈Task,是一种用来放置Activity实例的 ...

  10. Leetcode_228_Summary Ranges

    本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/46762039 Given a sorted integer ...