File size: 4,339 Bytes
8ed1da1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7a47e4d
8ed1da1
 
 
 
 
 
7a47e4d
8ed1da1
 
 
 
 
7a47e4d
8ed1da1
 
 
7a47e4d
8ed1da1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7a47e4d
 
8ed1da1
 
 
 
 
 
 
 
ef22c1c
 
 
 
8ed1da1
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
import os as _os
import cv2 as _cv2
import numpy as _np
import glob as _glob
import joblib as _jb
import matplotlib.pyplot as _plt

from skimage.feature import local_binary_pattern as _lbp, graycomatrix as _gcm, graycoprops as _gcp
from sklearn.model_selection import train_test_split as _tts
from sklearn.metrics import classification_report as _cr, accuracy_score as _acc
from sklearn.svm import SVC as _S
from sklearn.ensemble import RandomForestClassifier as _RF
from sklearn.linear_model import LogisticRegression as _LR

# distances and angles for GLCM
def  generateAngles():
    angs = [_np.pi * i / 5 for i in range(5)]          # five angles at 0, π/5, 2π/5, 3π/5, 4π/5
    s = "1.2,2.2,3.1"                                     # string of distances
    dists = [float(x) for x in s.split(",")]             # parse distances to floats
    return angs, dists

(_bestangles, _bestglcmdist) =  generateAngles()

# best parameters for LBP
_bestpoints = 9
_bestradius = 1

# SVM hyperparameters
def  generateSVM_Args():
    kern = 'linear'
    Cval = 2.1
    gamma = 'scale'
    rs = 42
    return {'kernel': kern, 'C': Cval, 'gamma': gamma, 'random_state': rs}

# Random Forest hyperparameters
def  generateRF_Args():
    ne = 110
    rs = 40
    nj = -1
    return {'n_estimators': ne, 'random_state': rs, 'n_jobs': nj}

# Logistic Regression hyperparameters
def  generateLR_Args():
    mc = 'multinomial'
    solv = 'lbfgs'
    mi = 900
    rs = 37
    return {'multi_class': mc, 'solver': solv, 'max_iter': mi, 'random_state': rs}

# Color feature extraction: compute 3D histogram component A
def fun_colorA(img):
    return _cv2.calcHist([img], [0,1,2], None, (5,5,5), [0,256,0,256,0,256])

# Color feature extraction: normalize and flatten histogram
def fun_colorB(hist_raw):
    _cv2.normalize(hist_raw, hist_raw)
    return hist_raw.flatten()

# Full color histogram feature
def fun_color(img):
    return fun_colorB(fun_colorA(img))

# Convert image to grayscale for LBP
def lbpGray(img):
    return _cv2.cvtColor(img, _cv2.COLOR_BGR2GRAY)

# Compute LBP map with specified points and radius
def lbpMap(gray_img):
    return _lbp(gray_img, _bestpoints, _bestradius, method='uniform')

# Compute normalized histogram of LBP map
def lbpHist(lbp_map):
    bins = _np.arange(0, _bestpoints + 3)                 # bin edges from 0 to points+2
    h, _ = _np.histogram(lbp_map.ravel(), bins=bins, range=(0, _bestpoints + 2))
    h = h.astype('float')
    return h / (h.sum() + 1e-6)                            # avoid division by zero

# Full LBP feature pipeline: grayscale → map → histogram
def lbpFeature(img):
    g = lbpGray(img)
    lm = lbpMap(g)
    return lbpHist(lm)

# Convert image to grayscale for GLCM
def glcmGray(img):
    return _cv2.cvtColor(img, _cv2.COLOR_BGR2GRAY)

# Compute GLCM matrix given distances and angles
def glcmMatrix(gray_img):
    return _gcm(gray_img, distances=_bestglcmdist, angles=_bestangles, symmetric=True, normed=True)

# Extract a single GLCM property vector
def glcmProperties(glcm_mat, prop_name):
    return _gcp(glcm_mat, prop_name).flatten()

# Full GLCM feature pipeline: grayscale → GLCM matrix → properties
def glcmFeature(img):
    gray = glcmGray(img)
    glcm = glcmMatrix(gray)
    features = []
    properties = ["contrast", "dissimilarity", "homogeneity", "energy"]
    for prop in properties:
        features.extend(glcmProperties(glcm, prop))        # append each property’s flattened values
    return _np.array(features)

# Convert image to grayscale for Hu moments
def huGray(img):
    return _cv2.cvtColor(img, _cv2.COLOR_BGR2GRAY)

# Compute Hu Moments from grayscale image
def huMoments(img):
    g = huGray(img)
    m = _cv2.moments(g)
    return _cv2.HuMoments(m).flatten()

# Combine all feature types for a given image path
def FullFeautures(pathF):
    img = _cv2.imread(pathF)
    if img is None:
        print(f"[Warning] cannot read {pathF}")
        return None

    # compute each feature block
    ch   = fun_color(img)    # color histogram length = 125
    lbph = lbpFeature(img)      # LBP histogram length = 11
    glc  = glcmFeature(img)     # GLCM feature length = 60
    hu   = huMoments(img)   # Hu moments length = 7

    fv = []

    fv.extend(ch)
    fv.extend(lbph)
    fv.extend(glc)
    fv.extend(hu)

    return _np.array(fv)