#include "lbp.hpp" #include "helper.hpp" using namespace cv; //------------------------------------------------------------------------------ // cv::olbp //------------------------------------------------------------------------------ namespace libfacerec { template static void olbp_(InputArray _src, OutputArray _dst) { // get matrices Mat src = _src.getMat(); // allocate memory for result _dst.create(src.rows - 2, src.cols - 2, CV_8UC1); Mat dst = _dst.getMat(); // zero the result matrix dst.setTo(0); // calculate patterns for (int i = 1; i(i, j); unsigned char code = 0; code |= (src.at<_Tp>(i - 1, j - 1) >= center) << 7; code |= (src.at<_Tp>(i - 1, j) >= center) << 6; code |= (src.at<_Tp>(i - 1, j + 1) >= center) << 5; code |= (src.at<_Tp>(i, j + 1) >= center) << 4; code |= (src.at<_Tp>(i + 1, j + 1) >= center) << 3; code |= (src.at<_Tp>(i + 1, j) >= center) << 2; code |= (src.at<_Tp>(i + 1, j - 1) >= center) << 1; code |= (src.at<_Tp>(i, j - 1) >= center) << 0; dst.at(i - 1, j - 1) = code; } } } } void libfacerec::olbp(InputArray src, OutputArray dst) { switch (src.getMat().type()) { case CV_8SC1: olbp_(src, dst); break; case CV_8UC1: olbp_(src, dst); break; case CV_16SC1: olbp_(src, dst); break; case CV_16UC1: olbp_(src, dst); break; case CV_32SC1: olbp_(src, dst); break; case CV_32FC1: olbp_(src, dst); break; case CV_64FC1: olbp_(src, dst); break; default: break; } } //------------------------------------------------------------------------------ // cv::varlbp //------------------------------------------------------------------------------ namespace libfacerec { template static inline void varlbp_(InputArray _src, OutputArray _dst, int radius, int neighbors) { //get matrices Mat src = _src.getMat(); // allocate memory for result _dst.create(src.rows - 2 * radius, src.cols - 2 * radius, CV_32FC1); Mat dst = _dst.getMat(); // set initial values to zero dst.setTo(0.0); // allocate some memory for temporary on-line variance calculations Mat _mean = Mat::zeros(src.rows, src.cols, CV_32FC1); Mat _delta = Mat::zeros(src.rows, src.cols, CV_32FC1); Mat _m2 = Mat::zeros(src.rows, src.cols, CV_32FC1); for (int n = 0; n(radius)* cos(2.0f * (float)CV_PI*n / static_cast(neighbors)); float y = static_cast(radius)* -sin(2.0f * (float)CV_PI*n / static_cast(neighbors)); // relative indices int fx = static_cast(floor(x)); int fy = static_cast(floor(y)); int cx = static_cast(ceil(x)); int cy = static_cast(ceil(y)); // fractional part float ty = y - fy; float tx = x - fx; // 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++) { float t = static_cast(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)); _delta.at(i, j) = t - _mean.at(i, j); _mean.at(i, j) = (_mean.at(i, j) + (_delta.at(i, j) / (1.0f * (n + 1)))); // i am a bit paranoid _m2.at(i, j) = _m2.at(i, j) + _delta.at(i, j) * (t - _mean.at(i, j)); } } } // calculate result for (int i = radius; i < src.rows - radius; i++) { for (int j = radius; j < src.cols - radius; j++) { dst.at(i - radius, j - radius) = _m2.at(i, j) / (1.0f * (neighbors - 1)); } } } } void libfacerec::varlbp(InputArray src, OutputArray dst, int radius, int neighbors) { switch (src.getMat().type()) { case CV_8SC1: varlbp_(src, dst, radius, neighbors); break; case CV_8UC1: varlbp_(src, dst, radius, neighbors); break; case CV_16SC1: varlbp_(src, dst, radius, neighbors); break; case CV_16UC1: varlbp_(src, dst, radius, neighbors); break; case CV_32SC1: varlbp_(src, dst, radius, neighbors); break; case CV_32FC1: varlbp_(src, dst, radius, neighbors); break; case CV_64FC1: varlbp_(src, dst, radius, neighbors); break; default: break; } } //------------------------------------------------------------------------------ // cv::elbp //------------------------------------------------------------------------------ namespace libfacerec { template static inline void elbp_(InputArray _src, OutputArray _dst, int radius, int neighbors) { //get matrices Mat src = _src.getMat(); // allocate memory for result _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(-radius) * sin(2.0f*(float)CV_PI*n / static_cast(neighbors)); float y = static_cast(radius)* cos(2.0f*(float)CV_PI*n / static_cast(neighbors)); // relative indices int fx = static_cast(floor(x)); int fy = static_cast(floor(y)); int cx = static_cast(ceil(x)); int cy = static_cast(ceil(y)); // fractional part float ty = y - fy; float tx = x - fx; // 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 float t = static_cast(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 dst.at(i - radius, j - radius) += ((t > src.at<_Tp>(i, j)) || (std::abs(t - src.at<_Tp>(i, j)) < std::numeric_limits::epsilon())) << n; } } } } } namespace libfacerec { template static inline void elbp0(const Mat& src, Mat& dst, int radius, int neighbors) { neighbors = max(min(neighbors, 31), 1); // set bounds... // Note: alternatively you can switch to the new OpenCV Mat_ // type system to define an unsigned int matrix... I am probably // mistaken here, but I didn't see an unsigned int representation // in OpenCV's classic typesystem... dst = Mat::zeros(src.rows - 2 * radius, src.cols - 2 * radius, CV_32SC1); for (int n = 0; n < neighbors; n++) { // sample points float x = static_cast(radius)* cos(2.0f * (float)CV_PI * n / static_cast(neighbors)); float y = static_cast(radius)* -sin(2.0f * (float)CV_PI * n / static_cast(neighbors)); // relative indices int fx = static_cast(floor(x)); int fy = static_cast(floor(y)); int cx = static_cast(ceil(x)); int cy = static_cast(ceil(y)); // fractional part float ty = y - fy; float tx = x - fx; // 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++) { float t = static_cast(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)); // we are dealing with floating point precision, so add some little tolerance dst.at(i - radius, j - radius) += ((t > src.at<_Tp>(i, j)) && (abs(t - src.at<_Tp>(i, j)) > std::numeric_limits::epsilon())) << n; } } } } } void libfacerec::elbp0(const Mat& src, Mat& dst, int radius, int neighbors) { switch (src.type()) { case CV_8SC1: elbp0(src, dst, radius, neighbors); break; case CV_8UC1: elbp0(src, dst, radius, neighbors); break; case CV_16SC1: elbp0(src, dst, radius, neighbors); break; case CV_16UC1: elbp0(src, dst, radius, neighbors); break; case CV_32SC1: elbp0(src, dst, radius, neighbors); break; case CV_32FC1: elbp0(src, dst, radius, neighbors); break; case CV_64FC1: elbp0(src, dst, radius, neighbors); break; default: break; } } void libfacerec::elbp(InputArray src, OutputArray dst, int radius, int neighbors) { switch (src.type()) { case CV_8SC1: elbp_(src, dst, radius, neighbors); break; case CV_8UC1: elbp_(src, dst, radius, neighbors); break; case CV_16SC1: elbp_(src, dst, radius, neighbors); break; case CV_16UC1: elbp_(src, dst, radius, neighbors); break; case CV_32SC1: elbp_(src, dst, radius, neighbors); break; case CV_32FC1: elbp_(src, dst, radius, neighbors); break; case CV_64FC1: elbp_(src, dst, radius, neighbors); break; default: break; } } Mat libfacerec::spatial_histogram(InputArray _src, int numPatterns, int grid_x, int grid_y, bool normed) { Mat src = _src.getMat(); // calculate LBP patch size int width = src.cols / grid_x; int height = src.rows / grid_y; // allocate memory for the spatial histogram Mat result = Mat::zeros(grid_x * grid_y, numPatterns, CV_32FC1); // return matrix with zeros if no data was given if (src.empty()) return result.reshape(1, 1); // initial result_row int resultRowIdx = 0; // iterate through grid for (int i = 0; i < grid_y; i++) { for (int j = 0; j < grid_x; j++) { Mat src_cell = Mat(src, Range(i*height, (i + 1)*height), Range(j*width, (j + 1)*width)); Mat cell_hist = histc(src_cell, 0, (numPatterns - 1), true); // copy to the result matrix Mat result_row = result.row(resultRowIdx); cell_hist.reshape(1, 1).convertTo(result_row, CV_32FC1); // increase row count in result matrix resultRowIdx++; } } // return result as reshaped feature vector return result.reshape(1, 1); } //------------------------------------------------------------------------------ // cv::elbp, cv::olbp, cv::varlbp wrapper //------------------------------------------------------------------------------ Mat libfacerec::olbp(InputArray src) { Mat dst; olbp(src, dst); return dst; } Mat libfacerec::elbp(InputArray src, int radius, int neighbors) { Mat dst; elbp(src, dst, radius, neighbors); return dst; } Mat libfacerec::varlbp(InputArray src, int radius, int neighbors) { Mat dst; varlbp(src, dst, radius, neighbors); return dst; }