Search code examples
opencvnoisemotion-detection

Is it possible to recognize so minimal changes between noisy images in OpenCV?


I want to detect the very minimal movement of a conveyor belt using image evaluation (Resolution: 31x512, image rate: 1000 per second.). The moment of belt-start is important for me.

If I do cv::absdiff between two subsequent images, I obtain very noisy result:

enter image description here

According to the mechanical rotation sensor of the motor, the movement starts here:

enter image description here

I tried to threshold the abs-diff image with a cascade of erosion and dilation, but I could detect the earliest change more than second too late in this image:

enter image description here

Is it possible to find the change earlier? Here is the sequence of the Images without changes (according to motor sensor):

enter image description here

In this sequence the movement begins in the middle image:

enter image description here


Solution

  • Looks like I've found a solution which works in MY case. Instead of comparing the image changes in space-domain, the cross-correlation should be applied:

    I convert both images to DFT, multiply DFT-Mats and convert back. The max pixel value is the center of the correlation. As long as the images are same, the max-pix remains in the same position and moves otherwise.

    The actual working code uses 3 images, 2 DFT multiplication result between images 1,2 and 2,3:

    Mat img1_( 512, 32, CV_16UC1 );
    Mat img2_( 512, 32, CV_16UC1 );
    Mat img3_( 512, 32, CV_16UC1 );
    //read the  data in the images wohever you want. I read from MHD-file
    
    //Set ROI (if required)
    Mat img1 = img1_(cv::Rect(0,200,32,100));
    Mat img2 = img2_(cv::Rect(0,200,32,100));
    Mat img3 = img3_(cv::Rect(0,200,32,100));
    
    //Float mats for DFT
    Mat img1f;
    Mat img2f;
    Mat img3f;
    
    //DFT and produtcts mats
    Mat dft1,dft2,dft3,dftproduct,dftproduct2;
    
    //Calculate DFT of both images
    img1.convertTo(img1f, CV_32FC1);
    cv::dft(img1f, dft1);
    
    img2.convertTo(img3f, CV_32FC1);
    cv::dft(img3f, dft3);
    
    img3.convertTo(img2f, CV_32FC1);
    cv::dft(img2f, dft2);
    
    //Multiply DFT Mats
    cv::mulSpectrums(dft1,dft2,dftproduct,true);
    cv::mulSpectrums(dft2,dft3,dftproduct2,true);
    
    //Convert back to space domain
    cv::Mat result,result2;
    cv::idft(dftproduct,result);
    cv::idft(dftproduct2,result2);
    
    //Not sure if required, I needed it for visualizing 
    cv::normalize( result, result, 0, 255, NORM_MINMAX, CV_8UC1);
    cv::normalize( result2, result2, 0, 255, NORM_MINMAX, CV_8UC1);
    
    
    
    //Find maxima positions
    double dummy;
    Point locdummy; Point maxLoc1; Point maxLoc2;
    cv::minMaxLoc(result, &dummy, &dummy, &locdummy, &maxLoc1);
    cv::minMaxLoc(result2, &dummy, &dummy, &locdummy, &maxLoc2);
    
    //Calculate products simply fot having one value to compare
    int maxlocProd1 = maxLoc1.x*maxLoc1.y;
    int maxlocProd2 = maxLoc2.x*maxLoc2.y;
    
    //Calculate absolute difference of the products. Not 0 means movement
    int absPosDiff = std::abs(maxlocProd2-maxlocProd1);
    
    
    if ( absPosDiff>0 )
    {
       std::cout << id<< std::endl;
       break;
    }