CNN结构基元:纹理结构和纹理基元方程化GLOH、Gabor...(Code)
?????? 模式識別專注于尋找相同模式的共性和不同模式的分離。CNN把特征提取全局化,其中重要的一個是紋理特征,利用卷積核來表示紋理基元,用以重現模式,應如何顯示表示。
?????? 第一次使用紋理特征,2012年,使用了灰度共生矩陣:灰度共生矩陣-/Laws特征。此后LBP特征也是一種常用的特征:局部二元模式LBP特征。? 此外Gabor變換用以提取紋理,可以使用變換后的能量和方差進行計算特征, Gabor函數變換:Gabor濾波器學習-。
?????? 紋理模式分析CNN化的可行性分析:紋理基于子對象模式,紋理從直覺上即可分解為基元的基元,即分層化。紋理模式識別,模型構建方法即為尋找紋理模式的基元分布模式,可通過多層CNN結構堆疊而成,且描述直覺上比類別模式更為簡單清晰。
?
百度百科:
????? 紋理分析指通過一定的圖像處理技術提取出紋理特征參數,從而獲得紋理的定量或定性描述的處理過程。紋理分析方法按其性質而言,可分為4大類:統計分析方法、結構分析方法、信號處理方法和模型方法。
本質屬性-共性:
????? 定義1? 紋理是一種反映圖像中同質現象的視覺特征,體現了物體表面共有的內在屬性,包含了物體表面結構組織排列的重要信息以及它們與周圍環境的聯系。
????? 定義2? 按一定規則對元素(elements)或基元(primitives)進行排列所形成的重復模式。
????? 定義3? 如果圖像函數的一組局部屬性是恒定的,或者是緩變的,或者是近似周期性的,則圖象中的對應區域具有恒定的紋理。
????? 本質屬性的共性定義,表示紋理一旦確定,一定可以形式化,必然能找到一個特定形式的數學方程來描述此種紋理模式的唯一性,在CNN中,可以表示為特診個提取的特定卷積核的組合模式。
?
紋理屬性:
??????? 紋理基元和分布模式、影調。一個紋理基元(不嚴格地說)是一個具有一定的不變特性的視覺基元。這些不變特性在給定區域內的不同位置上,以不同的變形和不同的方向重復出現。紋理基元最基本的不變特性之一是區域內象素的色彩/灰度分布。
??????? 分布模式,可以以空間描述的紋理結構描述,特定紋理基元通過不同的空間組合組合成不同紋理。
??????影調也是表示灰度的明暗分布。因此,我們認為影調和紋理不是獨立的概念:當在圖象的一定面積區域中影調基元的變化很小時,這個區域的主導特性是影調。當在小面積區域中含大量不同的影調,這個區域占主導的特性是紋理。
?
紋理模式構架(紋理分析):
????? 紋理特征建立在子對象基礎之上,這就意味著,必須有一個對象等級架構去使用他們,精確的分割是使用形狀紋理特征的基礎,子對象的分割要盡量有意義。
???? 1. 考慮子對象光譜特征的紋理
???? 2. 考慮子對象形狀特征的紋理
???? 3. 基于灰度共生矩陣的紋理
方法簡述文章
參考文章:紋理圖像分析的基本方法簡述 。
????? 紋理是物體表面固有的一種特性,所以圖像中的區域常體現出紋理性質。紋理可以認為是灰度(顏色)在空間以一定的形式變化而產生的團(模式)。紋理與尺度有密切的關系,一般僅在一定的尺度上可以觀察到,對紋理的分析需要在恰當的尺度上進行。紋理還具有區域性質的特點,通常被看做對局部區域中像素之間關系的一種度量,對于單個像素來說討論紋理是沒有意義的。一把情況下目前常用的紋理分析方法中有以下三種:統計法,結構法,頻譜法。下面分別介紹。
?
1. 紋理描述的統計方法
????? 最簡單的統計法借助于灰度直方圖的矩來描述紋理,比如直方圖的二階矩是灰度對比度的度量,可以用于描述直方圖的相對平滑程度;三階矩表示了直方圖的偏度;四階矩表示的直方圖的相對平坦型等等。但是僅借助灰度直方圖的矩來描述紋理沒能利用像素相對位置的空間信息,為了利用這些信息,我們可以建立區域的灰度共生矩陣。
????? 一個帶有詳細GLOH講解和代碼的頁面:http://blog.csdn.net/guanyuqiu/article/details/53117507????????????????
1.1 灰度共生矩陣
設 S 為目標區域 R 中具有特定空間聯系(可由位置算子確定)的象素對的集合,共生矩陣 P 中的元素( #代表數量)
分子:具有某種空間關系、灰度值分別為g1和g2的象素對的個數
分母:象素對的總和個數
上面提到了一個概念,位置算子,位置算子其實就是象素對的特定空間聯系,比如向右1個象素和向下1個象素。共生矩陣的大小一般為k x k矩陣(k為所求圖像的灰度級數)。舉個栗子如下:
???
上圖a為3個灰度級的圖象( g1 = 0, g2 = 1, g3 = 2),位置算子為:向右1個象素和向下1個象素,b圖按照位置算子計算得到的灰度共生矩陣,c圖為共生矩陣歸一化的結果。然而,為了更好的對圖像分析,一般常用由共生矩陣產生的紋理描述符,比如:二階矩,對應圖像的均勻性或平滑性;熵,給出圖像內容隨機性的度量;對比度,反應緊鄰像素間的反差等。
?
1.2. 基于能量的紋理描述符
????? 通過利用模板(也稱核)計算局部紋理能量可以獲得灰度變化的信息,如果設圖象為I,模板為M1, M2, …, MN,則卷積 Jn = I * Mn, n = 1, 2, …, N 給出了各個象素鄰域中的紋理能量分量,如果采用尺寸為k × k的模板,則對應第n個模板的紋理圖像(的元素)為:
?
常見的一維模板有:
其中L代表層(level),E代表邊緣(edge),S代表形狀(shape),W代表波(wave),R代表紋(ripple),例如L5給出中心加權的局部平均, E5檢測邊緣。對應的二維模板常用兩個一維模板(行模板和列模板)的卷積得到。這里不再贅述。
?
2. 紋理描述的結構方法
2.1 結構描述法基礎
????? 一般認為紋理是由許多相互接近的,互相編織的元素構成(它們常具有周期性),所以紋理描述可提供圖像區域的平滑,稀疏,規則性等特性。結構法是一種空域的方法,其基本思想是認為復雜的紋理可由一些簡單的紋理基元(基本紋理元素)以一定的有規律的形式重復排列組合而成。
結構描述的關鍵點有兩個:一是確定紋理基元;二是建立排列規則。一個紋理基元是由一組屬性所刻畫的相連通的像素集合,設紋理基元為h(x, y),排列規則為r(x, y),則紋理t(x, y)可表示為:
?????? 為了用結構法描述紋理,在獲得紋理基元的基礎上,還要建立將它們及逆行排列的規則,排列規則和方式可用形式語法來定義,其中t表示紋理基元,a表示向右移動,b表示向下移動:
(1) S -> aS(變量S可用aS來替換)
(2) S -> bS( 變量S可用bS來替換)
(3) S -> tS(變量S可用tS來替換)
(4) S -> t(變量S可用t來替換)
???? 例如,t是下圖a的一個紋理基元,它也可以直接由上述規則(4)得到。如果依次使用規則(3),(1),(3),(1),(3),(1),(4),可得到tatatat,即生成如圖b的圖案。如果依次使用規則(3),(1),(3),(2),(3),(1),(3),(1),(4),即可得到下圖c的圖案。
比較規則的紋理在空間中可以用有次序的形式通過紋理鑲嵌來構建,比如下圖,通過使用一種正多邊形進行拼接組合。
?
2.2 局部二值模式(LBP)
????? 局部二值模式(LBP)是一種紋理分析算子,是一個借助局部鄰域定義的紋理測度。它屬于點樣本的估計方式,具有尺度不變性,旋轉不變性和計算復雜度低等優點。
????? 對一個象素的3 x 3鄰域里的象素按順序閾值化,將結果看作一個二進制數,并作為中心象素的標號,由256個不同標號得到的直方圖可進一步用作區域的紋理描述符 ,如下圖:
當然也可以使用不同尺寸的鄰域對基本LBP算子進行擴展。用(P, R)代表一個象素的鄰域,在這個鄰域里有P個象素 圓半徑為R。如下圖:
將一個鄰域中的象素按順序循環考慮,如果它包含最多兩個從0到1或從1到0的過渡,則這個二值模式就是均勻的,根據LBP的標號可以獲得不同的局部基元。如下:
?
3. 紋理描述的頻譜方法
?? ? ? 一般來說,紋理和圖像頻譜中的高頻分量是密切聯系的。光滑的圖像(主要包含低頻分量)一般不當做紋理圖像看待。頻譜法對應變換域的方法,著重考慮的是紋理的周期性。
3.1 傅里葉頻譜
???? 傅里葉頻譜可借助傅里葉變換得到,它有三個合適描述紋理的性質:
(1) 傅里葉頻譜中突起的峰值對應紋理模式的主方向
(2) 這些峰在頻域平面的位置對應模式的基本周期
(3) 利用濾波把周期性成分除去,用統計方法描述剩下的非周期性部分
在實際的特征檢測中,為簡便起見可把頻譜轉換到極坐標中。此時頻譜函數可用S(r, θ )表示,比如:
如果紋理具有空間周期性,或具有確定的方向性,則能量譜在對應的頻率處會有峰。以這些峰為基礎課組建模式識別所需的特征。
?
3.2 Gabor頻譜
????? Gabor濾波器用于人臉檢測:人臉識別的Gabor特征?????
????? Gabor濾波器代碼:OpenCV實現Gabor濾波器2 ????
????? Gabor函數變換:Gabor濾波器學習--
????? Gabor頻譜,也有成為蓋伯頻譜,源自于Gabor變換。如果在傅里葉變換中加上窗函數,就構成短時傅里葉變換,再進一步,如果短時傅里葉變換的窗函數為高斯函數,則構成Gabor變換。由于高斯函數的傅里葉變換仍為高斯函數,所以,Gabor變換再空域和頻域都具有局部性,或者說可以將能量進行集中。
實際中常使用兩個成對的實Gabor濾波器,其中對稱的和反對稱的濾波器響應分別為:
將上述兩個蓋伯濾波器旋轉和放縮,可分別獲得一組朝向和帶寬均不同的濾波器,并覆蓋整個平面,如下圖:
通過利用一組基于Gabor變換的濾波器可將圖像分別轉換到一系列的頻率帶中。
?
4. 小結
????? 本文主要從統計方法,結構方法以及頻譜的方法對紋理圖像的描述進行了初步的概述,以便讀者進行關于對紋理圖像的分析方面有一個初步的了解。本文部分內容參考章毓晉的圖像工程(中冊)之圖像分析,感謝!
?
5. Code
//獲取一定參數下的紋理特征
//產生紋理特征:圖片熵、灰度共生矩陣、Gabor濾波器 //輸入:RGB彩色圖像 輸出:紋理特征 //計算結果:得到GLOH直方圖; //得到四個值:對比度、能量、熵、逆方差、相關性 int ColorML::GenFeatTexture( cv::Mat &image, fvTexture &ftexture ) {Mat src; image.copyTo(src);Mat src2; image.copyTo(src2);if (src.empty()){return -1;}//1.得到灰度共生矩陣 函數值,此程序中有四個方向,共16個特征,后16維則為0getFeatGLOH( src, ftexture.fvGLOH );//2.得到Gabor濾波器的特征:32維//不能修改頻率和尺度,需要再在最后結果上做文章int U = 3;//尺度:-1~3;頻率:0~4;int V = 4;//論文U,V取7,4共得到(4+1)*(7+1)= 40個卷積核//修改為4個頻率,四個尺度,得到16個圖像,最后得到64個特征,必須與fvGabor 對應//在此計算中,只使用能量和熵//有兩個值為空值getFeatGabor(src2, ftexture.fvGabor,U,V);ftexture.combine();ftexture.normal();return 1; }//獲取Gabor核和GLOH特征
//從多個圖像中獲取灰度共生矩陣 int ColorML::getFeatGLOH(cv::Mat &src, std::vector<float> &featV){//代碼地址:http://blog.csdn.net/yanxiaopan/article/details/52356777//更詳細的理論和代碼:http://blog.csdn.net/guanyuqiu/article/details/53117507Mat dst_horison, dst_vertical, dst_45, dst_135;//使用HSV的灰度共生矩陣,直接使用H矩陣cv::Mat hm, sm, vm, hsvm;vector<cv::Mat> hsvs;cvtColor(src, hsvm, COLOR_BGR2HSV);cv::split(hsvm, hsvs);//分為3個通道 //hm = hsvs[0].clone();//sm = hsvs[1].clone();//vm = hsvs[2].clone();Mat src_gray;//cvtColor(src, src_gray, COLOR_BGR2GRAY);src_gray = hsvs[0].clone();//四個方向的直方圖//計算特征//ColorML* cm = new ColorML();double eng_horison = 0, con_horison = 0, idm_horison = 0, asm_horison = 0;ColorML::getglcm_horison(src_gray, dst_horison);ColorML::getglcm_45(src_gray, dst_45);ColorML::getglcm_vertical(src_gray, dst_vertical);ColorML::getglcm_135(src_gray, dst_135);bool isTest = g_mlTest;if (isTest) {//ColorML::feature_computer(dst_horison, asm_horison, eng_horison, con_horison, idm_horison);//cout << "asm_horison:" << asm_horison << endl;//cout << "eng_horison:" << eng_horison << endl;//cout << "con_horison:" << con_horison << endl;//cout << "idm_horison:" << idm_horison << endl;int f = 1;//mutilM(dst_horison, f);//mutilM(dst_45, f);//mutilM(dst_vertical, f);//mutilM(dst_135, f);printM(dst_horison);printM(dst_45);printM(dst_vertical);printM(dst_135);cv::imshow("RGB", src);cv::imshow("H-Image", src_gray);//cv::imshow("dst_horison", dst_horison);//cv::imshow("dst_45", dst_45);//cv::imshow("dst_vertical", dst_vertical);//cv::imshow("dst_135", dst_135);cv::waitKey();}//裝填入ftexture特征中//取灰度矩陣的每一列的值(每一行都會相同),4個方向共64維std::vector<cv::Mat> gMats;gMats.push_back(dst_horison);gMats.push_back(dst_45);gMats.push_back(dst_vertical);gMats.push_back(dst_135);//int consLen = fvTexture::lenFeat;//限制長度//std::vector<int> featV;//getFeatGLOH(gMats, featV, consLen);//此函數未必正確,只是截取前端,不能進行濾波////得到灰度共生矩陣直方圖//getFeatHistGLOH(gMats, ftexture.fvGLOH, consLen);//1.得到每個方向灰度共生矩陣的 5個函數:對比度、能量、熵、逆方差、相關性//本程序中使用四個方向,則有后10位為0 的空值,相關性未獲得getFeatGLOH( gMats, featV, fvTexture::lenFeat );return 1; } //從多個圖像中獲取灰度共生矩陣 //取每一行的均值 int ColorML::getFeatGLOH(std::vector<cv::Mat> &gMats, std::vector< float> &featV, int consLen){std::vector< std::vector< float>> feat(gMats.size());for (int k = 0; k < gMats.size();++k){cv::Mat src = gMats[k].clone();double Asm = 0;double Eng = 0;double Con = 0;double Idm = 0;feature_computer(src, Asm, Eng, Con, Idm);feat[k].push_back(Asm);feat[k].push_back(Eng);feat[k].push_back(Con);feat[k].push_back(Idm);}for ( int i = 0; i < featV.size() / 4 && i< feat.size(); ++i ){featV[4*i] = feat[i][0];featV[4*i+1] = feat[i][1];featV[4 * i + 2] = feat[i][2];featV[4 * i + 3] = feat[i][3];}return 1; } //獲取Gabor圖像 int ColorML::getFeatGabor( cv::Mat &image, std::vector<float> &featV ,int U ,int V) {int type = 0;if (!image.data){cout << "Could not open or find the image" << std::endl;return -1;}//縮放圖像int nr = image.rows / 640;int nc = image.cols / 640;if (nr > 1 || nc > 1){int maxFactor = std::max(nr, nc) + 1;cv::resize(image, image, cv::Size(image.rows / maxFactor, image.cols / maxFactor), cv::INTER_LINEAR);}//使用HSV的灰度共生矩陣,直接使用H矩陣cv::Mat hm, sm, vm, hsvm;vector<cv::Mat> hsvs;cvtColor(image, hsvm, COLOR_BGR2HSV);cv::split(hsvm, hsvs);//分為3個通道 //hm = hsvs[0].clone();//sm = hsvs[1].clone();//vm = hsvs[2].clone();//Mat src_gray;//cvtColor(src, src_gray, COLOR_BGR2GRAY);image = hsvs[0].clone();//建議不使用歸一化,為了方便能量計算//garbor kernel的參數,包括kernel_size 和 v的范圍,都是為了適應不同圖像的大小。//v 越小,Gabor函數的寬度越小,越能刻畫細節信息,適應于較小的圖像//19x19, 25x25, 35x35, 49x49, 69x69.const int kernel_size = 19;vector<Mat > gaborMats;Mat filterd_image;filterd_image = GaborFilter(image, type, kernel_size, U, V);filterd_image = GaborFilter(image, gaborMats, type, kernel_size, U, V);bool isTest = g_mlTest;if (isTest) {//printM(gaborMats[0]);//char型正常imshow("origin image", image);cv::namedWindow("filtered image");cv::resize(filterd_image, filterd_image, cv::Size(1280, 800));imshow("filtered image", filterd_image);//normalize(filterd_image, filterd_image, 0, 255, CV_MINMAX); //filterd_image.convertTo(filterd_image, CV_8U); //imwrite("filterd_image.jpg",filterd_image); waitKey();}//計算Gabor圖像的特征:5個函數:對比度、能量、熵、逆方差、相關性;相關性未計算//這樣共得到160個特征,太多了!最多只能40個double eng = 0, con = 0, idm = 0, asmf = 0;for (int i = 0; i < gaborMats.size();++i){int idx = 4 * i;float factor = 1.0;// / gaborMats[i].rows * gaborMats[i].cols;factor *= (gray_level*gray_level);cv::Mat m = gaborMats[i];downSampleTo16(m);downSampleV16( m );ColorML::feature_computer( m, asmf, eng, con, idm );featV[idx + 0] = asmf / factor;featV[idx + 1] = eng / factor;//featV[idx + 2] = con / factor;//只取能量和熵//featV[idx + 3] = idm / factor;}return 1; } //對實數和復數進行分解,還是只使用實數核的好! cv::Mat ColorML::GaborFilter(Mat& image, std::vector<cv::Mat> &matsGabor, int type, const int kernel_size, int U, int V) {// Ref: Mian Zhou. Thesis. Gabor-Boosting Face Recognition. // https://code.google.com/p/gaborboosting/ //const int kernel_size = 69; // should be odd cv::Mat img;if (image.type() == CV_8UC3){cv::cvtColor(image, img, COLOR_BGR2GRAY);}else{image.copyTo(img);}// variables for gabor filter double Kmax = M_PI / 2;double f = sqrt(2.0);double sigma = 2 * M_PI;//int U = 7;//int V = 4;int GaborH = kernel_size;int GaborW = kernel_size;int UStart = 0, UEnd = U+1;int VStart = 0, VEnd = V;//int VStart = -1, VEnd = V;// variables for filter2D Point archor(-1, -1);int ddepth = CV_64F;//CV_64F double delta = 0;// filter image with gabor bankMat kernel_re, kernel_im;Mat dst_re, dst_im, dst_mag;Mat totalMat, totalMat_re, totalMat_im;//把Bank里面的抽取出來,得到不同方向U和不同頻率V上的小波核,每一個進行濾波for (U = UStart; U < UEnd; U++){Mat colMat, colMat_re, colMat_im;for (V = VStart; V < VEnd; V++){switch (type){case 0://計算實數kernel_re = getGaborKer(GaborW, GaborH, U, V, Kmax, f, sigma, CV_64F, "real");//printM(kernel_re);//uchar型無誤filter2D(img, dst_re, ddepth, kernel_re);//normalize(dst_re, dst_re, 0, 1, CV_MINMAX);//printM(dst_re);//char型無誤matsGabor.push_back(dst_re);break;case 1://計算虛數kernel_im = getGaborKer(GaborW, GaborH, U, V, Kmax, f, sigma, CV_64F, "imag");filter2D(img, dst_im, ddepth, kernel_im);//normalize(dst_im, dst_im, 0, 1, CV_MINMAX);//matsGabor.push_back(dst_mag);break;default://計算全部kernel_re = getGaborKer(GaborW, GaborH, U, V, Kmax, f, sigma, CV_64F, "real");kernel_im = getGaborKer(GaborW, GaborH, U, V, Kmax, f, sigma, CV_64F, "imag");// normalize kernel ??//normalize(kernel_re, kernel_re, 0, 255, CV_MINMAX); // flip kernel// Gabor kernel is symmetric, so do not need flip //flip(kernel_re, kernel_re, -1); filter2D(img, dst_re, ddepth, kernel_re);filter2D(img, dst_im, ddepth, kernel_im);dst_mag.create(img.rows, img.cols, CV_64FC1);cv::magnitude(Mat_<float>(dst_re), Mat_<float>(dst_im), dst_mag);//show gabor kernel //cv::normalize(dst_mag, dst_mag, 0, 1, CV_MINMAX);//normalize(dst_re, dst_re, 0, 1, CV_MINMAX);//normalize(dst_im, dst_im, 0, 1, CV_MINMAX);matsGabor.push_back(dst_im);break;}//鏈接圖像,刪除if (V == VStart){colMat = dst_mag;colMat_re = dst_re;colMat_im = dst_im;}else{switch (type){case 0:vconcat(colMat_re, dst_re, colMat_re);break;case 1:vconcat(colMat_re, dst_re, colMat_re);break;default:cv::vconcat(colMat, dst_mag, colMat);vconcat(colMat_re, dst_re, colMat_re);vconcat(colMat_im, dst_im, colMat_im);break;}}}//for Uif (U == UStart){totalMat = colMat;totalMat_re = colMat_re;totalMat_im = colMat_im;}else{switch (type){case 0:hconcat(totalMat_re, colMat_re, totalMat_re);break;case 1:hconcat(totalMat_im, colMat_im, totalMat_im);break;default:cv::hconcat(totalMat, colMat, totalMat);hconcat(totalMat_re, colMat_re, totalMat_re);hconcat(totalMat_im, colMat_im, totalMat_im);break;}}}//return matsGabor.size();switch (type){case 0:return totalMat_re;case 1:return totalMat_im;default:return totalMat;} }//獲取紋理能量特征
//計算特征值:對比度Con、能量Asm、熵Eng、逆差矩Idm、相關性 void ColorML::feature_computer( Mat&src, double& Asm, double& Eng, double& Con, double& Idm ) {int height = src.rows;int width = src.cols;int total = 0;for (int i = 0; i < height; i++) {int*srcdata = src.ptr<int>(i);for (int j = 0; j < width; j++) {total += srcdata[j];//求圖像所有像素的灰度值的和}}Mat copy;copy.create(height, width, CV_64FC1);for (int i = 0; i < height; i++){int*srcdata = src.ptr<int>(i);double*copydata = copy.ptr<double>(i);for (int j = 0; j < width; j++) {copydata[j] = (double)srcdata[j] / (double)total;//圖像每一個像素的的值除以像素總和}}for (int i = 0; i < height; i++){double*srcdata = copy.ptr<double>(i);for (int j = 0; j < width; j++){Asm += srcdata[j] * srcdata[j];//能量if (srcdata[j]>0)Eng -= srcdata[j] * log(srcdata[j]);//熵 Con += (double)(i - j)*(double)(i - j)*srcdata[j];//對比度Idm += srcdata[j] / (1 + (double)(i - j)*(double)(i - j));//逆差矩}}}//計算特征值:對比度、能量、熵、逆方差、相關性實驗結果:
我的實驗結果,調節參數uv
他人結果:
簡單的紋理分析,以用于CNN的初始化工作,根據Gabor濾波器的參數調節得到的實驗結果,來尋找CNN的初始結構和相對靠譜的結構參數。
總結
以上是生活随笔為你收集整理的CNN结构基元:纹理结构和纹理基元方程化GLOH、Gabor...(Code)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ZfNet解卷积:可视化CNN模型( P
- 下一篇: 图论 Make Unique:有向图和无