BRINT: A binary rotation invariant and noise tolerant texture descriptor

原文地址:
https://ieeexplore.ieee.org/document/6738053
本文仅翻译论文第二章详细介绍BRINT的内容

BRINT:一种二进制旋转不变的抗噪声描述符

BRINT_S描述符

局部BRINT_S描述符的构造如图2所示。与原始LBP方法中的采样方案类似,我们对中心像素Xc周围的像素进行采样,但在半径r的任何圆上,我们限制采样点数为8的倍数,因此p=8q,q为正整数。因此,在半径r上采样的Xc的邻居是Xr,8q=[Xr,8q,0,·····,Xr,8q8q−1] T。
与原始LBP不同,我们通过沿弧局部平均来变换相邻向量Xr,8q,
在这里插入图片描述
如图2所示,使得Yr,q中的邻居数始终为8。
在这里插入图片描述
图2 BNT_S描述符的说明:BRINT引入了量化前平均的思想,首先将原始邻域转换为新的Yr,8q,i,其中i=0,…,7,在中心像素的灰度值处对Yr,8q,i进行阈值化,以生成二值模式,而不是直接从每个相邻像素Xr,8q,i, i = 0, . . . , 8q − 1,的精确灰度值中减去中心像素的灰度值Xc

给定Yr,q = [yr,q,0, · · · , yr,q,7]T我们可以简单地计算一个关于中心像素的二进制模式,如LBP:
在这里插入图片描述
其中,BNT_S表示“二进制噪声容限符号”。我们可以很容易地看到,对于任何参数对(r,q),总共有2^8=256个BNT_Sr,q二进制模式。此外,从Xr,8q到Yr,q的转换使模式对噪声更加鲁棒。
由于旋转不变性是我们声明的目标之一,为了避免统一模式的局限性,我们遵循LBPri,r,q的启发,将旋转下的二进制表示的相等版本分组,并将代码分配给结果组。那么,BRINT_Sr,q的形式定义为
在这里插入图片描述
其中,旋转函数ROR(•,•)与LBP中的相同,将一个刻度的柱状图单元数量从256个减少到36个。因此,将Yr,q中的点数固定为常数8的动机是限制具有比例的直方图箱的增长。
对于控制采样和平均圆中相邻邻居数量的参数q,我们采用了采样方案(r,p)∈ {(1,8),(2,24),(3,24),···,(r,24)}作为实现操作符的合理起点,但不能保证它们为给定任务生成最佳操作符。
图3通过对比BRINT_Sr,q与传统LBPri,r,p描述符的分类性能,验证了BRINT_Sr,q作为尺度数函数的基本行为。分类结果显示,三个Outex数据库的分类性能有了显著的提升,BLP的最佳结果。
在这里插入图片描述
图3 使用Ojala等人(BLP)指定的Outex数据库中的所有三个基准测试套件,比较BRINT_S描述符和传统LBPri描述符的分类精度。实验装置与LBP保持一致。结果有力地表明,所提出的BRINT_S描述符明显优于传统的LBPri描述符。

就计算成本而言,所提出的BRINT_S描述符并不意味着比传统的LBPriu2复杂度有所增加。特别是,BRINT_S总是处理基于8个点的局部二进制模式,而对于LBPriu2,从LBP到LBPriu2的映射需要一个包含2^p个元素的大型查找表。

BRINT_M描述符

受BRINT_S取得的显著分类结果的激励,考虑到CLBP_CSM特征的性能优于郭等人提出的CLBP单一特征LBPriu2,我们希望通过提出BRINT_M来进一步利用CLBP_M描述符。
给定一个中心像素Xc及其p个相邻像素Xr,p,0,···,Xr,p,p−1,如图2所示,我们首先计算中心像素Xc与其相邻像素之间的局部差值的绝对值:
在这里插入图片描述
继CLBP中的工作之后,∆r, 8q是局部差异的重要分量。与(2)类似,∆r, 8q转换为Zr,q,i=
在这里插入图片描述
我们计算了基于Z的二进制模式BNT_M(二进制噪声容限幅值):
在这里插入图片描述其中,µl是局部阈值。请注意,在CLBP中定义的CLBP_M描述符使用全局阈值,而在原始LBP操作符中,阈值是中心像素值,这明显随像素而异。因此,我们建议使用局部变化的阈值,而不是使用恒定的全局阈值:
在这里插入图片描述
定义BNT_M后,BRINT_M定义为:
在这里插入图片描述
最后,与CLBP一致,我们还将中心像素表示为两个二进制中的一个:
在这里插入图片描述
其中,µI,r是不包括边界像素的整个图像的平均值:
在这里插入图片描述

