Ask Your Question
5

HEP-histogram of equivalent patterns

asked 2014-07-15 06:28:11 -0600

There are a lot of papers comparing Local Binary Pattern (LBP) versus Local Ternary Pattern (LTP), or modifications to the original LBP operator like Center-symmetric local binary patterns (CS-LBP), Local quinary patterns (LQP), Completed Local Binary Pattern (CLBP) and so on.

All this methods belong to the same type and a framework for texture analysis can be build. This framework for texture analysis is called HEP (histogram of equivalent patterns) and it is described in this paper: Texture description through histograms of equivalent patterns

This is the project web page, with Matlab implementation of hep (hep.m):

http://dismac.dii.unipg.it/hep/index.html

It would be fantastic if Opencv had HEP implementation.







I have written some lines of pseudo-code assuming there is an Opencv implementation:

//create a hep descriptor. In this case, a uniform local binary pattern descriptor for gray-scale images 
int neighbors = 8;
int radius = 1;
//char is for    values between 0...255 (gray images)
HEP<LBP<u2>,char> * hep_lbp_u2_descriptor = new HEP<LBP<u2>>(neighbors,radius,..); 

//load a gray-scale image to test the descriptors
Mat image = imread(...., );

Mat gray_image;
cvtColor( image, gray_image, CV_BGR2GRAY );

 //1. First, you could have the possibility to test a "raw pattern" in order to 
 //see how this descriptor works for a given pixel

 Mat image_test = Mat::zeros(Size(3, 3), CV_8UC1);
 image_test.at<uchar>(0,0) = 1;
 image_test.at<uchar>(0,1) = 2;
 image_test.at<uchar>(0,2) = 3;
 image_test.at<uchar>(1,0) = 4;
 image_test.at<uchar>(1,1) = 4;
 image_test.at<uchar>(1,2) = 6;
 image_test.at<uchar>(2,0) = 7;
 image_test.at<uchar>(2,1) = 8;
 image_test.at<uchar>(2,2) = 9;

 //compute the "raw pattern" for the central pixel (1,1)
 cout<<"the value for the central pixel is"<<hep_lbp_u2_descriptor->compute_raw_pattern(image_test,1,1)<<endl;

 //2. You could use this descriptor to build a lbp-image (a hep-image):
 Mat lbp_image;
 hep_lbp_u2_descriptor->compute_map(gray_image,lbp_image);

 //3. You could have the posibility to build the lbp-histogram (a hep-histogram):
 Mat lbp_histogram;
 int width_divisions = 5;
 int height_divisions = 6;
 hep_lbp_u2_descriptor->compute_histogram_grid(gray_image, lbp_histogram, width_divisions ,height_divisions );
 //(in this case the lbp_histogram would have 59*5*6 features 
 //(uniform lbp with a neighborhood of 8 pixels))
edit retag flag offensive close merge delete

Comments

2

Good idea! Feel free to send a pull request for that! ;-) I'm not sure of the framework you propose, you should probably use a factory, like for the feature detectors/descriptors, but it's definitely something interesting for OpenCV.

Mathieu Barnachon gravatar imageMathieu Barnachon ( 2014-07-15 06:59:19 -0600 )edit
2

Nice idea, but I would love to see people adding more variants of the descriptors at first. I think newer versions of LBP should find their way to OpenCV as well as other feature descriptors.

StevenPuttemans gravatar imageStevenPuttemans ( 2014-07-15 08:07:13 -0600 )edit
2

wow, you managed to wreck my productivity twice today. ;)

i wonder, if the same way (like the matlab code) of doing matrix operations on shifted images (instead of doing operations on the neighbourhood of a pixel) would be feasible in opencv, too, given there are a lot of operations

berak gravatar imageberak ( 2014-07-15 11:47:16 -0600 )edit

1 answer

Sort by ยป oldest newest most voted
5

answered 2014-07-18 02:23:07 -0600

berak gravatar image

... so, i had to give it a try..

//
// reference impl, walking over pixels.
//
struct lbp_pix
{
    void operator()( const Mat &z, Mat & h ) const
    {   PROFILEX("lbp_pix");
        h  = Mat::zeros(1,256,CV_32F);
        Mat_<uchar> fI(z.size());
        Mat_<uchar> img(z);
        const int m=1;
        for ( int r=m; r<z.rows-m; r++ )
        {
            for ( int c=m; c<z.cols-m; c++ )
            {
                uchar v = 0;
                uchar cen = img(r,c);
                v |= (img(r-1,c  ) > cen) << 0;
                v |= (img(r-1,c+1) > cen) << 1;
                v |= (img(r  ,c+1) > cen) << 2;
                v |= (img(r+1,c+1) > cen) << 3;
                v |= (img(r+1,c  ) > cen) << 4;
                v |= (img(r+1,c-1) > cen) << 5;
                v |= (img(r  ,c-1) > cen) << 6;
                v |= (img(r-1,c-1) > cen) << 7;
                fI(r,c) = v;
            }
        }      
        hist(fI,h,256,GRID,GRID);
    }
};

