Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/image-processing/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 检测两幅图像之间的差异_C++_Image_Opencv_Image Processing_Artificial Intelligence - Fatal编程技术网

C++ 检测两幅图像之间的差异

C++ 检测两幅图像之间的差异,c++,image,opencv,image-processing,artificial-intelligence,C++,Image,Opencv,Image Processing,Artificial Intelligence,我正在编写以下代码 #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 <ope

我正在编写以下代码

#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;
        }
    }

}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
使用名称空间cv;
int main()
{
Mat电流,电流灰色,next,abs;
视频捕捉cam1,cam2;
矢量轮廓;
矢量轮廓(courtous.size());
cam1.open(0);
cam2.open(0);
名称(正常);
名称(“差异”);
如果(!cam1.isOpened())
{
电流;
电流灰色=电流;
cam2>>下一步;
//变灰
CVT颜色(CurrentGray、CurrentGray、CV_RGB2GRAY);
CVT颜色(下一个,下一个,CV_rgb2灰色);
//降低噪音
cv::GaussianBlur(当前灰色,当前灰色,大小(0,0),4);
cv::GaussianBlur(下一个,下一个,大小(0,0),4);
imshow(“正常”,灰色);
//获得绝对差异
absdiff(当前灰色,下一个,abs);
imshow(“差异”,abs);

对于(int i=0;i让我们看看OpenCV文档中关于cv::waitKey返回值的内容:

返回所按下键的代码,如果在指定时间之前未按下任何键,则返回-1。


因此…循环是无限的,在程序终止之前,每比较两个图像,就会打印一次“检测到的更改”。

图像差分有一些技巧。由于噪声,任何两帧都可能不相同

为了减轻噪声的影响,您可以对每一帧使用方法
blur()
GaussianBlur()
,以便使用简单的方框或高斯滤波器去除细微细节


然后,作为一个相似性标准,您可以取两帧的差值,在使用
abs
获取所得差值矩阵的绝对值后,您可以对所有元素求和,并计算该和与第一帧的总像素和的比率。如果该比率大于某个阈值,比如说0.05,则您可以n推断图像帧有足够的差异。

您应该计算两帧之间的均方误差

MSE = sum((frame1-frame2)^2 ) / no. of pixels
这里有一个计算它的例子

基于你可能有的代码

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;
    }
}
double getMSE(常数矩阵和I1、常数矩阵和I2)
{
垫s1;
absdiff(I1,I2,s1);/| I1-I2|
s1.convertTo(s1,CV_32F);//不能在8位上生成正方形
s1=s1.mul(s1);//I1-I2^2
标量s=sum(s1);//对每个通道的元素求和
双sse=s.val[0]+s.val[1]+s.val[2];//和通道
如果(sse某些_阈值)
cout可以稍微调整上面描述的函数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);

}
double getMSE(Mat&I1、Mat&I2)
{
垫s1;
//在转换为float之前保存I!和I2类型
int im1type=I1.type();
int im2type=I2.type();
//转换为浮点,以避免为负数生成零
I1.convertTo(I1,CV_32F);
I2.转换器(I2,CV_32F);
absdiff(I1,I2,s1);/| I1-I2|
s1.convertTo(s1,CV_32F);//不能在8位上生成正方形
s1=s1.mul(s1);//I1-I2^2
标量s=sum(s1);//对每个通道的元素求和
双sse=s.val[0]+s.val[1]+s.val[2];//和通道

如果(sse)我真的不明白它应该怎么做;它不应该把一个区域与另一个图像中的平行区域进行比较吗?因为在这里它不做,它从0,0开始,然后是1,1或0,1等等……检查这个:j=abs.cols+1;i=abs.rows+1;从我收集的abs.cols是图像的宽度,abs.rows是他看到的图像是的,所以你总是把i和j固定在那个值上,因为相机噪音是经常出现的,并且在每一帧中都会出现。@William,但它仍然把它固定在一个常量上,不是吗?检查@fatih_k answer。这是我想的。但是那行在while之后。带waitKey的条件语句在while循环中,否则“break”如果你是对的,那就没有意义了。但是,只有当图像真的不同时,它才应该打印出来。正如威廉在对你的问题的评论中所说:“相机噪音是经常出现的,并且存在于每一帧中。”在不同的时间从同一台相机拍摄的每两张图像都是不同的回答,但你似乎从不同的角度看待这个问题:)
blur
是一个方块滤波器,而不是高斯滤波器。求什么?abs?的所有像素之和,求和意味着得到abs?的总像素数@Knight,求差后,你可以取差矩阵的绝对值并求和所有结果元素。另一方面,你可以求和第一帧的所有像素。比值总的来说就是差额比率非常感谢你的回复。我真的很感激:)
   if(getMSE(currentGrey,next) > some_threshold)
        cout << "Change Detected" << endl;
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);

}
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;
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;