多分辨率BRINT和分类

到目前为止,BRINT描述符是从一个分辨率中提取出来的,该分辨率是位于半径为r的圆上的8q像素的圆对称邻域集。鉴于我们方法的一个目标是处理大量不同的尺度,通过改变r,我们可以实现不同空间分辨率的操作符,理想情况下,通过将来自多个分辨率的二进制直方图连接到单个直方图来表示纹理面片,这显然要求在每个分辨率下生成的直方图特征具有低维性。因此BRINT_CSM,BRINT_C、BRINT_S和BRINT_M的联合直方图的维数非常高,为36∗ 36∗ 2=2592,为了减少所需的统计堆栈数量,我们采用BRINT_CSr,q_CMr,q描述符,即联合直方图BRINT_C∗ BRINT_Sr,q与BRINT_C∗ BRINT_Mr,q连接,生成一个低维直方图:36∗ 2+36∗ 2=144。作为比较点,作为比较点,在实验结果中,我们还将评估BRINT_Sr,q_Mr,q,其维数为36+36=72。
实际分类通过简单最近邻分类器(NNC)执行:最近邻分类器(NNC)应用于归一化布氏直方图特征向量hi和hj,使用χ2距离度量,如CBLP所示。

C++代码

参考https://github.com/bhavikngala/BRINT-features

misc.hpp

#ifndef MISC_HPP
#define MISC_HPP

#include <vector>
#include <array>
#include <climits>
#include <cmath>

using std::vector;
using std::array;

namespace misc{
    
    

	// find min{ROR(x, i)} i=0..i; ROR -> right circular shift
	unsigned char minROR(unsigned char x, int numShifts);

	// vector of cordinates of circular neighbourhood
	// and interpolation weights
	// [floor_x, floor_y, ceil_x, ceil_y, w1, w2, w3, w4]
	vector<array<float, 8>> getNeighbourhoodCoordinates(int radius,
		int neighbours);
	
}

#endif

misc.cpp

#include "misc.hpp"

/*
** Author: Bhavik N Gala
** Email: [email protected]
*/

using std::floor;
using std::ceil;
using std::min;

namespace misc{
    
    
	vector<array<float, 8>> getNeighbourhoodCoordinates(int radius,
		int neighbours){
    
    
		// vector of cordinates and interpolation weights
		// [floor_x, floor_y, ceil_x, ceil_y, w1, w2, w3, w4]
		vector<array<float, 8>> neighbourhoodCoords;
		//float theta = 2.0*M_PI/neighbours;

		for(int i=0; i<neighbours; i++){
    
    
			// array template
			array<float, 8> neighbourhoodCoord;
			// theta = 2*pi/neighbours
			// x = r*cos(i * theta) + r
			// y = r*sin(i * theta) + r
			// adding r for translating center to image center
			float x = (float)(radius)*cos(i*2.0*M_PI/neighbours) + (float)(radius);
			float y = (float)(radius)*sin(i*2.0*M_PI/neighbours) + (float)(radius);

			// relative indices
			neighbourhoodCoord[0] = floor(x); // fx
			neighbourhoodCoord[1] = floor(y); // fy
			neighbourhoodCoord[2] = ceil(x);  // cx
			neighbourhoodCoord[3] = ceil(y);  // cy

			// fractional parts
			float tx = x-floor(x);
			float ty = y-floor(y);

			// weights
			neighbourhoodCoord[4] = (1-tx) * (1-ty); // w1
			neighbourhoodCoord[5] =    tx  * (1-ty); // w2
			neighbourhoodCoord[6] = (1-tx) *    ty;  // w3
			neighbourhoodCoord[7] =    tx  *    ty;  // w4

			// add array to vector
			neighbourhoodCoords.push_back(neighbourhoodCoord);
		}
		return neighbourhoodCoords;
	}

	unsigned char minROR(unsigned char x, int numShifts){
    
    
		unsigned char m = x;
		for(int i=1; i<numShifts; i++){
    
    
			m = min((unsigned char)((x >> i)|(x << (CHAR_BIT-i))), m);
		}
		return m;
	}
}

brint.hpp

