BRINT: バイナリ回転不変でノイズ耐性のあるテクスチャ記述子

原文アドレス:
https://ieeexplore.ieee.org/document/6738053
この記事は論文の第2章のみを翻訳し、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 とは異なり、図 2 に示すように、円弧に沿った局所平均によって近傍ベクトル Xr,8q を変換し、
ここに画像の説明を挿入
Yr,q の近傍の数が常に 8 になるようにします。
ここに画像の説明を挿入
図 2 BNT_S 記述子の説明: BRINT では、量子化の前に平均化するというアイデアが導入されており、最初に元の近傍を新しい Yr,8q,i (i=0,...,7) に変換します (i=0,...,7)。 Yr、8q、i は、中心ピクセルのグレー値 Xc を直接減算するのではなく、バイナリ パターンを生成するためにしきい値処理されます。


ここに画像の説明を挿入
Yr,q = [yr,q,0, , yr,q,7]T とすると、LBP などの中心ピクセルに関するバイナリ パターンを単純に計算できます。ここで、BNT_S は「Binary Noise Tolerance Notation」を表します。任意のパラメーター ペア (r,q) について、合計 2^8=256 個の BNT_Sr,q バイナリ パターンがあることが簡単にわかります。さらに、Xr,8q から Yr,q への遷移により、パターンがノイズに対してより堅牢になります。
回転の不変性は私たちが定めた目標の 1 つであるため、統一スキーマの制限を回避するために、回転の下でバイナリ表現の等しいバージョンをグループ化し、結果のグループにコードを割り当てることによって、LBPri,r,q のヒューリスティックに従います。次に、BRINT_Sr,q の形式は、
ここに画像の説明を挿入
回転関数 ROR(・,・) が LBP と同じになるように定義され、1 つのスケールのヒストグラム セルの数が 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 の基本的な動作を検証します。分類結果では、3 つの Outex データベースで分類パフォーマンスが大幅に向上しており、BLP からの最良の結果が得られています。
ここに画像の説明を挿入
図 3 Ojala ら (BLP) によって指定された Outex データベース内の 3 つのベンチマーク スイートすべてを使用した、BRINT_S 記述子と従来の LBPri 記述子の分類精度の比較。実験設定はLBPの設定と一致しています。結果は、提案された BRINT_S 記述子が従来の LBPri 記述子よりも大幅に優れていることを強く示しています。

計算コストの観点から見ると、提案された BRINT_S 記述子は、従来の LBPriu2 に比べて複雑さが増加することを意味しません。特に、BRINT_S は常に 8 ポイントベースのローカル バイナリ パターンを処理しますが、LBPriu2 の場合、LBP から LBPriu2 へのマッピングには 2^p 要素を含む大規模なルックアップ テーブルが必要です。

BRINT_M 記述子

BRINT_S によって達成された顕著な分類結果に動機付けられ、CLBP_CSM 機能が Guo らによって提案された CLBP 単一機能 LBPriu2 よりも優れていることを考慮して、BRINT_M を提案することで CLBP_M 記述子をさらに活用したいと考えています。
図 2 に示すように、中心ピクセル Xc とその p 個の隣接ピクセル Xr,p,0,...,Xr,p,p−1 が与えられると、まず中心ピクセル Xc とその隣接ピクセルの間の距離の絶対値を計算します。局所的な差異の分析:
ここに画像の説明を挿入
CLBP での研究に従って、Δr,8q は局所的な差異の重要な要素です。(2) と同様に、Δr,8q は Zr,q,i= に変換されます。Z
ここに画像の説明を挿入
ベースのバイナリ パターン BNT_M (バイナリ ノイズ許容量) を計算します。
ここに画像の説明を挿入ここで、μl はローカルしきい値です。CLBP で定義されている CLBP_M 記述子はグローバルしきい値を使用しますが、元の LBP 演算子ではしきい値は中心ピクセル値であり、明らかにピクセルごとに異なります。したがって、一定のグローバルしきい値の代わりに、局所的に変化するしきい値を使用することを提案します。
ここに画像の説明を挿入
BNT_M を定義した後、BRINT_M は次のように定義されます。
ここに画像の説明を挿入
最後に、CLBP と一致して、中心ピクセルも 2 つのバイナリの 1 つとして表します。
ここに画像の説明を挿入
ここで、μI、r は境界ピクセルを除いた画像全体の平均:
ここに画像の説明を挿入

多重解像度 BRINT と分類

これまでのところ、BRINT 記述子は、半径 r の円上にある 8q ピクセルの円対称近傍セットである解像度から抽出されています。私たちの方法の 1 つの目標が、多数の異なるスケールを処理することであることを考えると、r を変化させることで、異なる空間解像度の演算子を実装できます。理想的には、複数の解像度のバイナリ ヒストグラムを 1 つのヒストグラムに連結することによって表されます。 -各解像度で生成されたヒストグラム特徴の次元。したがって、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 が生成されます。比較のポイントとして、実験結果では、次元が 36+36=72 である BRINT_Sr,q_Mr,q も評価します。
実際の分類は、単純な最近傍分類器 (NNC) によって実行されます。最近傍分類器 (NNC) は、CBLP と同様に、χ2 距離メトリックを使用して、正規化されたブリネル ヒストグラム特徴ベクトル hi および hj に適用されます。

C++ コード

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

その他のHP

#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

その他.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;
	}
}

水素.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

水素.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