# how to normalize local binary pattern for kullback leibler?

This is my third post for local binary pattern. I've gotten the scikit-image code to work here (http://scikit-image.org/docs/dev/auto...), 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);
waitKey(0);

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);
waitKey(0);

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);
}
system("pause");
return 0; // success
}

edit retag close merge delete

## Comments

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.)

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

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?

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.

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.