#ifndef BRINT_HPP
#define  BRINT_HPP

#include <cmath>
#include <limits>
#include <array>
#include <vector>
#include <opencv2/core/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc.hpp>

#include "misc.hpp"

using namespace cv;
using namespace std;

namespace features{
    
    
	class Brint{
    
    
	public:
		static void brint_s(const Mat& src, Mat& dst,
				Mat& hist, int radius, int neighbours, bool normalizeHist);

		static void brint_m(const Mat& src, Mat& dst,
				Mat& hist, int radius, int neighbours, bool normalizeHist);

		static void brint_c(const Mat& src, Mat& dst,
				Mat& hist, int radius, int neighbours, bool normalizeHist);

		static void brint_cs_cm(const Mat& src, Mat& hist,
				int radius, int neighbours, bool normalizeHist);
	};
}

#endif

brint.cpp

#include "brint.hpp"
#include <iostream>

/*
** Author: Bhavik N Gala
** Email: [email protected]
*/

namespace features{
    
    

	void Brint::brint_s(const Mat& src, Mat& dst, Mat& hist, int radius,
		int neighbours, bool normalizeHist){
    
    

		// computes 'Binary Noise Tolerant Sign'
		// features for an given image

		// TODO: assert neighbours%8 == 0
		int q = (int)(neighbours/8);

		// TODO: check out other interpolation methods
		// interpolating pixel values
		// vector of cordinates and interpolation weights
		// [floor_x, floor_y, ceil_x, ceil_y, w1, w2, w3, w4]
		vector<array<float, 8>> neighbourhoodCoords = \
			misc::getNeighbourhoodCoordinates(radius, neighbours);

		// int dataType = src.depth();
		dst = Mat::zeros(src.rows-2*radius, src.cols-2*radius, CV_8U);

		// iterating through each pixel value
		for(int y=radius; y<src.rows-radius; y++){
    
    
			for(int x=radius; x<src.cols-radius; x++){
    
    
				// getting the neighbourhood
				Mat neighbourhood(src, Rect(x-radius, y-radius,
					2*radius+1, 2*radius+1));
				uint8_t *nData = neighbourhood.data;

				// array of circular neighbourhood pixel values
				float neighbourVector[neighbours];

				// iterating through all the points in the circular
				// neighbourhood and interpolating them
				for(int p=0; p<neighbours; p++){
    
    

					array<float, 8> xy = neighbourhoodCoords[p];

					// s = w1*src(fy,fx)+w2*src(fy,cx)+w3*src(cy,fx)+w4*src(cy,cx)
					Scalar p1 = neighbourhood.at<uchar>((int)(xy[1]), (int)(xy[0]));
					Scalar p2 = neighbourhood.at<uchar>((int)(xy[1]), (int)(xy[2]));
					Scalar p3 = neighbourhood.at<uchar>((int)(xy[3]), (int)(xy[0]));
					Scalar p4 = neighbourhood.at<uchar>((int)(xy[3]), (int)(xy[2]));
					//neighbourVector[p] = xy[4]*nData[(int)(xy[1]), (int)(xy[0])] + xy[5]*nData[(int)(xy[1]), (int)(xy[2])] + xy[6]*nData[(int)(xy[3]), (int)(xy[0])] + xy[7]*nData[(int)(xy[3]), (int)(xy[2])];
					neighbourVector[p] = xy[4]*p1.val[0] + xy[5]*p2.val[0] + xy[6]*p3.val[0] + xy[7]*p4.val[0];
				}

				// transform the neighbour vector by local averaging
				// along the arc
				unsigned char bnt_s = 0;
				for(int i=0; i<8; i++){
    
    
					float y = 0;
					// y_r,q,i=(1/q)*sum(from k=0,..,q-1)(x_r,8q,qi+k)
					for(int k=0; k<q; k++){
    
    
						y += neighbourVector[q*i + k];
					}
					y /= q;

					// compute LBP
					unsigned char s = ((y-nData[radius, radius])>=0) ? 1 : 0;
					bnt_s += s * (unsigned char)(pow(2, i));
				}

				// addding rotation invariance
				// BRINT_S = min{ROR(BNT_S, i)} i=0..7
				dst.at<unsigned char>(y-radius, x-radius) = misc::minROR(bnt_s, q);
			}
		}

		// compute histogram
		// number of bins in the histogram
		int histSize = 256;
		// set the range of values, from 0 to 255
		// upper value is exclusive
		float range[] = {
    
    0, 2};
		const float* histRange = {
    
    range};
		// uniform size of bins
		bool uniform = true;
		// set this flag to accumulate values of bins with previous histogram
		bool accumulate = false;
		cv::calcHist(&dst, 1, 0, Mat(), hist, 1, &histSize, &histRange, uniform, accumulate);

		if(normalizeHist){
    
    
			// min output value = 0; max output value = 255
			normalize(hist, hist, 0, 255, NORM_MINMAX, -1, Mat());
		}
	}

