BRINT: un descriptor de textura invariante de rotación binaria y tolerante al ruido

Dirección original:
https://ieeexplore.ieee.org/document/6738053
Este artículo solo traduce el segundo capítulo del documento y presenta el contenido de BRINT en detalle

BRINT: un descriptor resistente al ruido invariable de rotación binaria

Descriptor BRINT_S

La estructura del descriptor BRINT_S local se muestra en la Figura 2. Similar al esquema de muestreo en el método LBP original, muestreamos píxeles alrededor del píxel central Xc, pero en cualquier círculo de radio r, limitamos el número de puntos de muestreo a un múltiplo de 8, por lo que p = 8q, donde q es un entero positivo. Así, los vecinos de Xc muestreados en el radio r son Xr,8q=[Xr,8q,0,····,Xr,8q8q−1]T.
A diferencia del LBP original, transformamos el vector vecino Xr,8q promediando localmente a lo largo del arco,
inserte la descripción de la imagen aquí
como se muestra en la Fig. 2, de modo que el número de vecinos en Yr,q sea siempre 8.
inserte la descripción de la imagen aquí
Figura 2 Descripción del descriptor BNT_S: BRINT introduce la idea de promediar antes de cuantificar, primero convirtiendo el vecindario original en un nuevo Yr,8q,i, donde i=0,...,7, en el valor de gris del el píxel central Yr, 8q, i tienen un umbral para generar un patrón binario, en lugar de restar directamente el valor de gris Xc del píxel central

Dado Yr,q = [yr,q,0, , yr,q,7]T, podemos simplemente calcular un patrón binario sobre el píxel central, como LBP: donde, BNT_S significa "Notación de tolerancia de ruido binaria"
inserte la descripción de la imagen aquí
. Podemos ver fácilmente que para cualquier par de parámetros (r,q), hay un total de 2^8=256 BNT_Sr,q patrones binarios. Además, la transición de Xr,8q a Yr,q hace que el patrón sea más resistente al ruido.
Dado que la invariancia de rotación es uno de nuestros objetivos declarados, para evitar las limitaciones del esquema unificado, seguimos la heurística de LBPri,r,q al agrupar versiones iguales de la representación binaria bajo rotación y asignar códigos a los grupos resultantes. Luego, la forma de BRINT_Sr,q se define como
inserte la descripción de la imagen aquí
donde la función de rotación ROR(•,•) es la misma que en LBP, reduciendo el número de celdas de histograma para una escala de 256 a 36. Por lo tanto, la motivación para fijar el número de puntos en Yr,q a una constante de 8 es limitar el crecimiento de los intervalos de histograma con escala.
Para el parámetro q que controla el número de vecinos adyacentes en el círculo de muestreo y promedio, empleamos el esquema de muestreo (r,p) ∈ {(1,8),(2,24),(3,24),·· ·,( r, 24)} como un punto de partida razonable para implementar operadores, pero no se garantiza que generen el operador óptimo para una tarea determinada.
La Figura 3 verifica el comportamiento básico de BRINT_Sr,q en función de los números de escala comparando el rendimiento de clasificación de BRINT_Sr,q con el descriptor tradicional LBPri,r,p. Los resultados de clasificación muestran una mejora significativa en el rendimiento de clasificación en las tres bases de datos de Outex, con los mejores resultados de BLP.
inserte la descripción de la imagen aquí
Figura 3 Comparación de la precisión de clasificación del descriptor BRINT_S y el descriptor LBPri tradicional utilizando los tres conjuntos de referencia en la base de datos Outex especificada por Ojala et al. (BLP). La configuración experimental es consistente con la de LBP. Los resultados muestran claramente que el descriptor BRINT_S propuesto supera significativamente al descriptor LBPri tradicional.

En términos de coste computacional, el descriptor BRINT_S propuesto no implica un aumento de complejidad respecto al LBPriu2 convencional. En particular, BRINT_S siempre trata con patrones binarios locales basados ​​en 8 puntos, mientras que para LBPriu2, la asignación de LBP a LBPriu2 requiere una tabla de búsqueda grande con 2^p elementos.

Descriptor BRINT_M

Motivados por los notables resultados de clasificación logrados por BRINT_S, esperamos seguir utilizando el descriptor CLBP_M al proponer BRINT_M, considerando que la característica CLBP_CSM supera a la característica única CLBP LBPriu2 propuesta por Guo et al.
Dado un píxel central Xc y sus p píxeles vecinos Xr,p,0,...,Xr,p,p−1, como se muestra en la Figura 2, primero calculamos la distancia entre el píxel central Xc y sus píxeles vecinos Valor absoluto de diferencias locales:
inserte la descripción de la imagen aquí
Siguiendo el trabajo en CLBP, ∆r,8q es un componente importante de las diferencias locales. Similar a (2), ∆r,8q se transforma en Zr,q,i=
inserte la descripción de la imagen aquí
Calculamos el patrón binario basado en Z BNT_M (Magnitud de tolerancia de ruido binario):
inserte la descripción de la imagen aquídonde µl es el umbral local. Tenga en cuenta que el descriptor CLBP_M definido en CLBP utiliza un umbral global, mientras que en el operador LBP original el umbral es el valor del píxel central, que obviamente varía de píxel a píxel. Por lo tanto, proponemos usar un umbral variable localmente en lugar de un umbral global constante:
inserte la descripción de la imagen aquí
Después de definir BNT_M, BRINT_M se define como:
inserte la descripción de la imagen aquí
Finalmente, de acuerdo con CLBP, también representamos el píxel central como uno de dos binarios:
inserte la descripción de la imagen aquí
donde µI, r es el promedio sobre toda la imagen excluyendo los píxeles del límite:
inserte la descripción de la imagen aquí

BRINT multiresolución y clasificación

Hasta ahora, los descriptores BRINT se extraen de una resolución que es un conjunto de vecindad circularmente simétrico de 8q píxeles que se encuentran en un círculo de radio r. Dado que uno de los objetivos de nuestro método es manejar una gran cantidad de escalas diferentes, al variar r podemos implementar operadores de diferentes resoluciones espaciales, idealmente representados concatenando histogramas binarios de múltiples resoluciones en un solo histograma Parches de textura, que obviamente requieren el bajo -dimensionalidad de las características del histograma generadas en cada resolución. Por lo tanto, la dimensión del histograma conjunto de BRINT_CSM, BRINT_C, BRINT_S y BRINT_M es muy alta, que es 36∗ 36∗ 2 = 2592. Para reducir el número de pilas estadísticas requeridas, usamos los descriptores BRINT_CSr, q_CMr, q, es decir, el histograma conjunto BRINT_C∗ BRINT_Sr,q está conectado con BRINT_C∗ BRINT_Mr,q para generar un histograma de baja dimensión: 36∗ 2+36∗ 2=144. Como punto de comparación, en los resultados experimentales también evaluaremos BRINT_Sr,q_Mr,q, cuya dimensión es 36+36=72.
La clasificación real se realiza mediante un clasificador de vecino más cercano simple (NNC): El clasificador de vecino más cercano (NNC) se aplica a los vectores de características de histograma de Brinell normalizados hi y hj, utilizando la métrica de distancia χ2, como en CBLP.

código C++

Referencia 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;
	}
}

hidrogeno.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

hidrogeno.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);
	}

}

prueba_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;

}

código pitón

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

principal.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)

Supongo que te gusta

Origin blog.csdn.net/weixin_45184581/article/details/124900123
Recomendado
Clasificación