Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

Incorect feature points of akaze feature matching of deformed objects

I'm trying to match the feature points of a deformed object and the non deformed version of the same object. I know that after the deformation it's applied, I end up with a totally different image, but there are still some feature points in common between the 2 that could be found. If I don't comment the if (dist < m_InlierThreshold)condition, I end up with no inlier, most of them being wrong matches. Could someone tell me what is it that I'm doing wrong?

Here is the output of the feature matching (In this case I limited the number of feature matches for an easier view of the points): MatchingResult

This is the homography matrix that I am using :

7.6285898e-01  -2.9922929e-01   2.2567123e+02
3.3443473e-01   1.0143901e+00  -7.6999973e+01
3.4663091e-04  -1.4364524e-05   1.0000000e+00

Here are the members of the class CImage, of which I'm using the instances with the name m_SourceImage, m_TemplateImage :

std::string m_ImagePath;
cv::Mat m_Image, m_ImageDescriptors;
std::vector<cv::KeyPoint> m_ImageKeyPoints;

And here are the relevant members of the class that does the feature matching:

CImage m_SourceImage, m_TemplateImage;
float m_InlierThreshold, m_NnMatchRatio;
cv::Mat m_Homography, m_OutputResult;
std::vector<cv::DMatch> m_CorrectImageMatches;
std::vector<std::vector<cv::DMatch> > m_NnMatches;
std::vector<cv::KeyPoint> m_KPMatchedSourceImage, m_KPMatchedTemplateImage, m_InliersSourceImage, m_InliersTemplateImage;

And here we have the functions used for the feature matching and drawing the output:

    //-----------------------------------------------------------------------------
   void CImageTemplateMatching::AkazeTemplateMatch()
   {
        AkazeDescriptorsAndKeypointsDetection();
        BruteForceMatching();
        FindCorrectKeypoints();
        CheckMatchesHomographyFit();
        MatchOutput();
    }
    //-----------------------------------------------------------------------------
    void CImageTemplateMatching::AkazeDescriptorsAndKeypointsDetection()
    {
        Ptr<AKAZE> akazeMatch = AKAZE::create();
        akazeMatch->detectAndCompute(m_SourceImage.GetImage() , noArray(), m_SourceImage.GetImageKeyPoints(), m_SourceImage.GetImageDescriptors());
        akazeMatch->detectAndCompute(m_TemplateImage.GetImage() , noArray(), m_TemplateImage.GetImageKeyPoints(), m_TemplateImage.GetImageDescriptors());
    }
    //-----------------------------------------------------------------------------
    void CImageTemplateMatching::BruteForceMatching()
    {
        if (m_SourceImage.GetImageDescriptorsRows() > 0 && m_TemplateImage.GetImageDescriptorsRows() > 0)
        {
            BFMatcher templateMatcher(NORM_HAMMING);
            templateMatcher.knnMatch(m_SourceImage.GetImageDescriptors(), m_TemplateImage.GetImageDescriptors(), m_NnMatches, 4);
        }
    }
    //-----------------------------------------------------------------------------
    void CImageTemplateMatching::FindCorrectKeypoints()
    {
        for (size_t i = 0; i < m_NnMatches.size(); i++) {
            DMatch firstKPMatched = m_NnMatches[i][0];
            float  distSourceImage = m_NnMatches[i][0].distance;
            float  distTemplateImage = m_NnMatches[i][1].distance;

            if (distSourceImage < m_NnMatchRatio * distTemplateImage ) {
                m_KPMatchedSourceImage.push_back(m_SourceImage.GetImageKeyPoint(firstKPMatched.queryIdx%m_SourceImage.GetImageKeyPointsSize()));
                m_KPMatchedTemplateImage.push_back(m_TemplateImage.GetImageKeyPoint(firstKPMatched.queryIdx%m_TemplateImage.GetImageKeyPointsSize()));
            }
        }
    }
    //-----------------------------------------------------------------------------
    void CImageTemplateMatching::CheckMatchesHomographyFit()
    {
        unsigned kpSize = max(m_KPMatchedSourceImage.size(), m_KPMatchedTemplateImage.size());
        for (int i = 0; i < kpSize; i++) 
            {
                Mat columnCheck = Mat::ones(3, 1, CV_64F);
                columnCheck.at<double>(0) = m_KPMatchedSourceImage[i].pt.x;
                columnCheck.at<double>(1) = m_KPMatchedSourceImage[i].pt.y;
                columnCheck = columnCheck * m_Homography;
                columnCheck /= columnCheck.at<double>(2);
                float dist = sqrt(pow(columnCheck.at<double>(0) - m_KPMatchedTemlpateImage[i].pt.x, 2) +
                    pow(columnCheck.at<double>(1) - m_KPMatchedTemplateImage[i].pt.y, 2));
                if (dist < m_InlierThreshold) {
                int new_i = m_InliersSourceImage.size();
                m_InliersSourceImage.push_back(m_KPMatchedSourceImage[i]);
                if (i < m_KPMatchedTemplateImage.size())
                    m_InliersTemplateImage.push_back(m_KPMatchedTemplateImage[i]);
                m_CorrectImageMatches.push_back(DMatch(new_i, new_i, 0));
            }
            }
    }
    //-----------------------------------------------------------------------------
    void CImageTemplateMatching::MatchOutput()
    {
        drawMatches(m_SourceImage.GetImage(), m_InliersSourceImage, m_TemplateImage.GetImage(), m_InliersTemplateImage, m_CorrectImageMatches, m_OutputResult);
        imwrite(m_OutputPath.data(), m_OutputResult);
    }
    //-----------------------------------------------------------------------------

Incorect feature points of akaze feature matching of deformed objects