	void Brint::brint_m(const Mat& src, Mat& dst, Mat& hist, int radius,
		int neighbours, bool normalizeHist){
    
    
		// computes 'Binary Noise Tolerant Magnitude'
		// features for an given image

		// TODO: assert neighbours%8 == 0
		int q = (int)(neighbours/8);

		// TODO: check out other interpolation methods
		// interpolating pixel values
		// vector of cordinates and interpolation weights
		// [floor_x, floor_y, ceil_x, ceil_y, w1, w2, w3, w4]
		vector<array<float, 8>> neighbourhoodCoords = \
			misc::getNeighbourhoodCoordinates(radius, neighbours);

		dst = Mat::zeros(src.rows-2*radius, src.cols-2*radius, CV_8U);

		// iterating through each pixel value
		for(int y=radius; y<src.rows-radius; y++){
    
    
			for(int x=radius; x<src.cols-radius; x++){
    
    
				// getting the neighbourhood
				Mat neighbourhood(src, Rect(x-radius, y-radius,
					2*radius+1, 2*radius+1));
				uint8_t *nData = neighbourhood.data;

				// array of circular neighbourhood pixel values
				float neighbourVector[neighbours];

				// iterating through all the points in the circular
				// neighbourhood and interpolating them
				for(int p=0; p<neighbours; p++){
    
    

					array<float, 8> xy = neighbourhoodCoords[p];

					// s = w1*src(fy,fx)+w2*src(fy,cx)+w3*src(cy,fx)+w4*src(cy,cx)
					neighbourVector[p] = \
					xy[4]*nData[(int)(xy[1]), (int)(xy[0])] + \
					xy[5]*nData[(int)(xy[1]), (int)(xy[2])] + \
					xy[6]*nData[(int)(xy[3]), (int)(xy[0])] + \
					xy[7]*nData[(int)(xy[3]), (int)(xy[2])];

					// delta_r = abs(x_r,p,i - x_c)
					neighbourVector[p] = abs(neighbourVector[p] - nData[radius, radius]);
				}

				// transform the neighbour vector by local averaging
				// along the arc
				float z[8];
				for(int i=0; i<8; i++){
    
    
					float y = 0;
					// y_r,q,i=(1/q)*sum(from k=0,..,q-1)(x_r,8q,qi+k)
					for(int k=0; k<q; k++){
    
    
						y += neighbourVector[q*i + k];
					}
					y /= q;
					z[i] = y;
				}
				// compute mean of the array z
				float mu_z = 0;
				for(int i=0; i<8; i++){
    
    
					mu_z += z[i];
				}
				mu_z /= 8;

				unsigned char bnt_m = 0;
				for(int i=0; i<8; i++){
    
    
					// compute LBP
					unsigned char s = ((z[i]-mu_z)>=0) ? 1 : 0;
					bnt_m += s * (unsigned char)(pow(2, i));
				}

				// addding rotation invariance
				// BRINT_M = min{ROR(BNT_M, i)} i=0..7
				dst.at<unsigned char>(y-radius, x-radius) = misc::minROR(bnt_m, q);
			}
		}

		// compute histogram
		// number of bins in the histogram
		int histSize = 256;
		// set the range of values, from 0 to 255
		// upper value is exclusive
		float range[] = {
    
    0, 2};
		const float* histRange = {
    
    range};
		// uniform size of bins
		bool uniform = true;
		// set this flag to accumulate values of bins with previous histogram
		bool accumulate = false;
		calcHist(&dst, 1, 0, Mat(), hist, 1, &histSize, &histRange, uniform, accumulate);

		if(normalizeHist){
    
    
			// min output value = 0; max output value = 255
			normalize(hist, hist, 0, 255, NORM_MINMAX, -1, Mat());
		}
	}

