Month: September 2017

  • Hamming distance calculation

    This is a small snippet of how to calculate hamming distance in cpp with small bit of assembly for doing a population count.

    Code

    typedef unsigned long long   hash_t; 
    
    #include 
    #include 
    
    int popcount64(const hash_t& val) noexcept
    {
        int ret;
        __asm__ ("popcnt %1, %1" : "=r" (ret) : "0" (val));
        return ret;
    }
    
    int hamming_distance(const hash_t& x, const hash_t& y)
    {
        auto z = x ^ y;
        auto p = popcount64(z);
    
    #ifdef  DEBUG
        std::cout<<"size  : " << sizeof(hash_t) << std::endl;
        std::cout<<"x val : " << std::bitset<sizeof(hash_t)>(x) << std::endl;
        std::cout<<"y val : " << std::bitset<sizeof(hash_t)>(y) << std::endl;
        std::cout<<"z val : " << std::bitset<sizeof(hash_t)>(z) << std::endl;
        std::cout<<"pop   : " << p << std::endl;
    #endif
    
        return p;
    }
    </sizeof(hash_t)></sizeof(hash_t)></sizeof(hash_t)>

    Usage

        hash_t hash1 = 123456;
        hash_t hash2 = 123456;
    
        int  distance = hamming_distance(hash1, hash2);
        std::cout<<"Hamming : " << distance <<"\n";
    

    Results for sample runs

    Same hashes so we expect our distance to be 0.
    hash1 = 123456
    hash2 = 123456

    size  : 8
    x val : 01000000
    y val : 01000000
    z val : 00000000
    pop   : 0
    
    Hamming : 0
    

    Small difference in hashes.
    hash1 = 123456
    hash2 = 123455

    size  : 8
    x val : 01000000
    y val : 00111111
    z val : 01111111
    pop   : 7
    
    Hamming : 7
    

    Medium difference in hashes.
    hash1 = 123456
    hash2 = 223455

    size  : 8
    x val : 01000000
    y val : 11011111
    z val : 10011111
    pop   : 10
    
    Hamming : 10
    

    Large difference in hashes.
    hash1 = 12345678
    hash2 = 23445671

    size  : 8
    x val : 01001110
    y val : 10100111
    z val : 11101001
    pop   : 14
    
    Hamming : 14
    

    code gist

    Reference :
    https://en.wikipedia.org/wiki/Hamming_distance

  • Histogram Comparison for Image Analysis

    DRAFT

    This is the first article in the series on Image Comparison using Local Binary Patterns.
    Complete code is on github lbp-matcher

    We will start off by looking at different methods of comparing histograms.

    • Histogram Intersection
    • Log Likehood
    • Chi Squared
    • Kullback Leibler Divergence

    All our operations will be performed on 8bpp(bits per pixel) images anything that is not in that format will be up and down converted accordingly.

    Model representation is very simple it contains nothing more than a simple array of bins that will contain our histogram data. As we build the system the model might change.
    Our model will contain 256 bins each bin representing gray intensity in 8 bpp image with 0 being black and 255 being white.

    struct LBPModel
    {
        static const int_t bin_size = 256;
        int_t bins[bin_size] = {};
    };
    

    Histogram Intersection

    This is the basic method of comparing two histograms. The idea here is to take the minimum value of the two bins.

    Histogram Intersection
    [latex](a,b)\;=\sum\nolimits_{i=1}^nmax(a_i,\;b_i)[/latex]

    Histogram intersection in normalized form between 0..1;

    [latex]
    (a,b)\;=\;\frac{\sum_{i=1}^n(a_i,b_i)}{max(\sum_{i=1}^na,\sum_{i=1}^nb)\;}
    [/latex]

    Complete equation with branchless execution and normalization. Branchless execution can provide us with two benefits first there is no IF condition checking so we could gain performance but not necessarily, second it prevents timing attack analysis. Here we are only interested in performance. We will take a look at the generated assembly down the road and do quick performance analysis of our algorithm.

    [latex](a,b)\;=\;\frac{\frac12\sum_{i=1}^n(a_i+b_i\;-\;\vert a_i-b_i\vert)}{max(\sum_{i=1}^na,\sum_{i=1}^nb)\;}[/latex]

    Here we have couple examples of how this calculation was actually performed. This has been copied from the excel spreadsheet which can be found in the git repo.
    Example 1 – High similarity

    Bin[a]	Bin[b]	Result
    1	1	2       = A2+B2-ABS(A2-B2)
    2	2	4       = A3+B3-ABS(A3-B3)
    3	3	6
    4	4	8
    5	5	10
    		
    Value    	15.00   =  0.5 * SUM(C2:C6) 
    Normalized	1.0     =  C8 / MAX(SUM(A2:A6), SUM(B2:B6))
    

    Example 2 – Medium similarity
    In this example bin[b] has couple different values but it is still pretty close.

    Bin[a]	Bin[b]	Result
    1	2	2
    2	2	4
    3	3	6
    4	4	8
    5	2	4
    		
    Value    	12.00
    Normalized	0.8
    

    Example 3 – Low similarity
    Here our histograms are quite different so our similarity is very low.

    Bin[a]	Bin[b]	Result
    1	20	2
    2	2	4
    3	3	6
    4	4	8
    5	20	10
    		
    Value	15.00
    Normalized	0.3
    

    Implementation

    double HistogramComparison::scoreHistogramIntersection(const LBPModel &model, const LBPModel &sample) const
    {
        double d = 0,s1 = 0,s2 = 0;
    
        // branch less execution
        for (int_t i = 0; i < model.bin_size; ++i)
        {
            d  += model.bins[i] + sample.bins[i] - std::abs(model.bins[i] - sample.bins[i]);
            s1 += model.bins[i];
            s2 += sample.bins[i];
        }
    
        return (0.5 * d) / std::fmax(s1, s2);
    }
    

    Log Likelihood

    Implementation

    double HistogramComparison::scoreLogLikelihood(const LBPModel &model, const LBPModel &sample) const
    {
        double d = 0;
        for (int_t i = 0; i < model.bin_size; ++i)
        {
            if (model.bins[i] > 0)
            {
                d += sample.bins[i] * std::log(model.bins[i]);
            }
        }
        return -d;
    }
    

    Chi Squared

    Implementation

    double HistogramComparison::scoreChiSquared(const LBPModel &model, const LBPModel &sample) const
    {
        double d = 0;
        for (int_t i = 0; i < model.bin_size; ++i)
        {
            double q = sample.bins[i] + model.bins[i];
            if (q != 0)
            {
                double d1 = std::pow(sample.bins[i] - model.bins[i], 2);
                d += d1 / q;
            }
        }
        return d;
    }
    

    Kullback Leibler Divergence

    Implementation

    double HistogramComparison::scoreKullbackLeiblerDivergence(const LBPModel &model, const LBPModel &sample) const
    {
        double d = 0;
        for (int_t i = 0; i < model.bin_size; ++i)
        {
            double p = model.bins[i];
            double q = sample.bins[i];
    
            if (p != 0 && q != 0)
            {
                d += p * std::log(p / q);
            }
        }
        return d;
    }
    

    References :
    http://www.ariel.ac.il/sites/ofirpele/publications/ECCV2010.pdf
    https://en.wikipedia.org/wiki/Grayscale
    https://en.wikipedia.org/wiki/Likelihood_function
    https://www.mathjax.org/
    http://www.imatheq.com/imatheq/com/imatheq/math-equation-editor.html
    http://www.wiris.com/editor/demo/en/mathml-latex

  • Image Comparison using Local Binary Patterns

    This is a series of small articles on Image Comparison using Local Binary Patterns.
    Topics I like to cover will include

    • Histogram Comparsion
    • Local Binary Patterns
    • Perceptual Hashing

    From there we will go into building a system that can recognize same words/images in a document.

  • Dump leptonica pix data to console

    Small utility for dumping Leptonica Pix data to the screen.

    void dump(PIX* pix)
    {
        int_t w = pix->w;
        int_t h = pix->h;
    
        int_t wpl = pixGetWpl(pix);
        l_uint32* data = pixGetData(pix);
        l_uint32* line;
    
        printf("\n");
        printf("Depth : %d \n", pix->d);
    
        for (int_t y = 0; y < h; ++y)
        {
            printf("%04d  :  ", y);
            line = data + y * wpl;
            for (int_t x = 0; x < w; ++x)
            {
                l_uint32 val = 0;
    
                if(pix->d == 1)
                    val = GET_DATA_BIT(line, x);
                else if(pix->d == 2)
                    val = GET_DATA_DIBIT(line, x);
                else if(pix->d == 4)
                    val = GET_DATA_QBIT(line, x);
                else // 8, 16, 32
                    val = GET_DATA_BYTE(line, x);
    
                printf("%03d ", val);
            }
            printf("\n");
        }
    }