目录

  • 说在前面
  • SourceCode
    • 读取视频流
    • 图像相似度
    • Code
  • Result

说在前面

  • opencv版本:4.0.1
  • 操作系统:win10
  • vs版本:2017
  • 官方文档:Video Input with OpenCV and similarity measurement
  • 其他说明:自学,记录,demo

SourceCode

  • 读取视频流

    • 所有的视频操作需要类VideoCapture(基于开源库FFmpeg)
    • 视频由一系列图像组成,每一张图称为一帧。在视频文件中一个重要属性为帧率,用于度量帧与帧之间的时间间隔
    • 我们使用 cv::VideoCapture::VideoCapture 或者 cv::VideoCapture::open 来初始化。参数有两种:
      1. 一个整数,代表摄像头设备,值取决于操作系统(一般是0/1/2,递增)
      2. 文件名(路径)
      const string sourceReference = "test1.avi",sourceCompareWith = "test2.avi";VideoCapture captRefrnc(sourceReference);
      // or
      VideoCapture captUndTst;
      captUndTst.open(sourceCompareWith);
      
    • 我们可以使用cv::VideoCapture::isOpened来判断是否成功打开视频流
      if ( !captRefrnc.isOpened()){cout  << "Could not open reference " << sourceReference << endl;return -1;}
      
    • 视频流会在析构函数调用时自动关闭,但也可使用cv::VideoCapture::release 手动关闭
      captRefrnc.release();
      
    • 由于每一帧都是简单的图像,我们可以使用Mat来操作
      1. 使用重载的操作符>>
      2. 使用cv::VideoCapture::read
      Mat frameReference, frameUnderTest;
      captRefrnc >> frameReference;//当前视频文件还未读取完的时候
      captUndTst.read(frameUnderTest);
      
    • 判断是否到视频文件末(上面读取的时候若已经无帧可读,则Mat为空)
      if( frameReference.empty()  || frameUnderTest.empty())
      {// exit the program
      }
      
    • 获取VideoCapture的属性,支持的属性下面的表格(未显示摄像头相关,全部见 ALL)
      Size refS = Size((int) captRefrnc.get(CAP_PROP_FRAME_WIDTH),(int) captRefrnc.get(CAP_PROP_FRAME_HEIGHT)),cout << "Reference frame resolution: Width=" << refS.width << "  Height="
      << refS.height << " of nr#: " << captRefrnc.get(CAP_PROP_FRAME_COUNT) << endl;
      
    • 设置VideoCapture的属性
      captRefrnc.set(CAP_PROP_POS_MSEC, 1.2);  // go to the 1.2 second in the video
      captRefrnc.set(CAP_PROP_POS_FRAMES, 10); // go to the 10th frame of the video
      // now a read operation would read the frame at the set position
      