	void Brint::brint_c(const Mat& src, Mat& dst, Mat& hist, int radius,
		int neighbours, bool normalizeHist){
    
    
		// computes 'Binary Noise Tolerant Center'
		// features for an given image

		dst = Mat::zeros(src.rows-2*radius, src.cols-2*radius, CV_8U);

		uint8_t *srcData = src.data;
		// mean of all the pixels in the image
		float mu = (cv::mean(src(Range(radius, src.rows-radius),
						  Range(radius, src.cols-radius))))[0];

		// iterating through each pixel value
		for(int y=radius; y<src.rows-radius; y++){
    
    
			for(int x=radius; x<src.cols-radius; x++){
    
    
				unsigned char s = ((srcData[y, x]-mu)>=0) ? 1 : 0;
				dst.at<unsigned char>(y-radius, x-radius) = s;
			}
		}

		// compute histogram
		// number of bins in the histogram
		int histSize = 2;
		// set the range of values, from 0 to 1
		// upper value is exclusive
		float range[] = {
    
    0, 2};
		const float* histRange = {
    
    range};
		// uniform size of bins
		bool uniform = true;
		// set this flag to accumulate values of bins with previous histogram
		bool accumulate = false;
		calcHist(&dst, 1, 0, Mat(), hist, 1, &histSize, &histRange, uniform, accumulate);

		if(normalizeHist){
    
    
			// min output value = 0; max output value = 255
			normalize(hist, hist, 0, 255, NORM_MINMAX, -1, Mat());
		}
	}

	void Brint::brint_cs_cm(const Mat& src, Mat& hist, int radius, int neighbours, bool normalizeHist){
    
    
		// computes BRINT feature
		// computes joint histogram from BNT_C a)nd BNT_S; BNT_C and BNT_M
		// concatenates the two joint histogram

		// TODO: assert neighbours%8 == 0
		int q = (int)(neighbours/8);
		// TODO: check out other interpolation methods
		// interpolating pixel values
		// vector of cordinates and interpolation weights
		// [floor_x, floor_y, ceil_x, ceil_y, w1, w2, w3, w4]
		vector<array<float, 8>> neighbourhoodCoords = \
			misc::getNeighbourhoodCoordinates(radius, neighbours);

		Mat bnt_s = Mat::zeros(src.rows-2*radius, src.cols-2*radius, CV_8U);
		Mat bnt_m = Mat::zeros(src.rows-2*radius, src.cols-2*radius, CV_8U);
		Mat bnt_c = Mat::zeros(src.rows-2*radius, src.cols-2*radius, CV_8U);

		uint8_t *srcData = src.data;

		// mean of all the pixels in the image
		float mu = (cv::mean(src(Range(radius, src.rows-radius),
								 Range(radius, src.cols-radius))))[0];

		for(int y=radius; y<src.rows-radius; y++){
    
    
			for(int x=radius; x<src.cols-radius; x++){
    
    
				// getting the neighbourhood
				Mat neighbourhood(src, Rect(x-radius, y-radius,
											2*radius+1, 2*radius+1));
				uint8_t *nData = neighbourhood.data;

				// array of circular neighbourhood pixel values
				float neighbourVector[neighbours];

				// iterating through all the points in the circular
				// neighbourhood and interpolating them
				for(int p=0; p<neighbours; p++){
    
    

					array<float, 8> xy = neighbourhoodCoords[p];

					// s = w1*src(fy,fx)+w2*src(fy,cx)+w3*src(cy,fx)+w4*src(cy,cx)
					Scalar p1 = neighbourhood.at<uchar>((int)(xy[1]), (int)(xy[0]));
					Scalar p2 = neighbourhood.at<uchar>((int)(xy[1]), (int)(xy[2]));
					Scalar p3 = neighbourhood.at<uchar>((int)(xy[3]), (int)(xy[0]));
					Scalar p4 = neighbourhood.at<uchar>((int)(xy[3]), (int)(xy[2]));
					neighbourVector[p] = xy[4]*p1.val[0] + xy[5]*p2.val[0] + xy[6]*p3.val[0] + xy[7]*p4.val[0];
				}

				// transform the neighbour vector by local averaging
				// along the arc
				float z[8];
				for(int i=0; i<8; i++){
    
    
					float y = 0;
					// y_r,q,i=(1/q)*sum(from k=0,..,q-1)(x_r,8q,qi+k)
					for(int k=0; k<q; k++){
    
    
						y += neighbourVector[q*i + k];
					}
					y /= q;
					z[i] = y;
				}
				// compute mean of the array z
				float mu_z = 0;
				for(int i=0; i<8; i++){
    
    
					mu_z += z[i];
				}
				mu_z /= 8;

				unsigned char bnt_s1 = 0;
				unsigned char bnt_m1 = 0;
				unsigned char s;
				for(int i=0; i<8; i++){
    
    
					// compute LBP
					// bnt_s
					s = ((z[i]-nData[radius, radius])>=0) ? 1 : 0;
					bnt_s1 += s * (unsigned char)(pow(2, i));
					// bnt_m
					s = ((z[i]-mu_z)>=0) ? 1 : 0;
					bnt_m1 += s * (unsigned char)(pow(2, i));
				}
				// bnt_c
				s = ((srcData[y, x]-mu)>=0) ? 1 : 0;

				bnt_s.at<unsigned char>(y-radius, x-radius) = misc::minROR(bnt_s1, q);
				bnt_m.at<unsigned char>(y-radius, x-radius) = misc::minROR(bnt_m1, q);
				bnt_c.at<unsigned char>(y-radius, x-radius) = s;
			}
		}

		// compute histogram
		// number of bins in the histogram
		int histSize1 = 256;
		int histSize2 = 2;
		// set the range of values, from 0 to 255
		// upper value is exclusive
		float range1[] = {
    
    0, 256};
//		float range2[] = {0, 2};
		const float* histRange1 = {
    
    range1};
//		const float* histRange2= {range2};

		Mat hist_cs;
		Mat hist_cm;

		calcHist(&bnt_s, 1, 0, Mat(), hist_cs, 1, &histSize1, &histRange1, true, false); // clear the hist_cs array
		calcHist(&bnt_c, 1, 0, Mat(), hist_cs, 1, &histSize1, &histRange1, true, true); // accumulate the hist_cs array

		calcHist(&bnt_m, 1, 0, Mat(), hist_cm, 1, &histSize1, &histRange1, true, false); // clear the hist_cs array
		calcHist(&bnt_c, 1, 0, Mat(), hist_cm, 1, &histSize1, &histRange1, true, true); // accumulate the hist_cs array

		if(normalizeHist){
    
    
			// min output value = 0; max output value = 255
			normalize(hist_cs, hist_cs, 0, 255, NORM_MINMAX, -1, Mat());
			normalize(hist_cm, hist_cm, 0, 255, NORM_MINMAX, -1, Mat());
		}

		// concatenate the histograms
		vconcat(hist_cs, hist_cm, hist);
	}

}