I'm trying to match the feature points of a deformed object and the non deformed version of the same object. I know that after the deformation it's applied, I end up with a totally different image, but there are still some feature points in common between the 2 that could be found. If I don't comment the if (dist < m_InlierThreshold)condition, I end up with no inlier, most of them being wrong matches. Could someone tell me what is it that I'm doing wrong?

Here is the output of the feature matching (In this case I limited the number of feature matches for an easier view of the points): MatchingResult

This is the homography matrix that I am using :

7.6285898e-01  -2.9922929e-01   2.2567123e+02
3.3443473e-01   1.0143901e+00  -7.6999973e+01
3.4663091e-04  -1.4364524e-05   1.0000000e+00

Here are the values of m_InlierThreshold and m_NnMatchRatio :

m_InlierThreshold = 2.5f;
m_NnMatchRatio = 0.8f;

Here are the members of the class CImage, of which I'm using the instances with the name m_SourceImage, m_TemplateImage :

std::string m_ImagePath;
cv::Mat m_Image, m_ImageDescriptors;
std::vector<cv::KeyPoint> m_ImageKeyPoints;

And here are the relevant members of the class that does the feature matching:

CImage m_SourceImage, m_TemplateImage;
float m_InlierThreshold, m_NnMatchRatio;
cv::Mat m_Homography, m_OutputResult;
std::vector<cv::DMatch> m_CorrectImageMatches;
std::vector<std::vector<cv::DMatch> > m_NnMatches;
std::vector<cv::KeyPoint> m_KPMatchedSourceImage, m_KPMatchedTemplateImage, m_InliersSourceImage, m_InliersTemplateImage;

And here we have the functions used for the feature matching and drawing the output:

    //-----------------------------------------------------------------------------
   void CImageTemplateMatching::AkazeTemplateMatch()
   {
        AkazeDescriptorsAndKeypointsDetection();
        BruteForceMatching();
        FindCorrectKeypoints();
        CheckMatchesHomographyFit();
        MatchOutput();
    }
    //-----------------------------------------------------------------------------
    void CImageTemplateMatching::AkazeDescriptorsAndKeypointsDetection()
    {
        Ptr<AKAZE> akazeMatch = AKAZE::create();
        akazeMatch->detectAndCompute(m_SourceImage.GetImage() , noArray(), m_SourceImage.GetImageKeyPoints(), m_SourceImage.GetImageDescriptors());
        akazeMatch->detectAndCompute(m_TemplateImage.GetImage() , noArray(), m_TemplateImage.GetImageKeyPoints(), m_TemplateImage.GetImageDescriptors());
    }
    //-----------------------------------------------------------------------------
    void CImageTemplateMatching::BruteForceMatching()
    {
        if (m_SourceImage.GetImageDescriptorsRows() > 0 && m_TemplateImage.GetImageDescriptorsRows() > 0)
        {
            BFMatcher templateMatcher(NORM_HAMMING);
            templateMatcher.knnMatch(m_SourceImage.GetImageDescriptors(), m_TemplateImage.GetImageDescriptors(), m_NnMatches, 4);
        }
    }
    //-----------------------------------------------------------------------------
    void CImageTemplateMatching::FindCorrectKeypoints()
    {
        for (size_t i = 0; i < m_NnMatches.size(); i++) {
            DMatch firstKPMatched = m_NnMatches[i][0];
            float  distSourceImage = m_NnMatches[i][0].distance;
            float  distTemplateImage = m_NnMatches[i][1].distance;

            if (distSourceImage < m_NnMatchRatio * distTemplateImage ) {
                m_KPMatchedSourceImage.push_back(m_SourceImage.GetImageKeyPoint(firstKPMatched.queryIdx%m_SourceImage.GetImageKeyPointsSize()));
                m_KPMatchedTemplateImage.push_back(m_TemplateImage.GetImageKeyPoint(firstKPMatched.queryIdx%m_TemplateImage.GetImageKeyPointsSize()));
            }
        }
    }
    //-----------------------------------------------------------------------------
    void CImageTemplateMatching::CheckMatchesHomographyFit()
    {
        unsigned kpSize = max(m_KPMatchedSourceImage.size(), m_KPMatchedTemplateImage.size());
        for (int i = 0; i < kpSize; i++) 
            {
                Mat columnCheck = Mat::ones(3, 1, CV_64F);
                columnCheck.at<double>(0) = m_KPMatchedSourceImage[i].pt.x;
                columnCheck.at<double>(1) = m_KPMatchedSourceImage[i].pt.y;
                columnCheck = columnCheck * m_Homography;
                columnCheck /= columnCheck.at<double>(2);
                float dist = sqrt(pow(columnCheck.at<double>(0) - m_KPMatchedTemlpateImage[i].pt.x, 2) +
                    pow(columnCheck.at<double>(1) - m_KPMatchedTemplateImage[i].pt.y, 2));
                if (dist < m_InlierThreshold) {
                int new_i = m_InliersSourceImage.size();
                m_InliersSourceImage.push_back(m_KPMatchedSourceImage[i]);
                if (i < m_KPMatchedTemplateImage.size())
                    m_InliersTemplateImage.push_back(m_KPMatchedTemplateImage[i]);
                m_CorrectImageMatches.push_back(DMatch(new_i, new_i, 0));
            }
            }
    }
    //-----------------------------------------------------------------------------
    void CImageTemplateMatching::MatchOutput()
    {
        drawMatches(m_SourceImage.GetImage(), m_InliersSourceImage, m_TemplateImage.GetImage(), m_InliersTemplateImage, m_CorrectImageMatches, m_OutputResult);
        imwrite(m_OutputPath.data(), m_OutputResult);
    }
    //-----------------------------------------------------------------------------