基于opencv下对视频的灰度变换,高斯滤波,canny边缘检测处理,同窗体显示并保存
如题:使用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边缘检测处理,同窗体显示并保存的更多相关文章
- c++开发ocx入门实践三--基于opencv的简易视频播发器ocx
原文:http://blog.csdn.net/yhhyhhyhhyhh/article/details/51404649 利用opencv做了个简易的视频播放器的ocx,可以在c++/c#/web ...
- 基于opencv网络摄像头在ubuntu下的视频获取
基于opencv网络摄像头在ubuntu下的视频获取 1 工具 原料 平台 :UBUNTU12.04 安装库 Opencv-2.3 2 安装编译运行步骤 安装编译opencv-2.3 参 ...
- 基于OpenCv和swing的图片/视频展示Java实现
基于OpenCv和swing实现图片/视频的展示 图片的展示 swing展示图片,多为操作BufferedImage,这里要关注的核心是将Mat转为BufferedImage. 代码如下: publi ...
- 基于opencv将视频转化为字符串Java版
基于opencv将视频转化为字符串Java版 opencv java 先上一个效果图吧 首先,弄清一下原理 我们要将视频转化为字符画,那么就需要获取画面的每一帧,也就是每一张图片,然后将图片进行转化 ...
- 基于opencv在摄像头ubuntu根据视频获取
基于opencv在摄像头ubuntu根据视频获取 1 工具 原料 平台 :UBUNTU12.04 安装库 Opencv-2.3 2 安装编译执行步骤 安装编译opencv-2.3 參考h ...
- 基于OpenCV实现对图片及视频中感兴趣区域颜色识别
基于OpenCV实现图片及视频中选定区域颜色识别 近期,需要实现检测摄像头中指定坐标区域内的主体颜色,通过查阅大量相关的内容,最终实现代码及效果如下,具体的实现步骤在代码中都详细注释,代码还可以进一步 ...
- 基于OpenCV之视频读取,处理和显示框架的搭建(一)
主要包括以下内容: 1.使用的主要函数的说明. 2.两个实例:视频读取和显示.搭建视频读取和处理框架,调用canny函数提取边缘并显示. 3.一些注意事项和代码说明. 一.使用的主要函数 1.延时函数 ...
- 基于Opencv的简单图像处理
实验环境 本实验均在笔记本电脑完成,电脑的配置如表1所示: 系统 Windows 10 家庭版 处理器 英特尔 Core i5-6200 @ 2.30GHz 双核 主板 宏碁 Zoro_SL 内存 1 ...
- 基于OpenCV的火焰检测(一)——图像预处理
博主最近在做一个基于OpenCV的火焰检测的项目,不仅可以检测图片中的火焰,还可以检测视频中的火焰,最后在视频检测的基础上推广到摄像头实时检测.在做这个项目的时候,博主参考了很多相关的文献,用了很多种 ...
随机推荐
- css3的样式讲解-css学习之旅(3)
css背景 属性:background-color:background-image:url("位置"):background-position:right等,px,百分数:bac ...
- 1.Linux下libevent和memcached安装
1 下载libevent-2.0.22-stable.tar.gz,下载地址是:http://libevent.org/ 2 下载memcached,下载地址是:http://memcached ...
- Github Coding Developer Book For LiuGuiLinAndroid
Github Coding Developer Book For LiuGuiLinAndroid 收集了这么多开源的PDF,也许会帮到一些人,现在里面的书籍还不是很多,我也在一点点的上传,才上传不到 ...
- ORM对象关系映射之GreenDAO自定义属性转换器PropertyConverter
在使用GreenDAO定义实体的属性时候,通常来说定义的实体属性名就是对应的表的字段名.实体中属性的类型(如Long.String等)就是表的字段名类型,但是我们难免会有不一样的需求,比如实体中我定义 ...
- Linux自动安装JDK的shell脚本
Linux自动安装JDK的shell脚本 A:本脚本运行的机器,Linux B:待安装JDK的机器, Linux 首先在脚本运行的机器A上确定可以ssh无密码登录到待安装jdk的机器B上,然后就可以在 ...
- workbench的schema讲解一:(维度dimension设置的基本内容)
维度名字尽量用英文:因为,saiku读取schema配置文件时,用中文会出现不可预知的错误.比如,引用维度用中文,就容易出现不可预估的错误.如果要显示中文:每个对象的caption字段里键入中文,则可 ...
- 通过COM组件方式实现java调用C#写的DLL文件
转自这里 最近一段时间单位在做一个Web项目,工程师用JAVA语言,需要公用人员信息,统一用户名和密码,原有的平台中是用C#语言开发的,在网上查找解决方法,通过JAVA调用C#的DLL文件实现.网上资 ...
- Google官方网络框架Volley实战——QQ吉凶测试,南无阿弥陀佛!
Google官方网络框架Volley实战--QQ吉凶测试,南无阿弥陀佛! 这次我们用第三方的接口来做一个QQ吉凶的测试项目,代码依然是比较的简单 无图无真相 直接撸代码了,详细解释都已经写在注释里了 ...
- mysql随笔
MySQL查询优化器--非SPJ的优化 MySQL查询优化器--非SPJ优化(一)--GROUPBY优化 http://blog.163.com/li_hx/blog/static/183991413 ...
- 在linux下制作静态库和动态链接库的方法
静态库 .o文件的集合 制作 ar -cr libxxx.a xxx1.o xxx2.o xxx3.o ... 编译 gcc main.c -l xxx [-L 库路径] (如果不加-L则在标准库路径 ...