test_brint.cpp

#include "../utils/misc.hpp"
#include "../utils/brint.hpp"

using namespace std;
using namespace cv;

int main(int argc, char** argv){
    
    
	Mat image = imread("./data/leaf.png", IMREAD_GRAYSCALE);
	Mat brintImage;
	Mat hist;

//	Mat saltpepper_noise = Mat::zeros(image.rows, image.cols,CV_8U);
//	randu(saltpepper_noise,0,255);
//
//	Mat black = saltpepper_noise < 30;
//	Mat white = saltpepper_noise > 225;

//	Mat saltpepper_img = image.clone();
//	saltpepper_img.setTo(255,white);
//	saltpepper_img.setTo(0,black);
//	imwrite("./results/leaf_sp.jpg", saltpepper_img);

//	namedWindow("saltNpepper", WINDOW_NORMAL);
//	resizeWindow("saltNpepper", 1080, 1280);
//	imshow("saltNpepper", saltpepper_img);

	features::Brint::brint_s(image, brintImage, hist, 2, 32);
	imwrite("./results/as_brint_s_r2_n32.jpg", brintImage);

//	namedWindow( "Image", WINDOW_NORMAL);
//	resizeWindow("Image", 1280, 1080);
//	namedWindow( "Texture r=2, n=32", WINDOW_NORMAL );
//	resizeWindow("Texture r=2, n=32", 1280, 1080);
//	imshow("Image", image);
//	imshow( "Texture r=2, n=32", brintImage );


//	namedWindow( "Texture r=4, n=32", WINDOW_NORMAL );
//	resizeWindow("Texture r=4, n=32", 1280, 1080);
	features::Brint::brint_s(image, brintImage, hist, 4, 32);
	imwrite("./results/as_brint_s_r4_n32.jpg", brintImage);
//	imshow( "Texture r=4, n=32", brintImage );

//	namedWindow( "Texture r=8, n=32", WINDOW_NORMAL );
//	resizeWindow("Texture r=8, n=32", 1280, 1080);
	features::Brint::brint_s(image, brintImage, hist, 8, 32);
	imwrite("./results/as_brint_s_r8_n32.jpg", brintImage);
//	imshow( "Texture r=8, n=32", brintImage );

//	namedWindow( "Texture r=12, n=32", WINDOW_NORMAL );
//	resizeWindow("Texture r=12, n=32", 1280, 1080);
	features::Brint::brint_s(image, brintImage, hist, 12, 32);
	imwrite("./results/as_brint_s_r12_n32.jpg", brintImage);
//	imshow( "Texture r=12, n=32", brintImage );

//    waitKey(0);
	return 0;

}