名称 意义
CAP_PROP_POS_MSEC 当前帧所在视频流的位置(单位:毫秒)
CAP_PROP_POS_FRAMES 下一帧是第几帧(从0开始)
CAP_PROP_POS_AVI_RATIO 视频文件相对位置(0:靠近视频头;1:靠近视频尾)
CAP_PROP_FRAME_WIDTH 帧宽度(像素)
CAP_PROP_FRAME_HEIGHT 帧高度(像素)
CAP_PROP_FPS 帧率(frame per second)
CAP_PROP_FOURCC 四个字符的编码类型
CAP_PROP_FRAME_COUNT 视频文件帧总数
CAP_PROP_FORMAT VideoCapture::retrieve()返回的Mat格式
  • 图像相似度

    • 在进行视频处理的时候有时某些操作的结果是肉眼不可见的,所以我们需要逐帧进行对比(操作前后的同一帧图像)

    • 最简单的计算方式为均方差(mean squad error)
      MSE=1c∗i∗j∑(I1−I2)2MSE = \frac{1}{c*i*j} \sum{(I_1-I_2)^2}MSE=c∗i∗j1​∑(I1​−I2​)2
      其中I1、I2I_1、I_2I1​、I2​为 iii 行 jjj 列 ccc 通道的图像,后半部分为两个图像所有对应像素的对应通道的差值平方和的求和
      PSNR=10⋅log⁡10(MAXI2MSE)PSNR = 10 \cdot \log_{10} \left( \frac{MAX_I^2}{MSE} \right)PSNR=10⋅log10​(MSEMAXI2​​)
      上面的为PSNR公式,其中MAXIMAX_IMAXI​为通道的最大值(例如CV_8U就是255);PSNR值越小,表明差异越大

      double getPSNR(const Mat& I1, const Mat& I2)
      {Mat s1;absdiff(I1, I2, s1);       // |I1 - I2|s1.convertTo(s1, CV_32F);  // cannot make a square on 8 bitss1 = s1.mul(s1);           // |I1 - I2|^2Scalar s = sum(s1);        // sum elements per channeldouble sse = s.val[0] + s.val[1] + s.val[2]; // sum channelsif( sse <= 1e-10) // for small values return zeroreturn 0;else{double  mse =sse /(double)(I1.channels() * I1.total());double psnr = 10.0*log10((255*255)/mse);return psnr;}
      }
      

      但是这种计算方式在实际应用中可能与人眼的感觉结果不一致(啥意思?)

    • 另一种计算方式,structural similarity
      用了高斯模糊,咱先不管这部分

      Scalar getMSSIM( const Mat& i1, const Mat& i2)
      {const double C1 = 6.5025, C2 = 58.5225;/***************************** INITS **********************************/int d     = CV_32F;Mat I1, I2;i1.convertTo(I1, d);           // cannot calculate on one byte large valuesi2.convertTo(I2, d);Mat I2_2   = I2.mul(I2);        // I2^2Mat I1_2   = I1.mul(I1);        // I1^2Mat I1_I2  = I1.mul(I2);        // I1 * I2/***********************PRELIMINARY COMPUTING ******************************/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);Mat sigma1_2, sigma2_2, sigma12;GaussianBlur(I1_2, sigma1_2, Size(11, 11), 1.5);sigma1_2 -= mu1_2;GaussianBlur(I2_2, sigma2_2, Size(11, 11), 1.5);sigma2_2 -= mu2_2;GaussianBlur(I1_I2, sigma12, Size(11, 11), 1.5);sigma12 -= mu1_mu2;Mat t1, t2, t3;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;t1 = t1.mul(t2);      // t1 =((mu1_2 + mu2_2 + C1).*(sigma1_2 + sigma2_2 + C2))Mat ssim_map;divide(t3, t1, ssim_map);      // ssim_map =  t3./t1;Scalar mssim = mean( ssim_map ); // mssim = average of ssim mapreturn mssim;
      }
      
  • Code

