1

I am working on a project in which I try to compare two images in C#. I'm using EmguCV (a C# wrapper for OpenCV). I've tested some funcitons which work (compareHist for example). I am now trying to use the implementation of Earth's Mover Distance. As I use color images, I build a 2d Histogram based on the HSV image. I then build the corresponding signature (as described in the docs, and explained here). The problem is that I always obtain a NaN as the output of my code. Since I'm new to C# and EmguCV, I've tried to make the same steps, but this time in Python, and it works, EMD returns a number without any error. I've spent a lot of time on this problem trying to change the type of the histogram (between the OpenCV Mat and EmguCV image), looking at the histograms values to verify if they are right,... But I don't find what I'm doing wrong.

About the code: I have a "Comparator" class which just contain 2 images:

class Comparator
{
    public Image<Bgr, Byte> RefImage;
    public Image<Bgr, Byte> TestImage;

    public Comparator(string TestPath, string RefPath)
    {
        Image<Bgr, Byte> TestImagetemp = new Image<Bgr, Byte>(TestPath);
        Image<Bgr, Byte> RefImagetemp = new Image<Bgr, Byte>(RefPath);
        int newCols = Math.Min(TestImagetemp.Cols, RefImagetemp.Cols);
        int newRows = Math.Min(RefImagetemp.Rows, TestImagetemp.Rows);
        Rectangle roi = new Rectangle(0, 0, newCols, newRows);
        this.RefImage = crop(RefImagetemp, roi);
        this.TestImage = crop(TestImagetemp, roi);
        string DiffPath = "C:\\Users\\EPIERSO\\Docs\\testdiff";
        this.TestImage.Save(DiffPath + "testavant.png");
    }

Here is the method used for computing the histogram:

public static Mat CalcHistHSV(Image<Bgr,Byte> image)
    {
        int[] histbins = new int[] { 30, 32 };
        float[] ranges = new float[] { 0.0f, 180.0f, 0.0f, 256.0f };
        Mat hist = new Mat();
        VectorOfMat vm = new VectorOfMat();
        Image<Hsv,float> imghsv = image.Convert<Hsv, float>();
        vm.Push(imghsv);
        CvInvoke.CalcHist(vm, new int[] { 0, 1 }, null, hist, histbins, ranges, false);
        return hist;
    }

And this is the method used for comparing with EMD:

public bool EMDCompare()
    {
        int hbins = 30;
        int sbins = 32;
        Mat histref = CalcHistHSV(RefImage);
        Mat histtest = CalcHistHSV(TestImage);
        //Computing the signatures
        Mat sigref = new Mat(hbins*sbins,3,Emgu.CV.CvEnum.DepthType.Cv32F,1);
        Mat sigtest = new Mat(hbins*sbins,3, Emgu.CV.CvEnum.DepthType.Cv32F, 1);
        for (int h = 0; h<hbins; h++)
        {
            for (int s = 0; s < sbins; s++)
            {
                var bin = MatExtension.GetValue(histref,h,s);          
                MatExtension.SetValue(sigref, h * sbins + s, 0, bin);
                MatExtension.SetValue(sigref, h * sbins + s, 1, h);
                MatExtension.SetValue(sigref, h * sbins + s, 2, s);

                var bin2 = MatExtension.GetValue(histtest, h, s);
                MatExtension.SetValue(sigtest, h * sbins + s, 0, bin2);
                MatExtension.SetValue(sigtest, h * sbins + s, 1, h);
                MatExtension.SetValue(sigtest, h * sbins + s, 2, s);

            }
        }
        float emd = CvInvoke.EMD(sigref, sigtest, DistType.L2);
        return ((1 - emd) > 0.7);
    }

For modifying Mat values, I use an extension named MatExtension, found here: How can I get and set pixel values of an EmguCV Mat image?

This is the equivalent Python code: https://pastebin.com/drhvNMNs

0 Answers0