python代码

BRINT.py

import cv2
import numpy as np
import math


def brint_s(srcimg, radius, neighbours):
    src = cv2.cvtColor(srcimg, cv2.COLOR_RGB2GRAY)
    q = int(neighbours / 8)
    neighbourhoodCoords = getNeighbourhoodCoordinates(radius, neighbours)


    height = src.shape[0] - 2 * radius  # rows
    width = src.shape[1] - 2 * radius  # cols

    dst = np.zeros((height, width), dtype=np.uint8)
    # dst = src.resize(height,width)
    # cv2.imshow("1",dst)
    # cv2.waitKey(0)
    # print(radius,height+radius,width+radius)
    for y in range(radius, height+radius):
        for x in range(radius, width+radius):
            # 获得邻域
            neighbourhood = src[int(x - radius):int(x + radius + 1), int(y - radius):int(y + radius + 1)]

            nData = neighbourhood.data
            # 邻域像素值
            neighbourVector = np.zeros(neighbours, dtype=float)

            for p in range(0, neighbours):
                xy = neighbourhoodCoords[p]

                p1 = neighbourhood[int(xy[1]), int(xy[0])]
                p2 = neighbourhood[int(xy[1]), int(xy[2])]
                p3 = neighbourhood[int(xy[3]), int(xy[0])]
                p4 = neighbourhood[int(xy[3]), int(xy[2])]
                neighbourVector[p] = xy[4] * p1 + xy[5] * p2 + xy[6] * p3 + xy[7] * p4

            bnt_s = 0
            for i in range(0, 8):
                m = 0
                for k in range(0, q):
                    m += neighbourVector[q * i + k]
                m /= q
                if m - nData[radius, radius] >= 0:
                    s = 1
                else:
                    s = 0
                bnt_s += s * (2 ** i)

            dst[y - radius, x - radius] = float(minROR(bnt_s, q))
            
    tmp1 = np.zeros((height, width), dtype=np.uint8)
    cv2.transpose(dst,tmp1)
    return tmp1

def getNeighbourhoodCoordinates(radius,neighbours):
    neighbourhoodCoords = np.zeros((neighbours,8),dtype=float)
    for i in range(0,neighbours):
        # neighbourhoodCoord = np.zeros(8,dtype=float)
        x = float(radius*math.cos(i*2*math.pi/neighbours)+radius)
        y = float(radius*math.sin(i*2*math.pi/neighbours+radius))

        neighbourhoodCoords[i,0] = math.floor(x)
        neighbourhoodCoords[i,1] = math.floor(y)
        neighbourhoodCoords[i,2] = math.ceil(x)
        neighbourhoodCoords[i,3] = math.ceil(y)

        tx = float(x-math.floor(x))
        ty = float(y-math.floor(y))

        neighbourhoodCoords[i,4] = (1-tx)*(1-ty)
        neighbourhoodCoords[i,5] = tx*(1-ty)
        neighbourhoodCoords[i,6] = (1-tx)*ty
        neighbourhoodCoords[i,7] = tx*ty

    return neighbourhoodCoords


def minROR(x,numShifts):
    m=x
    for i in range(1,numShifts):
        m = min(m,(x>>i)|(x<<(8-i)))

    return m

main.py

import cv2
import numpy as np

from BRINT import brint_s

if __name__ == '__main__':
    img = cv2.imread("C:/Users/WRP/Desktop/3.jpg")
    dst = brint_s(img,2,32)
    cv2.imshow("BRINT_result",dst)
    cv2.waitKey(0)

猜你喜欢

转载自blog.csdn.net/weixin_45184581/article/details/124900123