OpenCV的视频输入和相似度测量
#include <iostream>
#include <string>
#include <iomanip> // 控制浮动类型的打印精度
#include <sstream> // 字符串和数值的转换 #include <opencv2/core.hpp> // CV::Mat,Scalar
#include <opencv2/imgproc.hpp> // 高斯平滑
#include <opencv2/videoio.hpp> // 视频
#include <opencv2/highgui.hpp> using namespace std;
using namespace cv; double getPSNR(const Mat& I1, const Mat& I2);
Scalar getMSSIM(const Mat& I1, const Mat& I2); int main(int argc, char *argv[])
{
const string sourceReference = "E:\\VS2015Opencv\\vs2015\\project\\video\\01.avi";
const string sourceCompareWith = "E:\\VS2015Opencv\\vs2015\\project\\video\\011.avi"; int frameNum = -; // 计算帧数
int psnrTriggerValue = ; VideoCapture captRefrnc(sourceReference), captUndTst(sourceCompareWith); // 获取视频
if (!captRefrnc.isOpened() || !captUndTst.isOpened()) { return -; } Size refS = Size((int)captRefrnc.get(CAP_PROP_FRAME_WIDTH), // 视频帧的大小
(int)captRefrnc.get(CAP_PROP_FRAME_HEIGHT));
Size uTSi = Size((int)captUndTst.get(CAP_PROP_FRAME_WIDTH),
(int)captUndTst.get(CAP_PROP_FRAME_HEIGHT));
if (refS != uTSi) { return -; } // 视频帧大小应相同 const char* WIN_UT = "Under Test"; // 显示窗口
const char* WIN_RF = "Reference";
namedWindow(WIN_RF, WINDOW_AUTOSIZE);
namedWindow(WIN_UT, WINDOW_AUTOSIZE);
moveWindow(WIN_RF, , );
moveWindow(WIN_UT, refS.width, ); cout << "Reference frame resolution: Width=" << refS.width << " Height=" << refS.height
<< " of nr#: " << captRefrnc.get(CAP_PROP_FRAME_COUNT) << endl;
cout << "PSNR trigger value " << psnrTriggerValue << endl; Mat frameReference, frameUnderTest;
double psnrV; // PSNR方法
Scalar mssimV; // SSIM方法 for (;;)
{
captRefrnc >> frameReference;
captUndTst >> frameUnderTest;
if (frameReference.empty() || frameUnderTest.empty())
{
cout << "The End" << endl;
break;
} ++frameNum;
cout << "Frame:" << frameNum << "#"; // 当前帧数,0开始 psnrV = getPSNR(frameReference, frameUnderTest); // 定义的PSNR函数 // setiosflags(ios::fixed)用定点方式显示实数,setprecision(n)可控制输出流显示浮点数的数字个数
cout << setiosflags(ios::fixed) << setprecision() << psnrV << "dB"; if (psnrV < psnrTriggerValue && psnrV) // PSNR结果不为零且小于输入值
{
mssimV = getMSSIM(frameReference, frameUnderTest); cout << "\tMSSIM:" << " R " << setiosflags(ios::fixed) << setprecision() << mssimV.val[] * << "%"
<< " G " << setiosflags(ios::fixed) << setprecision() << mssimV.val[] * << "%"
<< " B " << setiosflags(ios::fixed) << setprecision() << mssimV.val[] * << "%";
} cout << endl; imshow(WIN_RF, frameReference);
imshow(WIN_UT, frameUnderTest); char c = (char)waitKey();
if (c == ) break;
} return ;
} double getPSNR(const Mat& I1, const Mat& I2) // PSNR方法
{
Mat s1;
absdiff(I1, I2, s1); // |I1 - I2|
s1.convertTo(s1, CV_32F); // 转换为32位进行运算
s1 = s1.mul(s1); // |I1 - I2|^2 Scalar s = sum(s1); // 各个通道求和 double sse = s.val[] + s.val[] + s.val[]; // 所有通道的值相加在一起
if (sse <= 1e-) // 当值太小时近似于0,由公式可知分母为0时需另外对待,使用SSIM方法
return ;
else
{
double mse = sse / (double)(I1.channels() * I1.total()); // 公式
double psnr = 10.0 * log10(( * ) / mse);
return psnr;
}
}
Scalar getMSSIM(const Mat& i1, const Mat& i2) // SSIM方法
{
const double C1 = 6.5025, C2 = 58.5225; Mat I1, I2;
i1.convertTo(I1, CV_32F); // 转换为32位进行运算
i2.convertTo(I2, CV_32F); Mat I1_2 = I1.mul(I1); // I1^2
Mat I2_2 = I2.mul(I2); // I2^2
Mat I1_I2 = I1.mul(I2); // I1 * I2 Mat sigma1_2, sigma2_2, sigma12; // 先平方再高斯滤波
GaussianBlur(I1_2, sigma1_2, Size(, ), 1.5);
GaussianBlur(I2_2, sigma2_2, Size(, ), 1.5);
GaussianBlur(I1_I2, sigma12, Size(, ), 1.5); Mat mu1, mu2;
GaussianBlur(I1, mu1, Size(, ), 1.5);
GaussianBlur(I2, mu2, Size(, ), 1.5); Mat mu1_2 = mu1.mul(mu1); // 先高斯滤波再平方
Mat mu2_2 = mu2.mul(mu2);
Mat mu1_mu2 = mu1.mul(mu2); sigma1_2 -= mu1_2; // 两种方式的差值
sigma2_2 -= mu2_2;
sigma12 -= mu1_mu2; Mat t1, t2, t3, t4;
t1 = * mu1_mu2 + C1;
t2 = * sigma12 + C2;
t3 = t1.mul(t2); // t3 = ((2*mu1_mu2 + C1).*(2*sigma12 + C2)) t1 = mu1_2 + mu2_2 + C1;
t2 = sigma1_2 + sigma2_2 + C2;
t4 = t1.mul(t2); // t4 =((mu1_2 + mu2_2 + C1).*(sigma1_2 + sigma2_2 + C2)) Mat ssim_map;
divide(t3, t4, ssim_map); // ssim_map = t3./t4;
Scalar mssim = mean(ssim_map); // ssim map矩阵的平均值 return mssim;
}

