检测两幅图像之间的差异
Detecting difference between 2 images
我正在编写以下代码
#include <iostream>
#include <opencv2/core/core.hpp>
#include <string>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/video/background_segm.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat current,currentGrey,next,abs;
VideoCapture cam1,cam2;
std:: vector<vector<Point>>contours;
vector<vector<Point>>contoursPoly(contours.size());
cam1.open(0);
cam2.open(0);
namedWindow("Normal");
namedWindow("Difference");
if(!cam1.isOpened())
{
cout << "Cam not found" << endl;
return -1;
}
while(true)
{
//Take the input
cam1 >> current;
currentGrey = current;
cam2 >> next;
//Convert to grey
cvtColor(currentGrey,currentGrey,CV_RGB2GRAY);
cvtColor(next,next,CV_RGB2GRAY);
//Reduce Noise
cv::GaussianBlur(currentGrey,currentGrey,Size(0,0),4);
cv::GaussianBlur(next,next,Size(0,0),4);
imshow("Normal",currentGrey);
//Get the absolute difference
absdiff(currentGrey,next,abs);
imshow("Difference",abs);
for(int i=0;i<abs.rows;i++)
{
for(int j=0;j<abs.cols;j++)
{
if(abs.at<int>(j,i)>0)
{
cout << "Change Detected" << endl;
j = abs.cols+1;
i = abs.rows+1;
}
}
}
if(waitKey(30)>=0)
{
break;
}
}
}
在这里,我要做的是在检测到图像之间的差异时打印一条消息。下面是技术
for(int i=0;i<abs.rows;i++)
{
for(int j=0;j<abs.cols;j++)
{
if(abs.at<int>(j,i)>0)
{
cout << "Change Detected" << endl;
j = abs.cols+1;
i = abs.rows+1;
}
}
}
不幸的是,它不是在检测到差异时打印消息,而是始终打印消息。为什么会这样?
你应该计算两帧之间的均方误差。
MSE = sum((frame1-frame2)^2 ) / no. of pixels
在OpenCV教程中有一个计算它的例子。
根据这段代码,你可以得到
double getMSE(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 bits
s1 = s1.mul(s1); // |I1 - I2|^2
Scalar s = sum(s1); // sum elements per channel
double sse = s.val[0] + s.val[1] + s.val[2]; // sum channels
if( sse <= 1e-10) // for small values return zero
return 0;
else
{
double mse =sse /(double)(I1.channels() * I1.total());
return mse;
// Instead of returning MSE, the tutorial code returned PSNR (below).
//double psnr = 10.0*log10((255*255)/mse);
//return psnr;
}
}
你可以在你的代码中这样使用它:
if(getMSE(currentGrey,next) > some_threshold)
cout << "Change Detected" << endl;
这是由你来决定MSE的大小,你认为图像是相同的。另外,你应该用GaussianBlur()
预滤波来降低噪声,就像你已经做的那样。@fatih_k建议的blur
方法是而不是高斯滤波器;它是一个框式过滤器,虽然速度更快,但可能会引入工件。
图像区分有一些技巧。由于噪声,任意两帧可能不相同。
为了减轻噪声的影响,您可以对每一帧使用blur()
或GaussianBlur()
方法,以便用简单的框或高斯滤波器去除微小的细节。
然后,作为相似度准则,取两帧的差值,用abs
求差值矩阵的绝对值后,对所有元素求和,并计算该和与第一帧总像素和的比值。如果这个比率超过某个阈值,比如0.05,那么你可以推断图像帧是足够不同的。
让我们看一下OpenCV文档中关于cv::waitKey返回值的说明:
返回按下的键的代码,如果在指定时间之前没有按下键,则返回-1。
所以…循环是无限的,并且每比较两个图像打印一次"Change Detected",直到程序终止。
上面描述的函数getMSE()可以稍微调整一下,以更好地覆盖无符号整数8数据类型。无符号整数8数据类型的差值每次结果为负时都会产生0。通过首先将矩阵转换为双数据类型,然后计算均方误差,可以避免这个问题。
double getMSE(Mat& I1, Mat& I2)
{
Mat s1;
// save the I! and I2 type before converting to float
int im1type = I1.type();
int im2type = I2.type();
// convert to float to avoid producing zero for negative numbers
I1.convertTo(I1, CV_32F);
I2.convertTo(I2, CV_32F);
absdiff(I1, I2, s1); // |I1 - I2|
s1.convertTo(s1, CV_32F); // cannot make a square on 8 bits
s1 = s1.mul(s1); // |I1 - I2|^2
Scalar s = sum(s1); // sum elements per channel
double sse = s.val[0] + s.val[1] + s.val[2]; // sum channels
if( sse <= 1e-10) // for small values return zero
return 0;
else
{
double mse =sse /(double)(I1.channels() * I1.total());
return mse;
// Instead of returning MSE, the tutorial code returned PSNR (below).
//double psnr = 10.0*log10((255*255)/mse);
//return psnr;
}
// return I1 and I2 to their initial types
I1.convertTo(I1, im1type);
I2.convertTo(I2, im2type);
}
上面的代码对于较小的mse值(小于1e-10)返回零。s.val1和s.val[2]项对于1D图像为零。
如果您也想检查1D图像输入(它基本上支持3通道图像),请使用以下代码进行测试(随机无符号数):
Mat I1(12, 12, CV_8UC1), I2(12, 12, CV_8UC1);
double low = 0;
double high = 255;
cv::randu(I1, Scalar(low), Scalar(high));
cv::randu(I2, Scalar(low), Scalar(high));
double mse = getMSE(I1, I2);
cout << mse << endl;
如果要检查3D图像输入,请使用以下代码进行测试(使用随机无符号数):
Mat I1(12, 12, CV_8UC3), I2(12, 12, CV_8UC3);
double low = 0;
double high = 255;
cv::randu(I1, Scalar(low), Scalar(high));
cv::randu(I2, Scalar(low), Scalar(high));
double mse = getMSE(I1, I2);
cout << mse << endl;
- 如何使用 OpenCV 解码在两个 UWP 应用之间发送的图像字节?
- 使用 LoadToolbarEx 解决异常以及正常图像与大图像计数之间的差异
- OPENCV:如何使用5点算法从来自不同相机的两个图像之间的特征匹配来计算必需矩阵
- 从opencv的视频关注和标量拍摄的图像之间的整数划分
- 视差图和校正图像之间的叠加
- 如何在OpENCV中的图像中找到像素之间的欧几里得距离
- 如何在Python中实现ITK映像和SimpleItk图像之间的转换
- OpenCV Mahalanobis函数,用于计算两个图像之间的距离
- EMGU (openCV) 在 C# 和 C++ 之间来回传递图像
- 如何使用fftw包编写计算模板(T)和二维图像(亚胺)之间二维卷积的函数
- 图像操作2个图像之间的差异
- OpenCV:快速量化两个图像之间的差异
- 使用 lerp 在两个图像之间执行线性插值
- 计算图像对之间的几何变换
- 在 OpenCV / C++ 中对应两个图像之间的值
- Xcode 中多个图像之间的交集
- 如何找出两个图像之间的对象差异
- 图像深度和通道之间的差异
- 原始图像和调整大小的图像之间的关系(C++/OpenCV)
- 检测两幅图像之间的差异