how to normalize local binary pattern for kullback leibler?

asked 2015-05-13 03:58:48 -0500

fredreload gravatar image

updated 2015-05-13 04:14:03 -0500

This is my third post for local binary pattern. I've gotten the scikit-image code to work here (, but I would like to transport my result to Opencv. The scikit-image code does a histogram like this, hist, _ = np.histogram(lbp, normed=True, bins=n_bins, range=(0, n_bins)) with lbp being the lbp image, and n_bins being n_bins = lbp.max() + 1 which I checked is 18.0. They also have it normalized. This is using Numpy histogram with radius 2 and neighbor 16. Now I do the same thing with Opencv cv::calcHist( &lbp, 1, channels, Mat(), lbp_hist, 1, histSize, ranges, true, false ); with lbp being the lbp image for radius 2 and neighbor 16, except I change the histsize and ranges to 256. I believe this should be the same as Numpy Histogram. The problem is when I try to normalize the Opencv histogram with the normalize function normalize(lbp_hist, lbp_hist, 0, 1, NORM_MINMAX, -1, Mat() ); from 0 to 1. And then do a compare histogram with Kullback-Leibler double base_base = compareHist( lbp_hist, lbp1_hist, CV_COMP_KL_DIV );, I still get negative values sometimes. So my question is, how do I normalize the histogram correctly in range with radius 2 and neighbor 16? Below is my code.

P.S. I found out it has something to do with the conversion from CV_32SC1 to CV_32FC1 to CV_8UC1. But still get negative values.

#include <stdio.h>
#include <iostream>
#include "opencv2/core/core.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/xfeatures2d.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "lbp.hpp"
#include "histogram.hpp"

using namespace cv;

int main(int argc, const char *argv[]) {

    // initial values
    int radius = 2;
    int neighbors = radius*8;

    // matrices used
    Mat test;
    Mat test1;
    Mat frame; // always references the last frame
    Mat dst; // image after preprocessing
    Mat dst1;
    Mat lbp; // lbp image
    Mat lbp1;

    Mat lbp_hist, lbp1_hist;

    int histSize[] = {256};

    float s_ranges[] = { 0, 256 };

    const float* ranges[] = { s_ranges };

    // Use the o-th and 1-st channels
    int channels[] = { 0 };

    dst = imread("B10.png", 1); //Load as grayscale
    cvtColor(dst, dst, CV_BGR2GRAY);
    lbp::ELBP(dst, lbp, 2, 16); // use the extended operator

    lbp.convertTo(lbp, CV_32FC1);
    normalize(lbp, lbp, 0, 255, NORM_MINMAX);

    imshow("lbp", lbp);

    cv::calcHist( &lbp, 1, channels, Mat(), lbp_hist, 1, histSize, ranges, true, false );
    normalize(lbp_hist, lbp_hist, 0, 1, NORM_MINMAX, -1, Mat() );

    show_histogram("lbp_h", lbp);

    int lbp_operator=1;

    for (int i=1; i<31; i++) {
        dst1 = imread("B" + to_string(i) +".png", 1); //Load as grayscale
        cvtColor(dst1, dst1, CV_BGR2GRAY);

        lbp::ELBP(dst1, lbp1, 2, 16); // use the original operator

        lbp1.convertTo(lbp1, CV_32FC1);

        normalize(lbp1, lbp1, 0, 255, NORM_MINMAX);

        cv::calcHist( &lbp1, 1, channels, Mat(), lbp1_hist, 1, histSize, ranges, true, false );
        normalize(lbp1_hist, lbp1_hist, 0, 1, NORM_MINMAX, -1, Mat() );

        double base_base = compareHist( lbp_hist, lbp1_hist, CV_COMP_KL_DIV );

        printf("%f is %d\n",base_base,i);
    return 0; // success
edit retag flag offensive close merge delete


just saying, with 16 neighbours, you need 2^16 histogram bins, not 2^8, so your histogram size/ranges are already wrong.

also, you should not normalize the lbp images (the histogram, yes.)

berak gravatar imageberak ( 2015-05-13 04:04:34 -0500 )edit

The lbp code I got is too old, I need to check out some conversions. Either that or I need to stick with OLBP.

fredreload gravatar imagefredreload ( 2015-05-13 04:16:48 -0500 )edit

this one , maybe.

berak gravatar imageberak ( 2015-05-13 04:36:39 -0500 )edit

That's the format I'm having trouble with. After converting CV_32SC1 to CV_32FC1 for Opencv calcHist, the kullback-leibler gives a negative value. I'm thinking of just using original LBP since it stays the same as CV_8UC1. What is a good histogram analysis for the original LBP? Chi-Square? Or Histogram intersection?

fredreload gravatar imagefredreload ( 2015-05-13 05:27:51 -0500 )edit

why the conversion to float ? an lbp image is actually a binary bitmap (encoded to integers) the type of your lbp image depends on the neighbour count. for 8 neighbours, you can use CV_8U [0..255], for 16 you will need CV_32S [0..65335]

originally, CHI_SQR is used for comparison.

berak gravatar imageberak ( 2015-05-13 05:36:55 -0500 )edit

ah, right. did not see that.

berak gravatar imageberak ( 2015-05-13 05:47:46 -0500 )edit

CHI_SQR works, thanks for the help!

fredreload gravatar imagefredreload ( 2015-05-13 05:51:59 -0500 )edit

as an afterthought : using a plain nearest neighbour distance from compareHist is the most primitive way of classification. once you got your processing pipeline running nicely, also look at using e.g. an SVM or even PCA_LDA (similar to the face reco) for classification.

berak gravatar imageberak ( 2015-05-14 02:14:21 -0500 )edit