├── Gabor.py ├── Gray Level Co-occurence Matrix.py ├── Gray Level Run Length Matrix.py ├── Haralick.py ├── README.md └── Tamura.py /Gabor.py: -------------------------------------------------------------------------------- 1 | #Features extracted from this are "Local Energy" and "Mean Amplitude" at different angles and wavelengths (frequencies) 2 | #Number of features extracted = number of angles chosen * number of wavelengths chosen 3 | 4 | import cv2 5 | import os 6 | import glob 7 | import numpy as np 8 | import matplotlib.pyplot as plt 9 | import time 10 | import csv 11 | 12 | tic=time.time() 13 | 14 | #Importing the images 15 | img_dir = ".../...../..." # Enter Directory where all the images are stored 16 | data_path = os.path.join(img_dir,'*g') 17 | files = glob.glob(data_path) 18 | 19 | eo=len(files) 20 | 21 | img = [] 22 | for f1 in files: 23 | data = cv2.imread(f1) 24 | img.append(data) 25 | 26 | gamma=0.5 27 | sigma=0.56 28 | theta_list=[0, np.pi, np.pi/2, np.pi/4, 3*np.pi/4] #Angles 29 | phi=0 30 | lamda_list=[2*np.pi/1, 2*np.pi/2, 2*np.pi/3, 2*np.pi/4, 2*np.pi/5] #wavelengths 31 | num=1 32 | 33 | #Creating headings for the csv file 34 | gabor_label=[] 35 | for i in range(50): 36 | gabor_label.append('Gabor'+str(i+1)) 37 | 38 | with open('Gabor.csv','a+',newline='') as file: 39 | writer=csv.writer(file) 40 | #writer.writerow(gabor_label) 41 | 42 | for i in range(eo): 43 | img[i] = cv2.cvtColor(img[i] , cv2.COLOR_BGR2GRAY) 44 | print("For image number"+str(i+1)+'\n') 45 | local_energy_list=[] 46 | mean_ampl_list=[] 47 | 48 | for theta in theta_list: 49 | print("For theta = "+str(theta/np.pi)+"pi\n") 50 | 51 | for lamda in lamda_list: 52 | kernel=cv2.getGaborKernel((3,3),sigma,theta,lamda,gamma,phi,ktype=cv2.CV_32F) 53 | fimage = cv2.filter2D(img[i], cv2.CV_8UC3, kernel) 54 | 55 | mean_ampl=np.sum(abs(fimage)) 56 | mean_ampl_list.append(mean_ampl) 57 | 58 | local_energy=np.sum(fimage**2) 59 | local_energy_list.append(local_energy) 60 | 61 | num+=1 62 | print('\n\n') 63 | writer.writerow(local_energy_list+mean_ampl_list) 64 | 65 | toc=time.time() 66 | print("Computation time is {} seconds".format(str(toc-tic))) 67 | -------------------------------------------------------------------------------- /Gray Level Co-occurence Matrix.py: -------------------------------------------------------------------------------- 1 | #GLCM or Gray Level Co-occurence Matrix extracts texture features from images 2 | 3 | import matplotlib.pyplot as plt 4 | from skimage.feature import greycomatrix, greycoprops 5 | from skimage import data 6 | import cv2 7 | from PIL import Image 8 | import numpy as np 9 | import csv 10 | import os 11 | import glob 12 | import pandas as pd 13 | from skimage.transform import resize 14 | import time 15 | 16 | tic=time.time() 17 | 18 | PATCH_SIZE = 21 19 | 20 | #GLCM will work on batch of images only if all the images are of same size. 21 | #Uncomment the following two lines of code and enter the dimensions of images you want if the dataset has inconsistent sizes of images: 22 | 23 | #IMAGE_HEIGHT= 24 | #IMAGE_WIDTH= 25 | 26 | img_dir = ".../..../..." #Enter the directory where all the images are stored 27 | data_path=os.path.join(img_dir,'*g') 28 | files=glob.glob(data_path) 29 | 30 | eo=len(files) 31 | 32 | img = [] 33 | for f1 in files: 34 | data = cv2.imread(f1) 35 | img.append(data) 36 | 37 | for i in range(eo): 38 | img[i] = cv2.cvtColor(img[i] , cv2.COLOR_BGR2GRAY) 39 | 40 | #Uncomment the following line for inconsistent size of images in dataset 41 | #img[i] = cv2.resize(img[i],(IMAGE_WIDTH,IMAGE_HEIGHT),interpolation=cv2.INTER_AREA) 42 | 43 | print("For image number:"+str(i+1)+'\n') 44 | image=img[i] 45 | print("Shape of image is: ",image.shape) 46 | 47 | # select some patches from grassy areas of the image 48 | grass_locations = [(1000,100), (980,100), (990,120), (985,150)] 49 | grass_patches = [] 50 | for loc in grass_locations: 51 | grass_patches.append(image[loc[0]:loc[0] + PATCH_SIZE,loc[1]:loc[1] + PATCH_SIZE]) 52 | 53 | # select some patches from sky areas of the image 54 | sky_locations = [(417, 415), (427, 413), (420, 410), (422, 412)] 55 | sky_patches = [] 56 | for loc in sky_locations: 57 | sky_patches.append(image[loc[0]:loc[0] + PATCH_SIZE, loc[1]:loc[1] + PATCH_SIZE]) 58 | 59 | # compute some GLCM properties each patch 60 | xs = [] 61 | ys = [] 62 | bs = [] 63 | cs = [] 64 | ds = [] 65 | 66 | for patch in (grass_patches + sky_patches): 67 | glcm = greycomatrix(patch, distances=[5], angles=[0], levels=256,symmetric=True, normed=True) 68 | xs.append(greycoprops(glcm, 'dissimilarity')[0, 0]) 69 | ys.append(greycoprops(glcm, 'correlation')[0, 0]) 70 | bs.append(greycoprops(glcm, 'contrast')[0, 0]) 71 | cs.append(greycoprops(glcm, 'energy')[0, 0]) 72 | ds.append(greycoprops(glcm, 'homogeneity')[0, 0]) 73 | 74 | temp_xs=xs 75 | temp_ys=ys 76 | temp_bs=bs 77 | temp_cs=cs 78 | temp_ds=ds 79 | 80 | temp_xs.sort() 81 | temp_ys.sort() 82 | temp_bs.sort() 83 | temp_cs.sort() 84 | temp_ds.sort() 85 | 86 | xs_max=temp_xs[-1] 87 | ys_max=temp_ys[-1] 88 | bs_max=temp_bs[-1] 89 | cs_max=temp_cs[-1] 90 | ds_max=temp_ds[-1] 91 | 92 | xs_mean=sum(temp_xs)/len(xs) 93 | ys_mean=sum(temp_ys)/len(ys) 94 | bs_mean=sum(temp_bs)/len(bs) 95 | cs_mean=sum(temp_cs)/len(cs) 96 | ds_mean=sum(temp_ds)/len(ds) 97 | 98 | xs_var=np.var(np.array(temp_xs)) 99 | ys_var=np.var(np.array(temp_ys)) 100 | bs_var=np.var(np.array(temp_bs)) 101 | cs_var=np.var(np.array(temp_cs)) 102 | ds_var=np.var(np.array(temp_ds)) 103 | 104 | df = pd.DataFrame() 105 | 106 | df['dissimilarity_max'] = [xs_max] 107 | df['dissimilarity_mean'] = xs_mean 108 | df['dissimilarity_var'] = xs_var 109 | 110 | df['correlation_max'] = ys_max 111 | df['correlation_mean'] = ys_mean 112 | df['correlation_var'] = ys_var 113 | 114 | df['contrast_max'] = bs_max 115 | df['contrast_mean'] = bs_mean 116 | df['contrast_var'] = bs_var 117 | 118 | df['energy_max'] = cs_max 119 | df['energy_mean'] = cs_mean 120 | df['energy_var'] = cs_var 121 | 122 | df['homogeneity_max'] = ds_max 123 | df['homogeneity_mean'] = ds_mean 124 | df['homogeneity_var'] = ds_var 125 | 126 | print(df) 127 | 128 | with open('GLCM_BreCaHAD_temp.csv','a+',newline='') as file: 129 | writer=csv.writer(file) 130 | 131 | if i==0: 132 | writer.writerow(['dissimilarity_max','dissimilarity_mean','dissimilarity_var','contrast_max','contrast_mean','contrast_var','energy_max','energy_mean', 133 | 'energy_var','correlation_max','correlation_mean','correlation_var','homogeneity_max','homogeneity_mean','homogeneity_var']) 134 | 135 | writer.writerow([xs_max,xs_mean,xs_var,ys_max,ys_mean,ys_var,bs_max,bs_mean,bs_var,cs_max,cs_mean,cs_var,ds_max,ds_mean,ds_var]) 136 | 137 | #Uncomment the following section for features visualization 138 | ''' 139 | # create the figure 140 | fig = plt.figure(figsize=(8, 8)) 141 | 142 | # display original image with locations of patches 143 | ax = fig.add_subplot(3, 2, 1) 144 | ax.imshow(image, cmap=plt.cm.gray, 145 | vmin=0, vmax=255) 146 | for (y, x) in grass_locations: 147 | ax.plot(x + PATCH_SIZE / 2, y + PATCH_SIZE / 2, 'gs') 148 | for (y, x) in sky_locations: 149 | ax.plot(x + PATCH_SIZE / 2, y + PATCH_SIZE / 2, 'bs') 150 | ax.set_xlabel('Original Image') 151 | ax.set_xticks([]) 152 | ax.set_yticks([]) 153 | ax.axis('image') 154 | 155 | # for each patch, plot (dissimilarity, correlation) 156 | ax = fig.add_subplot(3, 2, 2) 157 | ax.plot(xs[:len(grass_patches)], ys[:len(grass_patches)], 'go', 158 | label='Grass') 159 | ax.plot(xs[len(grass_patches):], ys[len(grass_patches):], 'bo', 160 | label='Sky') 161 | ax.set_xlabel('GLCM Dissimilarity') 162 | ax.set_ylabel('GLCM Correlation') 163 | ax.legend() 164 | 165 | # display the image patches 166 | for i, patch in enumerate(grass_patches): 167 | ax = fig.add_subplot(3, len(grass_patches), len(grass_patches)*1 + i + 1) 168 | ax.imshow(patch, cmap=plt.cm.gray, 169 | vmin=0, vmax=255) 170 | ax.set_xlabel('Grass %d' % (i + 1)) 171 | 172 | for i, patch in enumerate(sky_patches): 173 | ax = fig.add_subplot(3, len(sky_patches), len(sky_patches)*2 + i + 1) 174 | ax.imshow(patch, cmap=plt.cm.gray, 175 | vmin=0, vmax=255) 176 | ax.set_xlabel('Sky %d' % (i + 1)) 177 | 178 | 179 | # display the patches and plot 180 | fig.suptitle('Grey level co-occurrence matrix features', fontsize=14, y=1.05) 181 | plt.tight_layout() 182 | plt.show() 183 | ''' 184 | 185 | toc=time.time() 186 | print('Computation time is : {} seconds'.format(str(toc-tic))) 187 | -------------------------------------------------------------------------------- /Gray Level Run Length Matrix.py: -------------------------------------------------------------------------------- 1 | #GLRLM or Gray Level Run Length Matrix 2 | #33 different features are extracted from this 3 | 4 | import matplotlib.pyplot as plt 5 | from PIL import Image 6 | import numpy as np 7 | from itertools import groupby 8 | 9 | data = 0 10 | def read_img(path=" "): 11 | 12 | try: 13 | img = Image.open(path) 14 | img = img.convert('L') 15 | self.data=np.array(img) 16 | 17 | except: 18 | img = None 19 | 20 | def getGrayLevelRumatrix(array, theta): 21 | 22 | 23 | #array: the numpy array of the image 24 | #theta: Input, the angle used when calculating the gray scale run matrix, list type, can contain fields:['deg0', 'deg45', 'deg90', 'deg135'] 25 | #glrlm: output,the glrlm result 26 | 27 | P = array 28 | x, y = P.shape 29 | min_pixels = np.min(P) # the min pixel 30 | run_length = max(x, y) # Maximum parade length in pixels 31 | num_level = np.max(P) - np.min(P) + 1 # Image gray level 32 | 33 | deg0 = [val.tolist() for sublist in np.vsplit(P, x) for val in sublist] # 0deg 34 | deg90 = [val.tolist() for sublist in np.split(np.transpose(P), y) for val in sublist] # 90deg 35 | diags = [P[::-1, :].diagonal(i) for i in range(-P.shape[0]+1, P.shape[1])] #45deg 36 | deg45 = [n.tolist() for n in diags] 37 | Pt = np.rot90(P, 3) # 135deg 38 | diags = [Pt[::-1, :].diagonal(i) for i in range(-Pt.shape[0]+1, Pt.shape[1])] 39 | deg135 = [n.tolist() for n in diags] 40 | 41 | def length(l): 42 | if hasattr(l, '_len_'): 43 | return np.size(l) 44 | else: 45 | i = 0 46 | for _ in l: 47 | i += 1 48 | return i 49 | 50 | glrlm = np.zeros((num_level, run_length, len(theta))) 51 | for angle in theta: 52 | for splitvec in range(0, len(eval(angle))): 53 | flattened = eval(angle)[splitvec] 54 | answer = [] 55 | for key, iter in groupby(flattened): 56 | answer.append((key, length(iter))) 57 | for ansIndex in range(0, len(answer)): 58 | glrlm[int(answer[ansIndex][0]-min_pixels), int(answer[ansIndex][1]-1), theta.index(angle)] += 1 59 | return glrlm 60 | 61 | # The gray scale run matrix is only the measurement and statistics of the image pixel information. In the actual use process, the generated 62 | # The gray scale run matrix is calculated to obtain image feature information based on the gray level co-occurrence matrix. 63 | # First write a few common functions to complete the calculation of subscripts i and j (calcuteIJ ()), multiply and divide according to the specified dimension (apply_over_degree ()) 64 | # And calculate the sum of all pixels (calcuteS ()) 65 | 66 | 67 | def apply_over_degree(function, x1, x2): 68 | rows, cols, nums = x1.shape 69 | result = np.ndarray((rows, cols, nums)) 70 | for i in range(nums): 71 | #print(x1[:, :, i]) 72 | result[:, :, i] = function(x1[:, :, i], x2) 73 | # print(result[:, :, i]) 74 | result[result == np.inf] = 0 75 | result[np.isnan(result)] = 0 76 | return result 77 | def calcuteIJ (rlmatrix): 78 | gray_level, run_length, _ = rlmatrix.shape 79 | I, J = np.ogrid[0:gray_level, 0:run_length] 80 | return I, J+1 81 | 82 | def calcuteS(rlmatrix): 83 | return np.apply_over_axes(np.sum, rlmatrix, axes=(0, 1))[0, 0] 84 | 85 | #The following code realizes the extraction of 11 gray runoff matrix features 86 | 87 | #1.SRE 88 | def getShortRunEmphasis(rlmatrix): 89 | I, J = calcuteIJ(rlmatrix) 90 | numerator = np.apply_over_axes(np.sum, apply_over_degree(np.divide, rlmatrix, (J*J)), axes=(0, 1))[0, 0] 91 | S = calcuteS(rlmatrix) 92 | return numerator / S 93 | #2.LRE 94 | def getLongRunEmphasis(rlmatrix): 95 | I, J = calcuteIJ(rlmatrix) 96 | numerator = np.apply_over_axes(np.sum, apply_over_degree(np.multiply, rlmatrix, (J*J)), axes=(0, 1))[0, 0] 97 | S = calcuteS(rlmatrix) 98 | return numerator / S 99 | #3.GLN 100 | def getGrayLevelNonUniformity(rlmatrix): 101 | G = np.apply_over_axes(np.sum, rlmatrix, axes=1) 102 | numerator = np.apply_over_axes(np.sum, (G*G), axes=(0, 1))[0, 0] 103 | S = calcuteS(rlmatrix) 104 | return numerator / S 105 | # 4. RLN 106 | def getRunLengthNonUniformity(rlmatrix): 107 | R = np.apply_over_axes(np.sum, rlmatrix, axes=0) 108 | numerator = np.apply_over_axes(np.sum, (R*R), axes=(0, 1))[0, 0] 109 | S = calcuteS(rlmatrix) 110 | return numerator / S 111 | 112 | # 5. RP 113 | def getRunPercentage(rlmatrix): 114 | gray_level, run_length,_ = rlmatrix.shape 115 | num_voxels = gray_level * run_length 116 | return calcuteS(rlmatrix) / num_voxels 117 | 118 | # 6. LGLRE 119 | def getLowGrayLevelRunEmphasis(rlmatrix): 120 | I, J = calcuteIJ(rlmatrix) 121 | numerator = np.apply_over_axes(np.sum, apply_over_degree(np.divide, rlmatrix, (I*I)), axes=(0, 1))[0, 0] 122 | S = calcuteS(rlmatrix) 123 | return numerator / S 124 | 125 | # 7. HGL 126 | def getHighGrayLevelRunEmphais(rlmatrix): 127 | I, J = calcuteIJ(rlmatrix) 128 | numerator = np.apply_over_axes(np.sum, apply_over_degree(np.multiply, rlmatrix, (I*I)), axes=(0, 1))[0, 0] 129 | S = calcuteS(rlmatrix) 130 | return numerator / S 131 | 132 | # 8. SRLGLE 133 | def getShortRunLowGrayLevelEmphasis(rlmatrix): 134 | I, J = calcuteIJ(rlmatrix) 135 | numerator = np.apply_over_axes(np.sum, apply_over_degree(np.divide, rlmatrix, (I*I*J*J)), axes=(0, 1))[0, 0] 136 | S = calcuteS(rlmatrix) 137 | return numerator / S 138 | # 9. SRHGLE 139 | def getShortRunHighGrayLevelEmphasis(rlmatrix): 140 | I, J = calcuteIJ(rlmatrix) 141 | temp = apply_over_degree(np.multiply, rlmatrix, (I*I)) 142 | print('-----------------------') 143 | numerator = np.apply_over_axes(np.sum, apply_over_degree(np.divide, temp, (J*J)), axes=(0, 1))[0, 0] 144 | S = calcuteS(rlmatrix) 145 | return numerator / S 146 | 147 | # 10. LRLGLE 148 | def getLongRunLow(rlmatrix): 149 | I, J = calcuteIJ(rlmatrix) 150 | temp = apply_over_degree(np.multiply, rlmatrix, (J*J)) 151 | numerator = np.apply_over_axes(np.sum, apply_over_degree(np.divide, temp, (J*J)), axes=(0, 1))[0, 0] 152 | S = calcuteS(rlmatrix) 153 | return numerator / S 154 | 155 | # 11. LRHGLE 156 | def getLongRunHighGrayLevelEmphais(rlmatrix): 157 | I, J = calcuteIJ(rlmatrix) 158 | numerator = np.apply_over_axes(np.sum,apply_over_degree(np.multiply, rlmatrix, (I*I*J*J)), axes=(0, 1))[0, 0] 159 | S = calcuteS(rlmatrix) 160 | return numerator / S 161 | 162 | #import getGrayRumatrix 163 | from PIL import Image 164 | import numpy as np 165 | from itertools import groupby 166 | import csv 167 | import warnings 168 | warnings.filterwarnings("ignore") 169 | import cv2 170 | import os 171 | import glob 172 | import time 173 | 174 | tic=time.time() 175 | 176 | img_dir=".../..../..." #Enter the directory where all the images are stored 177 | data_path=os.path.join(img_dir,'*g') 178 | files=glob.glob(data_path) 179 | i=0 180 | for path in files: 181 | data = 0 182 | img = Image.open(path) 183 | img = img.convert('L') 184 | data=np.array(img) 185 | 186 | DEG = [['deg0'], ['deg45'], ['deg90'], ['deg135']] 187 | 188 | with open('GLRLM.csv','a+',newline='',encoding='utf-8') as f: 189 | csv_writer = csv.writer(f) 190 | 191 | if i==0: 192 | csv_writer.writerow(['deg0_SRE','deg45_SRE','deg90_SRE','deg135_SRE','deg0_LRE','deg45_LRE','deg90_LRE','deg135_LRE', 193 | 'deg0_GLN','deg45_GLN','deg90_GLN','deg135_GLN','deg0_RLN','deg45_RLN','deg90_RLN','deg135_RLN', 194 | 'deg0_RP','deg45_RP','deg90_RP','deg135_RP','deg0_LGLRE','deg45_LGLRE','deg90_LGLRE','deg135_LGLRE', 195 | 'deg0_HGL','deg45_HGL','deg90_HGL','deg135_HGL','deg0_SRLGLE','deg45_SRLGLE','deg90_SRLGLE','deg135_SRLGLE', 196 | 'deg0_SRHGLE','deg45_SRHGLE','deg90_SRHGLE','deg135_SRHGLE','deg0_LRLGLE','deg45_LRLGLE','deg90_LRLGLE','deg135_LRLGLE', 197 | 'deg0_LRHGLE','deg45_LRHGLE','deg90_LRHGLE','deg135_LRHGLE']) 198 | 199 | print("Processing Image",i+1) 200 | i+=1 201 | SRE_l=[] 202 | LRE_l=[] 203 | GLN_l=[] 204 | RLN_l=[] 205 | RP_l=[] 206 | LGLRE_l=[] 207 | HGL_l=[] 208 | SRLGLE_l=[] 209 | SRHGLE_l=[] 210 | LRLGLE_l=[] 211 | LRHGLE_l=[] 212 | for deg in DEG: 213 | now_deg = deg[0] 214 | test_data = getGrayLevelRumatrix(data,deg) 215 | 216 | 217 | #1 218 | SRE = getShortRunEmphasis(test_data) 219 | SRE = np.squeeze(SRE) 220 | SRE_l.append(SRE) 221 | 222 | 223 | #2 224 | LRE = getLongRunEmphasis(test_data) 225 | LRE = np.squeeze(LRE) 226 | LRE_l.append(LRE) 227 | 228 | #3 229 | GLN = getGrayLevelNonUniformity(test_data) 230 | GLN = np.squeeze(GLN) 231 | GLN_l.append(GLN) 232 | 233 | #4 234 | RLN = getRunLengthNonUniformity(test_data) 235 | RLN = np.squeeze(RLN) 236 | RLN_l.append(RLN) 237 | 238 | #5 239 | RP = getRunPercentage(test_data) 240 | RP = np.squeeze(RP) 241 | RP_l.append(RP) 242 | 243 | #6 244 | LGLRE = getLowGrayLevelRunEmphasis(test_data) 245 | LGLRE = np.squeeze(LGLRE) 246 | LGLRE_l.append(LGLRE) 247 | 248 | #7 249 | HGL = getHighGrayLevelRunEmphais(test_data) 250 | HGL = np.squeeze(HGL) 251 | HGL_l.append(HGL) 252 | 253 | #8 254 | SRLGLE = getShortRunLowGrayLevelEmphasis(test_data) 255 | SRLGLE = np.squeeze(SRLGLE) 256 | SRLGLE_l.append(SRLGLE) 257 | 258 | #9 259 | SRHGLE = getShortRunHighGrayLevelEmphasis(test_data) 260 | SRHGLE = np.squeeze(SRHGLE) 261 | SRHGLE_l.append(SRHGLE) 262 | 263 | #10 264 | LRLGLE = getLongRunLow(test_data) 265 | LRLGLE = np.squeeze(LRLGLE) 266 | LRLGLE_l.append(LRLGLE) 267 | 268 | #11 269 | LRHGLE = getLongRunHighGrayLevelEmphais(test_data) 270 | LRHGLE = np.squeeze(LRHGLE) 271 | LRHGLE_l.append(LRHGLE) 272 | 273 | 274 | csv_writer.writerow(SRE_l+LRE_l+GLN_l+RLN_l+RP_l+LGLRE_l+HGL_l+SRLGLE_l+SRHGLE_l+LRLGLE_l+LRHGLE_l) 275 | 276 | toc=time.time() 277 | print("Computation time is: {} minutes.".format(str((toc-tic)/60))) 278 | 279 | -------------------------------------------------------------------------------- /Haralick.py: -------------------------------------------------------------------------------- 1 | #13 texture features are extracted from this 2 | 3 | import cv2 4 | import numpy as np 5 | import os 6 | import glob 7 | import mahotas as mt 8 | from sklearn.svm import LinearSVC 9 | import csv 10 | import time 11 | 12 | tic = time.time() 13 | 14 | # function to extract haralick textures from an image 15 | def extract_features(image): 16 | # calculate haralick texture features for 4 types of adjacency 17 | textures = mt.features.haralick(image) 18 | 19 | # take the mean of it and return it 20 | ht_mean = textures.mean(axis=0) 21 | return ht_mean 22 | 23 | # load the training dataset 24 | train_path = ".../..../..." #Enter the directory where all the images are stored 25 | train_names = os.listdir(train_path) 26 | 27 | 28 | # empty list to hold feature vectors and train labels 29 | train_features = [] 30 | train_labels = [] 31 | 32 | # loop over the training dataset 33 | print ("[STATUS] Started extracting haralick textures..") 34 | cur_path = os.path.join(train_path, '*g') 35 | cur_label = train_names 36 | i = 0 37 | with open('Haralick_BreaKHis_temp.csv','a+',newline='') as obj: 38 | writer = csv.writer(obj) 39 | if i==0: 40 | writer.writerow(['Haralick1','Haralick2','Haralick3','Haralick4','Haralick5','Haralick6','Haralick7','Haralick8','Haralick9', 41 | 'Haralick10','Haralick11','Haralick12','Haralick13']) 42 | for file in glob.glob(cur_path): 43 | print ("Processing Image - {} in {}".format(i, cur_label[i])) 44 | #read the training image 45 | image=cv2.imread(file) 46 | 47 | #convert the image to grayscale 48 | gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY) 49 | 50 | #extract haralick texture from image 51 | features=extract_features(gray) 52 | #print(features) 53 | 54 | #append the feature vector and label 55 | train_features.append(features) 56 | train_labels.append(cur_label[i]) 57 | 58 | 59 | writer.writerow(features) 60 | 61 | #show loop update 62 | i+=1 63 | 64 | 65 | # have a look at the size of our feature vector and labels 66 | print ("Training features: {}".format(np.array(train_features).shape)) 67 | print ("Training labels: {}".format(np.array(train_labels).shape)) 68 | 69 | toc = time.time() 70 | print("Computation time is {} minutes.".format((toc-tic)/60)) 71 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Traditional-Feature-Extraction-Methods 2 | Feature Extraction is an integral step for Image Processing jobs. This repository contains the python codes for Traditonal Feature Extraction Methods from an image dataset, namely Gabor, Haralick, Tamura, GLCM and GLRLM. 3 | ## Gabor filters: 4 | In image processing, a Gabor filter, named after Dennis Gabor, is a linear filter used for edge detection. Frequency and orientation representations of Gabor filters are similar to those of the human visual system, and they have been found to be particularly appropriate for texture representation and discrimination. In the spatial domain, a 2D Gabor filter is a Gaussian kernel function modulated by a sinusoidal plane wave. Simple cells in the visual cortex of mammalian brains can be modeled by Gabor functions. Thus, image analysis with Gabor filters is thought to be similar to perception in the human visual system. 5 | 6 | Read more about Gabor filters in this paper by Arora et al.: [A Review Paper on Gabor Filter Algorithm & Its Applications](http://ijarece.org/wp-content/uploads/2017/09/IJARECE-VOL-6-ISSUE-9-1003-1007.pdf) 7 | ## Gray Level Co-occurence Matrix(GLCM): 8 | Haralick et al.(1973): [Textural Features for Image Classification](https://ieeexplore.ieee.org/abstract/document/4309314) 9 | #### Abstract of the paper: 10 | Texture is one of the important characteristics used in identifying objects or regions of interest in an image, whether the image be a photomicrograph, an aerial photograph, or a satellite image. This paper describes some easily computable textural features based on gray-tone spatial dependancies, and illustrates their application in category-identification tasks of three different kinds of image data: photomicrographs of five kinds of sandstones, 1:20 000 panchromatic aerial photographs of eight land-use categories, and Earth Resources Technology Satellite (ERTS) multispecial imagery containing seven land-use categories. We use two kinds of decision rules: one for which the decision regions are convex polyhedra (a piecewise linear decision rule), and one for which the decision regions are rectangular parallelpipeds (a min-max decision rule). In each experiment the data set was divided into two parts, a training set and a test set. Test set identification accuracy is 89 percent for the photomicrographs, 82 percent for the aerial photographic imagery, and 83 percent for the satellite imagery. These results indicate that the easily computable textural features probably have a general applicability for a wide variety of image-classification applications. 11 | ## Gray Level Run Length Matrix(GLRLM): 12 | Galloway et al.(1975): [Texture analysis using grey level run lengths](https://ui.adsabs.harvard.edu/abs/1974STIN...7518555G/abstract) 13 | ## Haralick features: 14 | Haralick texture features are calculated from a Gray Level Co-occurrence Matrix, (GLCM), a matrix that counts the co-occurrence of neighboring gray levels in the image. 15 | ## Tamura features: 16 | Tamura et al. (1978): [Textural Features Corresponding to Visual Perception](https://ieeexplore.ieee.org/abstract/document/4309999) 17 | #### Abstract of the paper: 18 | Textural features corresponding to human visual perception are very useful for optimum feature selection and texture analyzer design. We approximated in computational form six basic textural features, namely, coarseness, contrast, directionality, line-likeness, regularity, and roughness. In comparison with psychological measurements for human subjects, the computational measures gave good correspondences in rank correlation of 16 typical texture patterns. Similarity measurements using these features were attempted. The discrepancies between human vision and computerized techniques that we encountered in this study indicate fundamental problems in digital analysis of textures. Some of them could be overcome by analyzing their causes and using more sophisticated techniques. 19 | -------------------------------------------------------------------------------- /Tamura.py: -------------------------------------------------------------------------------- 1 | #4 texture features are extracted from this 2 | 3 | import cv2 4 | import numpy as np 5 | import os 6 | import glob 7 | import time 8 | 9 | tic = time.time() 10 | 11 | def coarseness(image, kmax): 12 | image = np.array(image) 13 | w = image.shape[0] 14 | h = image.shape[1] 15 | kmax = kmax if (np.power(2,kmax) < w) else int(np.log(w) / np.log(2)) 16 | kmax = kmax if (np.power(2,kmax) < h) else int(np.log(h) / np.log(2)) 17 | average_gray = np.zeros([kmax,w,h]) 18 | horizon = np.zeros([kmax,w,h]) 19 | vertical = np.zeros([kmax,w,h]) 20 | Sbest = np.zeros([w,h]) 21 | 22 | for k in range(kmax): 23 | window = np.power(2,k) 24 | for wi in range(w)[window:(w-window)]: 25 | for hi in range(h)[window:(h-window)]: 26 | average_gray[k][wi][hi] = np.sum(image[wi-window:wi+window, hi-window:hi+window]) 27 | for wi in range(w)[window:(w-window-1)]: 28 | for hi in range(h)[window:(h-window-1)]: 29 | horizon[k][wi][hi] = average_gray[k][wi+window][hi] - average_gray[k][wi-window][hi] 30 | vertical[k][wi][hi] = average_gray[k][wi][hi+window] - average_gray[k][wi][hi-window] 31 | horizon[k] = horizon[k] * (1.0 / np.power(2, 2*(k+1))) 32 | vertical[k] = horizon[k] * (1.0 / np.power(2, 2*(k+1))) 33 | 34 | for wi in range(w): 35 | for hi in range(h): 36 | h_max = np.max(horizon[:,wi,hi]) 37 | h_max_index = np.argmax(horizon[:,wi,hi]) 38 | v_max = np.max(vertical[:,wi,hi]) 39 | v_max_index = np.argmax(vertical[:,wi,hi]) 40 | index = h_max_index if (h_max > v_max) else v_max_index 41 | Sbest[wi][hi] = np.power(2,index) 42 | 43 | fcrs = np.mean(Sbest) 44 | return fcrs 45 | 46 | 47 | def contrast(image): 48 | image = np.array(image) 49 | image = np.reshape(image, (1, image.shape[0]*image.shape[1])) 50 | m4 = np.mean(np.power(image - np.mean(image),4)) 51 | v = np.var(image) 52 | std = np.power(v, 0.5) 53 | alfa4 = m4 / np.power(v,2) 54 | fcon = std / np.power(alfa4, 0.25) 55 | return fcon 56 | 57 | def directionality(image): 58 | image = np.array(image, dtype = 'int64') 59 | h = image.shape[0] 60 | w = image.shape[1] 61 | convH = np.array([[-1,0,1],[-1,0,1],[-1,0,1]]) 62 | convV = np.array([[1,1,1],[0,0,0],[-1,-1,-1]]) 63 | deltaH = np.zeros([h,w]) 64 | deltaV = np.zeros([h,w]) 65 | theta = np.zeros([h,w]) 66 | 67 | # calc for deltaH 68 | for hi in range(h)[1:h-1]: 69 | for wi in range(w)[1:w-1]: 70 | deltaH[hi][wi] = np.sum(np.multiply(image[hi-1:hi+2, wi-1:wi+2], convH)) 71 | for wi in range(w)[1:w-1]: 72 | deltaH[0][wi] = image[0][wi+1] - image[0][wi] 73 | deltaH[h-1][wi] = image[h-1][wi+1] - image[h-1][wi] 74 | for hi in range(h): 75 | deltaH[hi][0] = image[hi][1] - image[hi][0] 76 | deltaH[hi][w-1] = image[hi][w-1] - image[hi][w-2] 77 | 78 | # calc for deltaV 79 | for hi in range(h)[1:h-1]: 80 | for wi in range(w)[1:w-1]: 81 | deltaV[hi][wi] = np.sum(np.multiply(image[hi-1:hi+2, wi-1:wi+2], convV)) 82 | for wi in range(w): 83 | deltaV[0][wi] = image[1][wi] - image[0][wi] 84 | deltaV[h-1][wi] = image[h-1][wi] - image[h-2][wi] 85 | for hi in range(h)[1:h-1]: 86 | deltaV[hi][0] = image[hi+1][0] - image[hi][0] 87 | deltaV[hi][w-1] = image[hi+1][w-1] - image[hi][w-1] 88 | 89 | deltaG = (np.absolute(deltaH) + np.absolute(deltaV)) / 2.0 90 | deltaG_vec = np.reshape(deltaG, (deltaG.shape[0] * deltaG.shape[1])) 91 | 92 | # calc the theta 93 | for hi in range(h): 94 | for wi in range(w): 95 | if (deltaH[hi][wi] == 0 and deltaV[hi][wi] == 0): 96 | theta[hi][wi] = 0; 97 | elif(deltaH[hi][wi] == 0): 98 | theta[hi][wi] = np.pi 99 | else: 100 | theta[hi][wi] = np.arctan(deltaV[hi][wi] / deltaH[hi][wi]) + np.pi / 2.0 101 | theta_vec = np.reshape(theta, (theta.shape[0] * theta.shape[1])) 102 | 103 | n = 16 104 | t = 12 105 | cnt = 0 106 | hd = np.zeros(n) 107 | dlen = deltaG_vec.shape[0] 108 | for ni in range(n): 109 | for k in range(dlen): 110 | if((deltaG_vec[k] >= t) and (theta_vec[k] >= (2*ni-1) * np.pi / (2 * n)) and (theta_vec[k] < (2*ni+1) * np.pi / (2 * n))): 111 | hd[ni] += 1 112 | hd = hd / np.mean(hd) 113 | hd_max_index = np.argmax(hd) 114 | fdir = 0 115 | for ni in range(n): 116 | fdir += np.power((ni - hd_max_index), 2) * hd[ni] 117 | return fdir 118 | 119 | def roughness(fcrs, fcon): 120 | return fcrs + fcon 121 | 122 | if __name__ == '__main__': 123 | 124 | # load the training dataset 125 | train_path = "D:/#Projects/Image Processing Project Prof. Nibaran Das/400X/Train" 126 | train_names = os.listdir(train_path) 127 | 128 | # loop over the training dataset 129 | cur_path = os.path.join(train_path, '*g') 130 | cur_label = train_names 131 | i = 0 132 | 133 | for file in glob.glob(cur_path): 134 | print('For image {} named {}:'.format(i+1,cur_label[i])) 135 | img = cv2.imread(file) 136 | img=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) 137 | print('Shape of image is: {} '.format(img.shape)) 138 | fcrs = coarseness(img, 5) 139 | print("coarseness: %f" % fcrs); 140 | fcon = contrast(img) 141 | print("contrast: %f" % fcon) 142 | fdir= directionality(img) 143 | print("directionality: %f" % fdir) 144 | f_r=roughness(fcrs,fcon) 145 | print("roughness: %f" % f_r) 146 | print('\n\n') 147 | i+=1 148 | 149 | toc = time.time() 150 | print("Computation time is {} minutes".format((toc-tic)/60)) 151 | --------------------------------------------------------------------------------