代码解析:
关于视频读取函数:opencv视频操作基础---VideoCapture类
VideoCapture capture;
capture.open("E:\\Workspace\\OpenCV\\test\\video\\video.avi");
上面代码是读取本地视频,下面代码与上面代码类似,只不过换了名字;
VideoCapture captRefrnc(sourceReference), captUndTst(sourceCompareWith); // 获取视频
if (!captRefrnc.isOpened() || !captUndTst.isOpened()) { return -1; }
视频通常拥有很多除了视频帧图像以外的信息,像是帧数之类,有些时候数据较短,有些时候用4个字节的字符串来表示。所以 get 函数返回一个double(8个字节)类型的数据来表示这些属性。然后你可以使用位操作符来操作这个返回值从而得到想要的整型数据等。这个函数有一个参数,代表着试图查询的属性ID。在下面的例子里我们会先获得视频的尺寸和帧数。

Size refS = Size((int)captRefrnc.get(CAP_PROP_FRAME_WIDTH), // 视频帧的大小
(int)captRefrnc.get(CAP_PROP_FRAME_HEIGHT));
Size uTSi = Size((int)captUndTst.get(CAP_PROP_FRAME_WIDTH),
(int)captUndTst.get(CAP_PROP_FRAME_HEIGHT));
if (refS != uTSi) { return -1; } // 视频帧大小应相同 const char* WIN_UT = "Under Test"; // 显示窗口
const char* WIN_RF = "Reference";
namedWindow(WIN_RF, WINDOW_AUTOSIZE);
namedWindow(WIN_UT, WINDOW_AUTOSIZE);
moveWindow(WIN_RF, 0, 0);
moveWindow(WIN_UT, refS.width, 0); cout << "Reference frame resolution: Width=" << refS.width << " Height=" << refS.height
<< " of nr#: " << captRefrnc.get(CAP_PROP_FRAME_COUNT) << endl;
cout << "PSNR trigger value " << psnrTriggerValue << endl;
图像比较 - PSNR and SSIM
当我们想检查压缩视频带来的细微差异的时候,就需要构建一个能够逐帧比较差视频差异的系统。最常用的比较算法是PSNR( Peak signal-to-noise ratio)。这是个使用“局部均值误差”来判断差异的最简单的方法,假设有这两幅图像:I1和I2,它们的行列数分别是i,j,有c个通道。

PSNR公式如下:

