局部二值模式(Local Binary Pattern - LBP)是广泛用于图像分类的一种图像特征,它的特点是,在图像发生光照变化时,提取的特征仍然能够不发生大的改变。提取LBP的过程首先是将原始图像转换为LBP图,然后统计LBP图的LBP直方图,并以这个向量形式的直方图来表示原始的图像。由于目前不少开源的LBP实现代码没有给出中间过程的可视化步骤,这里给出了由原始图转换为LBP图的C++代码。
转换LBP图的代码
- #include <iostream>
-
- #include <opencv2/core/core.hpp>
- #include <opencv2/imgproc/imgproc.hpp>
- #include <opencv2/highgui/highgui.hpp>
-
- #ifdef _DEBUG
- #pragma comment( lib, "opencv_core245d.lib" )
- #pragma comment( lib, "opencv_imgproc245d.lib" )
- #pragma comment( lib, "opencv_highgui245d.lib" )
- #else
- #pragma comment( lib, "opencv_core245.lib" )
- #pragma comment( lib, "opencv_imgproc245.lib" )
- #pragma comment( lib, "opencv_highgui245.lib" )
- #endif
-
- int main( int argc, char * argv[] )
- {
- if ( argc != 4 )
- {
- std::cerr << "Arguments not valid." << std::endl;
- return 1;
- }
-
- //////////////////////////////////////////////////////////////////////////
-
- cv::Mat image = cv::imread( argv[1], 0 );
- bool bRotation = true;
- bool bMapping = atoi( argv[3] );
-
- if ( image.empty() )
- {
- std::cerr << "Input image name not valid." << std::endl;
- return 2;
- }
-
- //////////////////////////////////////////////////////////////////////////
-
- unsigned int valMap[256];
-
- if ( bMapping )
- {
- for ( int i = 0; i < 256; i++ )
- {
- valMap[i] = 57;
- }
-
- valMap[0x00] = 56;
- valMap[0xff] = 56;
-
- for ( int i = 0 ; i < 8 ; ++i )
- {
- for ( int j = 1 ; j <= 7 ; ++j )
- {
-
- unsigned int nByte = (1 << j) - 1 ;
-
- /* put i zeroes in front */
- nByte <<= i ;
-
- /* wrap around 8 bit boundaries */
- nByte = (nByte | (nByte >> 8)) & 0xff ;
-
- /* optionally transpose the pattern */
- if ( bRotation )
- {
- unsigned int original = nByte;
-
- /* flip the string left-right */
- nByte = 0;
-
- for ( int k = 0 ; k < 8 ; ++k)
- {
- nByte <<= 1 ;
- nByte |= original & 0x1 ;
- original >>= 1 ;
- }
-
- /* rotate 90 degrees */
- nByte <<= 3 ;
- nByte = ( nByte | ( nByte >> 8 ) ) & 0xff ;
- }
-
- valMap[nByte] = i * 7 + ( j - 1 ) ;
- }
- }
- }
-
- //////////////////////////////////////////////////////////////////////////
-
- cv::Mat imageLBP = cv::Mat::zeros( image.size(), image.type() );
-
- for ( int y = 1; y < image.rows - 1; y++ )
- {
- for ( int x = 1; x < image.cols - 1; x++ )
- {
- unsigned int bitString = 0 ;
- unsigned char center = image.at<unsigned char>( cv::Point( x, y ) );
- if(image.at<unsigned char>( cv::Point(x+1,y+0) ) > center ) bitString |= 0x1 << 0; /* E */
- if(image.at<unsigned char>( cv::Point(x+1,y+1) ) > center ) bitString |= 0x1 << 1; /* SE */
- if(image.at<unsigned char>( cv::Point(x+0,y+1) ) > center ) bitString |= 0x1 << 2; /* S */
- if(image.at<unsigned char>( cv::Point(x-1,y+1) ) > center ) bitString |= 0x1 << 3; /* SW */
- if(image.at<unsigned char>( cv::Point(x-1,y+0) ) > center ) bitString |= 0x1 << 4; /* W */
- if(image.at<unsigned char>( cv::Point(x-1,y-1) ) > center ) bitString |= 0x1 << 5; /* NW */
- if(image.at<unsigned char>( cv::Point(x+0,y-1) ) > center ) bitString |= 0x1 << 6; /* N */
- if(image.at<unsigned char>( cv::Point(x+1,y-1) ) > center ) bitString |= 0x1 << 7; /* NE */
- if(bMapping) bitString = valMap[bitString];
- imageLBP.at<unsigned char>( cv::Point(x, y) ) = bitString;
- }
- }
-
- if ( !cv::imwrite( argv[2], imageLBP ) )
- {
- std::cerr << "Output mage name not valid." << std::endl;
- return 3;
- }
-
- return 0;
- }
使用方法
- /** Convert to 256 Code LBP Image */
- /** 转换为 256 Code LBP图 */
- // Program.exe [原始图像路径] [输出图像路径] 0
-
- /** Convert to 56 Code LBP Image */
- /** 转换为 56 Code LBP图 */
- // Program.exe [原始图像路径] [输出图像路径] 1
实验结果
原始图像及其对应的256 Code和56 Code LBP图
光照发生改变的图像及其对应的256 Code和56 Code LBP图
由上图可以看出,当图像发生光照变化时,其提取的LBP图是基本上不变的;而56 Code LBP图相对于256Code LBP图变化会更小一些。
局部二值模式(Local Binary Pattern - LBP)是广泛用于图像分类的一种图像特征,它的特点是,在图像发生光照变化时,提取的特征仍然能够不发生大的改变。提取LBP的过程首先是将原始图像转换为LBP图,然后统计LBP图的LBP直方图,并以这个向量形式的直方图来表示原始的图像。由于目前不少开源的LBP实现代码没有给出中间过程的可视化步骤,这里给出了由原始图转换为LBP图的C++代码。
转换LBP图的代码
- #include <iostream>
-
- #include <opencv2/core/core.hpp>
- #include <opencv2/imgproc/imgproc.hpp>
- #include <opencv2/highgui/highgui.hpp>
-
- #ifdef _DEBUG
- #pragma comment( lib, "opencv_core245d.lib" )
- #pragma comment( lib, "opencv_imgproc245d.lib" )
- #pragma comment( lib, "opencv_highgui245d.lib" )
- #else
- #pragma comment( lib, "opencv_core245.lib" )
- #pragma comment( lib, "opencv_imgproc245.lib" )
- #pragma comment( lib, "opencv_highgui245.lib" )
- #endif
-
- int main( int argc, char * argv[] )
- {
- if ( argc != 4 )
- {
- std::cerr << "Arguments not valid." << std::endl;
- return 1;
- }
-
- //////////////////////////////////////////////////////////////////////////
-
- cv::Mat image = cv::imread( argv[1], 0 );
- bool bRotation = true;
- bool bMapping = atoi( argv[3] );
-
- if ( image.empty() )
- {
- std::cerr << "Input image name not valid." << std::endl;
- return 2;
- }
-
- //////////////////////////////////////////////////////////////////////////
-
- unsigned int valMap[256];
-
- if ( bMapping )
- {
- for ( int i = 0; i < 256; i++ )
- {
- valMap[i] = 57;
- }
-
- valMap[0x00] = 56;
- valMap[0xff] = 56;
-
- for ( int i = 0 ; i < 8 ; ++i )
- {
- for ( int j = 1 ; j <= 7 ; ++j )
- {
-
- unsigned int nByte = (1 << j) - 1 ;
-
- /* put i zeroes in front */
- nByte <<= i ;
-
- /* wrap around 8 bit boundaries */
- nByte = (nByte | (nByte >> 8)) & 0xff ;
-
- /* optionally transpose the pattern */
- if ( bRotation )
- {
- unsigned int original = nByte;
-
- /* flip the string left-right */
- nByte = 0;
-
- for ( int k = 0 ; k < 8 ; ++k)
- {
- nByte <<= 1 ;
- nByte |= original & 0x1 ;
- original >>= 1 ;
- }
-
- /* rotate 90 degrees */
- nByte <<= 3 ;
- nByte = ( nByte | ( nByte >> 8 ) ) & 0xff ;
- }
-
- valMap[nByte] = i * 7 + ( j - 1 ) ;
- }
- }
- }
-
- //////////////////////////////////////////////////////////////////////////
-
- cv::Mat imageLBP = cv::Mat::zeros( image.size(), image.type() );
-
- for ( int y = 1; y < image.rows - 1; y++ )
- {
- for ( int x = 1; x < image.cols - 1; x++ )
- {
- unsigned int bitString = 0 ;
- unsigned char center = image.at<unsigned char>( cv::Point( x, y ) );
- if(image.at<unsigned char>( cv::Point(x+1,y+0) ) > center ) bitString |= 0x1 << 0; /* E */
- if(image.at<unsigned char>( cv::Point(x+1,y+1) ) > center ) bitString |= 0x1 << 1; /* SE */
- if(image.at<unsigned char>( cv::Point(x+0,y+1) ) > center ) bitString |= 0x1 << 2; /* S */
- if(image.at<unsigned char>( cv::Point(x-1,y+1) ) > center ) bitString |= 0x1 << 3; /* SW */
- if(image.at<unsigned char>( cv::Point(x-1,y+0) ) > center ) bitString |= 0x1 << 4; /* W */
- if(image.at<unsigned char>( cv::Point(x-1,y-1) ) > center ) bitString |= 0x1 << 5; /* NW */
- if(image.at<unsigned char>( cv::Point(x+0,y-1) ) > center ) bitString |= 0x1 << 6; /* N */
- if(image.at<unsigned char>( cv::Point(x+1,y-1) ) > center ) bitString |= 0x1 << 7; /* NE */
- if(bMapping) bitString = valMap[bitString];
- imageLBP.at<unsigned char>( cv::Point(x, y) ) = bitString;
- }
- }
-
- if ( !cv::imwrite( argv[2], imageLBP ) )
- {
- std::cerr << "Output mage name not valid." << std::endl;
- return 3;
- }
-
- return 0;
- }
使用方法
- /** Convert to 256 Code LBP Image */
- /** 转换为 256 Code LBP图 */
- // Program.exe [原始图像路径] [输出图像路径] 0
-
- /** Convert to 56 Code LBP Image */
- /** 转换为 56 Code LBP图 */
- // Program.exe [原始图像路径] [输出图像路径] 1
实验结果
原始图像及其对应的256 Code和56 Code LBP图
光照发生改变的图像及其对应的256 Code和56 Code LBP图
由上图可以看出,当图像发生光照变化时,其提取的LBP图是基本上不变的;而56 Code LBP图相对于256Code LBP图变化会更小一些。
|