You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
EasyPR/thirdparty/LBP/lbp.cpp

276 lines
11 KiB

#include "lbp.hpp"
#include "helper.hpp"
using namespace cv;
//------------------------------------------------------------------------------
// cv::olbp
//------------------------------------------------------------------------------
namespace libfacerec {
template <typename _Tp> 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<src.rows - 1; i++) {
for (int j = 1; j<src.cols - 1; j++) {
_Tp center = src.at<_Tp>(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<unsigned char>(i - 1, j - 1) = code;
}
}
}
}
void libfacerec::olbp(InputArray src, OutputArray dst) {
switch (src.getMat().type()) {
case CV_8SC1: olbp_<char>(src, dst); break;
case CV_8UC1: olbp_<unsigned char>(src, dst); break;
case CV_16SC1: olbp_<short>(src, dst); break;
case CV_16UC1: olbp_<unsigned short>(src, dst); break;
case CV_32SC1: olbp_<int>(src, dst); break;
case CV_32FC1: olbp_<float>(src, dst); break;
case CV_64FC1: olbp_<double>(src, dst); break;
default: break;
}
}
//------------------------------------------------------------------------------
// cv::varlbp
//------------------------------------------------------------------------------
namespace libfacerec {
template <typename _Tp> 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<neighbors; n++) {
// sample points
float x = static_cast<float>(radius)* cos(2.0f * (float)CV_PI*n / static_cast<float>(neighbors));
float y = static_cast<float>(radius)* -sin(2.0f * (float)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 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<float>(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<float>(i, j) = t - _mean.at<float>(i, j);
_mean.at<float>(i, j) = (_mean.at<float>(i, j) + (_delta.at<float>(i, j) / (1.0f * (n + 1)))); // i am a bit paranoid
_m2.at<float>(i, j) = _m2.at<float>(i, j) + _delta.at<float>(i, j) * (t - _mean.at<float>(i, j));
}
}
}
// calculate result
for (int i = radius; i < src.rows - radius; i++) {
for (int j = radius; j < src.cols - radius; j++) {
dst.at<float>(i - radius, j - radius) = _m2.at<float>(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_<char>(src, dst, radius, neighbors); break;
case CV_8UC1: varlbp_<unsigned char>(src, dst, radius, neighbors); break;
case CV_16SC1: varlbp_<short>(src, dst, radius, neighbors); break;
case CV_16UC1: varlbp_<unsigned short>(src, dst, radius, neighbors); break;
case CV_32SC1: varlbp_<int>(src, dst, radius, neighbors); break;
case CV_32FC1: varlbp_<float>(src, dst, radius, neighbors); break;
case CV_64FC1: varlbp_<double>(src, dst, radius, neighbors); break;
default: break;
}
}
//------------------------------------------------------------------------------
// cv::elbp
//------------------------------------------------------------------------------
namespace libfacerec {
template <typename _Tp> 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<neighbors; n++) {
// sample points
float x = static_cast<float>(-radius) * sin(2.0f*(float)CV_PI*n / static_cast<float>(neighbors));
float y = static_cast<float>(radius)* cos(2.0f*(float)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 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<float>(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<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;
}
}
}
}
}
namespace libfacerec {
template <typename _Tp> 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<float>(radius)* cos(2.0f * (float)CV_PI * n / static_cast<float>(neighbors));
float y = static_cast<float>(radius)* -sin(2.0f * (float)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 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<float>(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<unsigned int>(i - radius, j - radius) += ((t > src.at<_Tp>(i, j)) && (abs(t - src.at<_Tp>(i, j)) > std::numeric_limits<float>::epsilon())) << n;
}
}
}
}
}
void libfacerec::elbp0(const Mat& src, Mat& dst, int radius, int neighbors) {
switch (src.type()) {
case CV_8SC1: elbp0<char>(src, dst, radius, neighbors); break;
case CV_8UC1: elbp0<unsigned char>(src, dst, radius, neighbors); break;
case CV_16SC1: elbp0<short>(src, dst, radius, neighbors); break;
case CV_16UC1: elbp0<unsigned short>(src, dst, radius, neighbors); break;
case CV_32SC1: elbp0<int>(src, dst, radius, neighbors); break;
case CV_32FC1: elbp0<float>(src, dst, radius, neighbors); break;
case CV_64FC1: elbp0<double>(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_<char>(src, dst, radius, neighbors); break;
case CV_8UC1: elbp_<unsigned char>(src, dst, radius, neighbors); break;
case CV_16SC1: elbp_<short>(src, dst, radius, neighbors); break;
case CV_16UC1: elbp_<unsigned short>(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: 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;
}