// src为输入图像,dst为输出图像,radius为半径,neighbor为计算当前点LBP所需的邻域像素点数,也就是样本点个数 template <typename _Tp> static// 模板函数,根据不同的原始数据类型得到不同的结果 inlinevoidelbp_(InputArray _src, OutputArray _dst, int radius, int neighbors) { //get matrices Mat src = _src.getMat(); // allocate memory for result因此不用在外部给_dst分配内存空间,输出数据类型都是int _dst.create(src.rows-2*radius, src.cols-2*radius, CV_32SC1); Mat dst = _dst.getMat(); // zero dst.setTo(0); for(int n=0; n<neighbors; n++) { // sample points 获取当前采样点 float x = static_cast<float>(-radius) * sin(2.0*CV_PI*n/static_cast<float>(neighbors)); float y = static_cast<float>(radius) * cos(2.0*CV_PI*n/static_cast<float>(neighbors)); // relative indices 下取整和上取整 int fx = static_cast<int>(floor(x)); // 向下取整 int fy = static_cast<int>(floor(y)); int cx = static_cast<int>(ceil(x)); // 向上取整 int cy = static_cast<int>(ceil(y)); // fractional part 小数部分 float tx = x - fx; float ty = y - fy; // set interpolation weights 设置四个点的插值权重 float w1 = (1 - tx) * (1 - ty); float w2 = tx * (1 - ty); float w3 = (1 - tx) * ty; float w4 = tx * ty; // iterate through your data 循环处理图像数据 for(int i=radius; i < src.rows-radius;i++) { for(int j=radius;j < src.cols-radius;j++) { // calculate interpolated value 计算插值,t表示四个点的权重和 float t = w1*src.at<_Tp>(i+fy,j+fx) + w2*src.at<_Tp>(i+fy,j+cx) + w3*src.at<_Tp>(i+cy,j+fx) + w4*src.at<_Tp>(i+cy,j+cx); // floating point precision, so check some machine-dependent epsilon // std::numeric_limits<float>::epsilon()=1.192092896e-07F // 当t>=src(i,j)的时候取1,并进行相应的移位 dst.at<int>(i-radius,j-radius) += ((t > src.at<_Tp>(i,j)) || (std::abs(t-src.at<_Tp>(i,j)) < std::numeric_limits<float>::epsilon())) << n; } } } }
// 外部接口,根据不同的数据类型调用模板函数 staticvoidelbp(InputArray src, OutputArray dst, int radius, int neighbors) { int type = src.type(); switch (type) { case CV_8SC1: elbp_<char>(src,dst, radius, neighbors); break; case CV_8UC1: elbp_<unsignedchar>(src, dst, radius, neighbors); break; case CV_16SC1: elbp_<short>(src,dst, radius, neighbors); break; case CV_16UC1: elbp_<unsignedshort>(src,dst, radius, neighbors); break; case CV_32SC1: elbp_<int>(src,dst, radius, neighbors); break; case CV_32FC1: elbp_<float>(src,dst, radius, neighbors); break; case CV_64FC1: elbp_<double>(src,dst, radius, neighbors); break; default: string error_msg = format("Using Circle Local Binary Patterns for feature extraction only works on single-channel images (given %d). Please pass the image data as a grayscale image!", type); CV_Error(CV_StsNotImplemented, error_msg); break; } } Mat cv::elbp(InputArray src, int radius, int neighbors){ Mat dst; elbp(src, dst, radius, neighbors); return dst; }