#include <iostream> // for standard I/O
#include <string>   // for strings
#include <iomanip>  // for controlling float print precision
#include <sstream>  // string to number conversion#include <opencv2/core.hpp>     // Basic OpenCV structures (cv::Mat, Scalar)
#include <opencv2/imgproc.hpp>  // Gaussian Blur
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>  // OpenCV window I/Ousing namespace std;
using namespace cv;double getPSNR(const Mat& I1, const Mat& I2);
Scalar getMSSIM(const Mat& I1, const Mat& I2);int main()
{stringstream conv;const string sourceReference = "Megamind.avi", sourceCompareWith = "Megamind_bugy.avi";int psnrTriggerValue=35, delay=10;int frameNum = -1;          // Frame counterVideoCapture captRefrnc(sourceReference), captUndTst(sourceCompareWith);if (!captRefrnc.isOpened()){cout << "Could not open reference " << sourceReference << endl;return -1;}if (!captUndTst.isOpened()){cout << "Could not open case test " << sourceCompareWith << endl;return -1;}Size refS = Size((int)captRefrnc.get(CAP_PROP_FRAME_WIDTH),(int)captRefrnc.get(CAP_PROP_FRAME_HEIGHT)),uTSi = Size((int)captUndTst.get(CAP_PROP_FRAME_WIDTH),(int)captUndTst.get(CAP_PROP_FRAME_HEIGHT));if (refS != uTSi){cout << "Inputs have different size!!! Closing." << endl;return -1;}const char* WIN_UT = "Under Test";const char* WIN_RF = "Reference";// WindowsnamedWindow(WIN_RF, WINDOW_AUTOSIZE);namedWindow(WIN_UT, WINDOW_AUTOSIZE);moveWindow(WIN_RF, 400, 0);         //750,  2 (bernat =0)moveWindow(WIN_UT, refS.width, 0);         //1500, 2cout << "Reference frame resolution: Width=" << refS.width << "  Height=" << refS.height<< " of nr#: " << captRefrnc.get(CAP_PROP_FRAME_COUNT) << endl;cout << "PSNR trigger value " << setiosflags(ios::fixed) << setprecision(3)<< psnrTriggerValue << endl;Mat frameReference, frameUnderTest;double psnrV;Scalar mssimV;for (;;) //Show the image captured in the window and repeat{captRefrnc >> frameReference;captUndTst >> frameUnderTest;if (frameReference.empty() || frameUnderTest.empty()){cout << " < < <  Game over!  > > > ";break;}++frameNum;cout << "Frame: " << frameNum << "# ";psnrV = getPSNR(frameReference, frameUnderTest);cout << setiosflags(ios::fixed) << setprecision(3) << psnrV << "dB";if (psnrV < psnrTriggerValue && psnrV){mssimV = getMSSIM(frameReference, frameUnderTest);cout << " MSSIM: "<< " 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(delay);if (c == 27) break;}return 0;
}double getPSNR(const Mat& I1, const Mat& I2)
{Mat s1;absdiff(I1, I2, s1);       // |I1 - I2|s1.convertTo(s1, CV_32F);  // cannot make a square on 8 bitss1 = s1.mul(s1);           // |I1 - I2|^2Scalar s = sum(s1);        // sum elements per channeldouble sse = s.val[0] + s.val[1] + s.val[2]; // sum channelsif (sse <= 1e-10) // for small values return zeroreturn 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)
{const double C1 = 6.5025, C2 = 58.5225;/***************************** INITS **********************************/int d = CV_32F;Mat I1, I2;i1.convertTo(I1, d);            // cannot calculate on one byte large valuesi2.convertTo(I2, d);Mat I2_2 = I2.mul(I2);        // I2^2Mat I1_2 = I1.mul(I1);        // I1^2Mat I1_I2 = I1.mul(I2);        // I1 * I2/*************************** END INITS **********************************/Mat mu1, mu2;                   // PRELIMINARY COMPUTINGGaussianBlur(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);Mat sigma1_2, sigma2_2, sigma12;GaussianBlur(I1_2, sigma1_2, Size(11, 11), 1.5);sigma1_2 -= mu1_2;GaussianBlur(I2_2, sigma2_2, Size(11, 11), 1.5);sigma2_2 -= mu2_2;GaussianBlur(I1_I2, sigma12, Size(11, 11), 1.5);sigma12 -= mu1_mu2;Mat t1, t2, t3;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;t1 = t1.mul(t2);         // t1 =((mu1_2 + mu2_2 + C1).*(sigma1_2 + sigma2_2 + C2))Mat ssim_map;divide(t3, t1, ssim_map);        // ssim_map =  t3./t1;Scalar mssim = mean(ssim_map);   // mssim = average of ssim mapreturn mssim;
}

Result

  • 测试视频为官方的那个,一个原视频、一个压缩后的视频


END-2019.7.5┗( T﹏T )┛

【opencv/videoio module】(一)Video Input with OpenCV and similarity measurement相关推荐

  1. Video Input with OpenCV and similarity measurement(使用opencv测量两个视频的相似度)

    Video Input with OpenCV and similarity measurement(使用opencv测量两个视频的相似度) 参考示例程序及视频文件下载: 一.先决条件 1.两种检查相 ...

  2. load opencv videoio gstreamer453 64d dll failed 打开摄像头慢

    环境:win10+opencv4.5.3+opencv_contrib-4.5.3+vs2019 状态:禁用笔记本自带摄像头,使用webcam 问题 配置好opencv和contrib库后,通过ope ...

  3. opencv videoio无法读取rstp_使用一行Python代码从图像读取文本

    作者 | Dario Radečić 编译 | VK 来源 | Towards DataScience 处理图像不是一项简单的任务.对你来说,作为一个人,很容易看着某样东西然后马上知道你在看什么.但电 ...

  4. opencv 脸部识别_实时面部识别如何与OpenCV一起使用?

    opencv 脸部识别 An eazy code from eazy ciphers 易密码的易密码 Are you keen to learn about the implementation of ...

  5. OpenCV入门(十七)快速学会OpenCV 16 视频处理

    OpenCV入门(十七)快速学会OpenCV 16 视频处理 1.构造VideoCapture对象 2.构造VideoWriter对象 3.视频操作基础 3.1 读取视频帧 3.2 播放视频文件 3. ...

  6. opencv resize_树莓派监控摄像头python+picamera或openCV

    1.在raspi-config中使能摄像头 打开树莓派终端,输入sudo raspi-config 完成后重启树莓派 2.检查摄像头运行情况 vcgencmd get_camera raspistil ...

  7. python卸载opencv包_Ubuntu下安装与卸载opencv模块

    opencv安装 因工程需要,想在python中调用opencv import cv2 现在记录一下如何在Linux系统(ubutun)下安装该模块: 在自己的电脑上安装成功,现记录一下安装过程: s ...

  8. cv2.error: OpenCV(4.1.0) C:\projects\opencv-python\opencv\modules\highgui\src\window.cpp:352: error:

    运行环境:python 3.6.0 初学 opencv,看着程序跟书本都一样啊,突然报了以下错误 Traceback (most recent call last):File "E:/Pyt ...

  9. OpenCV开发笔记(一):OpenCV介绍、编译

    若该文为原创文章,未经允许不得转载 本文章博客地址:https://blog.csdn.net/qq21497936/article/details/100072151 各位读者,知识无穷而人力有穷, ...

最新文章

  1. 谷歌“亲儿子”竟然成为了NLP革新者
  2. Spring配置问题——元素 quot;context:component-scanquot; 的前缀 quot;contextquot; 未绑定...
  3. zabbix监控防火墙和交换机
  4. pandas库Series使用和ix、loc、iloc基础用法
  5. 【阿里妈妈营销科学系列】第三篇:受众沟通和品牌认知评价
  6. 开源开放 | 熵简科技 AI Lab 开源金融领域中文预训练语言模型 FinBERT
  7. MySQL流浪记(四)—— DDL和DML区别与介绍
  8. 漫画:下辈子你还当程序员么?
  9. windows下MongoDB数据库的安装
  10. jsp mysql论坛_体育论坛ssm,mysql)
  11. HTML Text Editor
  12. Unity显示(内嵌)网页- UniWebView的使用教程
  13. html设置div大小位置不变,div大小 div固定大小设置
  14. 84.常用的返回QuerySet对象的方法使用详解:select_related, prefetch_related
  15. 推荐5个设计素材网站
  16. 使用OAS Validator帮助你规范OpenAPI Spec文档
  17. android12.0(S) 从SD卡导入vCard文件到通讯录 号码带“-“ 如何把横线去除
  18. 创建虚拟机、安装centos6,centos7系统,图形化界面
  19. Telnet 1521端口连接失败问题,经过四天的努力终于解决!
  20. nth_element详解

热门文章

  1. 云邮箱登陆,如何登录企业邮箱?电子邮箱如何登陆?
  2. spingioc浅见
  3. 参加英特尔迅驰二代风尚盛典发布会小记
  4. 2014校园招聘总结 .
  5. 【学习进度】截至2022.9.6,已学习的C++知识
  6. AS运行app闪退,出现keeps stopping错误
  7. 2021年度高等院校皇家勋章授勋仪式-乌隆他尼皇家大学
  8. 文献综述参考文献的格式说明
  9. 什么是基本表?什么是视图?两者的…
  10. Android Fota(差分包)制作