//
// here be matlab dragons.
//
//  pitfalls:
//  * since a Matop in opencv like A>B results in a Mat filled with [0xff or 0], (not [0 or 1]), 
//    we have to use & and | instead of * and +
//
//

#define SHIFTED_MATS_3x3 \
        int M = I.rows; \
        int N = I.cols; \
        Mat I7 = I(Range(1,M-2), Range(1,N-2));\
        Mat I6 = I(Range(1,M-2), Range(2,N-1));\
        Mat I5 = I(Range(1,M-2), Range(3,N  ));\
        Mat I4 = I(Range(2,M-1), Range(3,N  ));\
        Mat I3 = I(Range(3,M  ), Range(3,N  ));\
        Mat I2 = I(Range(3,M  ), Range(2,N-1));\
        Mat I1 = I(Range(3,M  ), Range(1,N-2));\
        Mat I0 = I(Range(2,M-1), Range(1,N-2));\
        Mat Ic = I(Range(2,M-1), Range(2,N-1));\


struct LBP_3x3
{
    void operator()( const Mat &I, Mat & h ) const
    {   PROFILEX("LBP");

        SHIFTED_MATS_3x3;

        Mat fI = ((I7>Ic)&128) |
             ((I6>Ic)&64)  |
             ((I5>Ic)&32)  |
             ((I4>Ic)&16)  |
             ((I3>Ic)&8)   |
             ((I2>Ic)&4)   |
             ((I1>Ic)&2)   |
             ((I0>Ic)&1);  

        hist(fI,h,256,GRID,GRID);
    }
};



struct  LQP_3x3 
{
    int kerP1;
    int kerP2;

    LQP_3x3(int k1=5,int k2=5) : kerP1(k1), kerP2(k2) {}

    void operator()( const Mat &I, Mat & h ) const
    {   PROFILEX("LQP");
        Mat fI_2,fI_1,fI1,fI2;

        SHIFTED_MATS_3x3;

        Mat Icplus1  = Ic+kerP1;
        Mat Icplus2  = Ic+kerP2;
        Mat Icminus1 = Ic-kerP1;
        Mat Icminus2 = Ic-kerP2;
        fI_2 =  ((I7<Icminus2)&128 ) |
                ((I6<Icminus2)& 64 ) |
                ((I5<Icminus2)& 32 ) |
                ((I4<Icminus2)& 16 ) |
                ((I3<Icminus2)&  8 ) |
                ((I2<Icminus2)&  4 ) |
                ((I1<Icminus2)&  2 ) |
                ((I0<Icminus2)&  1 );
        fI_1 =  (((I7>=Icminus2) &(I7<Icminus1))&128 ) |
                (((I6>=Icminus2) &(I6<Icminus1))& 64 ) |
                (((I5>=Icminus2) &(I5<Icminus1))& 32 ) |
                (((I4>=Icminus2) &(I4<Icminus1))& 16 ) |
                (((I3>=Icminus2) &(I3<Icminus1))&  8 ) |
                (((I2>=Icminus2) &(I2<Icminus1))&  4 ) |
                (((I1>=Icminus2) &(I1<Icminus1))&  2 ) |
                (((I0>=Icminus2) &(I0<Icminus1))&  1 );
        fI1 =   (((I7>=Icplus1) &(I7<Icplus2))&128 ) |
                (((I6>=Icplus1) &(I6<Icplus2))& 64 ) |
                (((I5>=Icplus1) &(I5<Icplus2))& 32 ) |
                (((I4>=Icplus1) &(I4<Icplus2))& 16 ) |
                (((I3>=Icplus1) &(I3<Icplus2))&  8 ) |
                (((I2>=Icplus1) &(I2<Icplus2))&  4 ) |
                (((I1>=Icplus1) &(I1<Icplus2))&  2 ) |
                (((I0>=Icplus1) &(I0<Icplus2))&  1 );
        fI2 =   ((I7>=Icplus2)&128 ) |
                ((I6>=Icplus2)& 64 ) |
                ((I5>=Icplus2)& 32 ) |
                ((I4>=Icplus2)& 16 ) |
                ((I3>=Icplus2)&  8 ) |
                ((I2>=Icplus2)&  4 ) |
                ((I1>=Icplus2)&  2 ) |
                ((I0>=Icplus2)&  1 );

        Mat h1,h2,h3,h4;
        hist(fI_2,h1,256,GRID,GRID);
        hist(fI_1,h2,256,GRID,GRID);
        hist(fI1 ...
(more)
edit flag offensive delete link more

Comments

1

Haha nice one!

StevenPuttemans gravatar imageStevenPuttemans ( 2014-07-18 03:00:00 -0600 )edit

Question Tools

2 followers

Stats

Asked: 2014-07-15 06:28:11 -0600

Seen: 1,251 times

Last updated: Jul 18 '14