每个像素的每个通道的值占用一个字节,值域[0,255]。这里每个像素会有
个有效的最大值 注意当两幅图像的相同的话,MSE的值会变成0。这样会导致PSNR的公式会除以0而变得没有意义。所以我们需要单独的处理这样的特殊情况。此外由于像素的动态范围很广,在处理时会使用对数变换来缩小范围。这些变换的C++代码如下:
double getPSNR(const Mat& I1, const Mat& I2) // PSNR方法
{
Mat s1;
absdiff(I1, I2, s1); // |I1 - I2|
s1.convertTo(s1, CV_32F); // 转换为32位进行运算
s1 = s1.mul(s1); // |I1 - I2|^2 Scalar s = sum(s1); // 各个通道求和 double sse = s.val[0] + s.val[1] + s.val[2]; // 所有通道的值相加在一起
if (sse <= 1e-10) // 当值太小时近似于0,由公式可知分母为0时需另外对待,使用SSIM方法
return 0;
else
{
double mse = sse / (double)(I1.channels() * I1.total()); // 公式
double psnr = 10.0 * log10((255 * 255) / mse);
return psnr;
}
}
Scalar getMSSIM(const Mat& i1, const Mat& i2) // SSIM方法
{
const double C1 = 6.5025, C2 = 58.5225; Mat I1, I2;
i1.convertTo(I1, CV_32F); // 转换为32位进行运算
i2.convertTo(I2, CV_32F); Mat I1_2 = I1.mul(I1); // I1^2
Mat I2_2 = I2.mul(I2); // I2^2
Mat I1_I2 = I1.mul(I2); // I1 * I2 Mat sigma1_2, sigma2_2, sigma12; // 先平方再高斯滤波
GaussianBlur(I1_2, sigma1_2, Size(11, 11), 1.5);
GaussianBlur(I2_2, sigma2_2, Size(11, 11), 1.5);
GaussianBlur(I1_I2, sigma12, Size(11, 11), 1.5); Mat mu1, mu2;
GaussianBlur(I1, mu1, Size(11, 11), 1.5);
GaussianBlur(I2, mu2, Size(11, 11), 1.5); Mat mu1_2 = mu1.mul(mu1); // 先高斯滤波再平方
Mat mu2_2 = mu2.mul(mu2);
Mat mu1_mu2 = mu1.mul(mu2); sigma1_2 -= mu1_2; // 两种方式的差值
sigma2_2 -= mu2_2;
sigma12 -= mu1_mu2; Mat t1, t2, t3, t4;
t1 = 2 * mu1_mu2 + C1;
t2 = 2 * sigma12 + C2;
t3 = t1.mul(t2); // t3 = ((2*mu1_mu2 + C1).*(2*sigma12 + C2)) t1 = mu1_2 + mu2_2 + C1;
t2 = sigma1_2 + sigma2_2 + C2;
t4 = t1.mul(t2); // t4 =((mu1_2 + mu2_2 + C1).*(sigma1_2 + sigma2_2 + C2)) Mat ssim_map;
divide(t3, t4, ssim_map); // ssim_map = t3./t4;
Scalar mssim = mean(ssim_map); // ssim map矩阵的平均值 return mssim;
调用相似度测量方法
for (;;)
{
captRefrnc >> frameReference;
captUndTst >> frameUnderTest;
if (frameReference.empty() || frameUnderTest.empty())
{
cout << "The End" << endl;
break;
} ++frameNum;
cout << "Frame:" << frameNum << "#"; // 当前帧数,0开始 psnrV = getPSNR(frameReference, frameUnderTest); // 定义的PSNR函数 // setiosflags(ios::fixed)用定点方式显示实数,setprecision(n)可控制输出流显示浮点数的数字个数
cout << setiosflags(ios::fixed) << setprecision(3) << psnrV << "dB"; if (psnrV < psnrTriggerValue && psnrV) // PSNR结果不为零且小于输入值
{
mssimV = getMSSIM(frameReference, frameUnderTest); cout << "\tMSSIM:" << " R " << setiosflags(ios::fixed) << setprecision(2) << mssimV.val[2] * 100 << "%"
<< " G " << setiosflags(ios::fixed) << setprecision(2) << mssimV.val[1] * 100 << "%"
<< " B " << setiosflags(ios::fixed) << setprecision(2) << mssimV.val[0] * 100 << "%";
} cout << endl; imshow(WIN_RF, frameReference);
imshow(WIN_UT, frameUnderTest); char c = (char)waitKey(30);
if (c == 27) break;
}
OpenCV的视频输入和相似度测量
OpenCV的视频输入和相似度测量的更多相关文章
- Opencv python图像处理-图像相似度计算
一.相关概念 一般我们人区分谁是谁,给物品分类,都是通过各种特征去辨别的,比如黑长直.大白腿.樱桃唇.瓜子脸.王麻子脸上有麻子,隔壁老王和儿子很像,但是儿子下巴涨了一颗痣和他妈一模一样,让你确定这是你 ...
- cesium-长度测量和面积测量
网上找的大神的实现方法有点问题,实现有一些bug,作为cesium新手一个,弃之不忍,只好硬着头皮修改了,不过还好问题不大,再次mark一下,下次就可以直接用了 image.png import ...
- 利用Python,四步掌握机器学习
为了理解和应用机器学习技术,你需要学习 Python 或者 R.这两者都是与 C.Java.PHP 相类似的编程语言.但是,因为 Python 与 R 都比较年轻,而且更加“远离”CPU,所以它们显得 ...
- 利用python 掌握机器学习的过程
转载:http://python.jobbole.com/84326/ 偶然看到的这篇文章,觉得对我挺有引导作用的.特此跟大家分享一下. 为了理解和应用机器学习技术,你需要学习 Python 或者 R ...
- 机器学习&数据挖掘笔记_16(常见面试之机器学习算法思想简单梳理)
前言: 找工作时(IT行业),除了常见的软件开发以外,机器学习岗位也可以当作是一个选择,不少计算机方向的研究生都会接触这个,如果你的研究方向是机器学习/数据挖掘之类,且又对其非常感兴趣的话,可以考虑考 ...
- paper 17 : 机器学习算法思想简单梳理
前言: 本文总结的常见机器学习算法(主要是一些常规分类器)大概流程和主要思想. 朴素贝叶斯: 有以下几个地方需要注意: 1. 如果给出的特征向量长度可能不同,这是需要归一化为通长度的向量(这里以文本分 ...
- 机器学习&数据挖掘笔记(常见面试之机器学习算法思想简单梳理)
机器学习&数据挖掘笔记_16(常见面试之机器学习算法思想简单梳理) 作者:tornadomeet 出处:http://www.cnblogs.com/tornadomeet 前言: 找工作时( ...
- [转]机器学习&数据挖掘笔记_16(常见面试之机器学习算法思想简单梳理)
机器学习&数据挖掘笔记_16(常见面试之机器学习算法思想简单梳理) 转自http://www.cnblogs.com/tornadomeet/p/3395593.html 前言: 找工作时(I ...
- 【图像配准】基于灰度的模板匹配算法(一):MAD、SAD、SSD、MSD、NCC、SSDA、SATD算法
简介: 本文主要介绍几种基于灰度的图像匹配算法:平均绝对差算法(MAD).绝对误差和算法(SAD).误差平方和算法(SSD).平均误差平方和算法(MSD).归一化积相关算法(NCC).序贯相似性检测算 ...
随机推荐
- 小白的java学习之路 “ 二重循环”
二重循环: 1.什么是二重循环: 一个循环体内又包含另一个完整的循环结构 语法: while(循环条件1) { //循环操作1 while(循环条件2) { //循环操作2 } } do { //循环 ...
- beego控制器介绍
控制器介绍 提示:在 v1.6 中,此文档所涉及的 API 有重大变更,this.ServeJson() 更改为 this.ServeJSON(),this.TplNames 更改为 this.Tpl ...
- 【巨杉数据库SequoiaDB】为“战疫” 保驾护航,巨杉在行动
2020年,我们经历了一个不平静的新春,在这场大的“战疫”中,巨杉数据库也积极响应号召,勇于承担新一代科技企业的社会担当,用自己的行动助力这场疫情防控阻击战! 赋能“战疫”快速响应 巨杉数据库目前服务 ...
- Centos下查看CPU个数跟核数
总核数 = 物理CPU个数 X 每颗物理CPU的核数 总逻辑CPU数 = 物理CPU个数 X 每颗物理CPU的核数 X 超线程数 查看物理CPU个数 cat /proc/cpuinfo| grep & ...
- Oracle 12c 如何在 PDB 中添加 SCOTT 模式(数据泵方式)
Oracle 12c 建库后,没有 scott 模式,本篇使用数据泵方式,在12c版本之前数据库中 expdp 导出 scott 模式,并连接 12c 的 pdb 进行 impdp 导入. 目录 1. ...
- 2019-2020-2 《网络对抗技术》Exp0 环境搭建-Kali Linux 的安装
2019-2020-2 20175334 环境搭建-Kali Linux 的安装 一.Kali的下载与安装 在Kali官网中下载镜像文件 打开Vmware开始创建新虚拟机 选择镜像文件 选择操作系统 ...
- set类型的应用场景 —— Redis实战经验
set类型是string类型的集合,其特点是集合元素无序且不重复,每个集合最多可以存储 232 - 1 个元素(40多亿),set类型主要有以下应用场景. 1. 好友/关注/粉丝/感兴趣的人集合 se ...
- koa文档笔记
请求 get ctx.request.query // 查询对象 ctx.request.querystring // 查询字符串 ctx.query // 查询对象 ctx.querystring ...
- Ubuntu 16 服务器配置PHP+MySQL+Apache环境
一.获取软件包资源并进行资源更新 apt是Ubuntu上默认的软件包管理器,使用它可以很容易进行各种软件安装,而且会自动帮你安装可能需要的依赖关系. 另一个强大的软件管理工具是 dpkg,可以用于安装 ...
- 云服务器 使用 onedrive 快速同步
重大更新:支持微软的onedrive网盘,可以自动实时双向同步数据,也可以多台服务器和网盘之间实时同步数据.新增了一个虚拟环境python367,支持pytorch1.2:-----------微软O ...