CoolFace
Apppublic

pidoko/textureClassification

sourceHugging Faceupdated 2y agoView on Hugging Face
0likes
feature.py159 linesDownload Raw Back to root
1# Program implementing GLCM to extract contrast, correlation, energy and homogeneity,
2# and LBP to create a histogram to capture micro patterns.
3
4import logging
5import numpy as np
6import skimage.feature as sf
7import cv2
8from glob import glob
9import pandas as pd
10from skimage.feature import local_binary_pattern, graycomatrix, graycoprops
11from pathlib import Path
12from typing import List
13from config import BASE_PATH, IMAGE_SIZE, DISTANCES, ANGLES, LBP_RADIUS, LBP_POINTS, LBP_METHOD, TEXTURE_CLASSES, OUTPUT_DIR
14
15# Setup logging
16logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
17
18def load_and_preprocess_image(image_path: str) -> np.ndarray:
19    """
20    Loads an image in grayscale and applies histogram equalization.
21    
22    Args:
23        image_path (str): Path to the image file.
24    
25    Returns:
26        np.ndarray: Preprocessed grayscale image.
27    """
28    image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
29    
30    if image is None:
31        logging.warning(f"Skipping unreadable image: {image_path}")
32        return None
33
34    image = cv2.equalizeHist(image)
35    image = cv2.resize(image, IMAGE_SIZE)
36    return image
37
38# Base path
39base_path = "C:/Users/peter_idoko.VACFSS/Documents/VSCode/textureClassification"
40
41# GLCM parameters: distances and angles
42# Pixel offset to capture finer and coarse textures
43distances = [1, 2, 3, 4]
44
45# Captures the four primary orientations in a 2D image
46angles = [0, np.pi/4, np.pi/2, 3*np.pi/4]
47
48# LBP parameters: radius, points, method
49LBP_RADIUS = 3  # Defines neighborhood radius
50LBP_POINTS = min(8 * LBP_RADIUS, 24)  # Number of points for LBP
51LBP_METHOD = "uniform"  # Rotation-invariant LBP
52
53# Resize images to a smaller size to speed up GLCM processing
54IMAGE_SIZE = (64, 64) # 64x64 pixels
55
56def compute_glcm_features(image: np.ndarray) -> np.ndarray:
57    """
58    Computes GLCM features: contrast, correlation, energy, and homogeneity.
59    
60    Args:
61        image (np.ndarray): Grayscale image.
62    
63    Returns:
64        np.ndarray: Feature vector containing GLCM properties.
65    """
66    glcm = graycomatrix(image, distances=DISTANCES, angles=ANGLES, levels=256, symmetric=True, normed=True)
67
68    features = np.hstack([
69        graycoprops(glcm, prop).flatten()
70        for prop in ["contrast", "correlation", "energy", "homogeneity"]
71    ])
72
73    return features
74
75def compute_lbp_features(image: np.ndarray) -> np.ndarray:
76    """
77    Computes LBP histogram features.
78    
79    Args:
80        image (np.ndarray): Grayscale image.
81    
82    Returns:
83        np.ndarray: Normalized LBP histogram.
84    """
85    lbp = local_binary_pattern(image, P=LBP_POINTS, R=LBP_RADIUS, method=LBP_METHOD)
86
87    lbp_hist, _ = np.histogram(lbp.ravel(), bins=np.arange(0, LBP_POINTS + 3), range=(0, LBP_POINTS + 2))
88    lbp_hist = lbp_hist.astype("float")
89    lbp_hist /= (lbp_hist.sum() + 1e-8)  # Avoid division by zero
90    return lbp_hist
91
92
93def extract_features() -> None:
94    """
95    Extracts GLCM and LBP features from images and saves them as CSV files.
96    """
97    glcm_features_list, lbp_features_list, labels = [], [], []
98
99    for class_label in TEXTURE_CLASSES:
100        class_path = Path(BASE_PATH) / class_label
101        image_files = list(class_path.glob("*.jpg")) + \
102                      list(class_path.glob("*.png")) + \
103                      list(class_path.glob("*.webp")) + \
104                      list(class_path.glob("*.tiff"))
105
106        for image_path in image_files:
107            image = load_and_preprocess_image(str(image_path))
108            if image is None:
109                continue
110
111            glcm_features = compute_glcm_features(image)
112            lbp_features = compute_lbp_features(image)
113
114            glcm_features_list.append(glcm_features)
115            lbp_features_list.append(lbp_features)
116            labels.append(class_label)
117
118    save_features_to_csv(glcm_features_list, lbp_features_list, labels)
119
120
121def save_features_to_csv(glcm_features_list: List[np.ndarray], lbp_features_list: List[np.ndarray], labels: List[str]) -> None:
122    """
123    Saves extracted features to CSV files.
124    
125    Args:
126        glcm_features_list (List[np.ndarray]): List of GLCM feature vectors.
127        lbp_features_list (List[np.ndarray]): List of LBP feature vectors.
128        labels (List[str]): Corresponding class labels.
129    """
130    glcm_columns = [
131        f"{prop}_{d}_{int(np.degrees(a))}"
132        for prop in ["contrast", "correlation", "energy", "homogeneity"]
133        for d in DISTANCES
134        for a in ANGLES
135    ]
136    lbp_columns = [f"lbp_{i}" for i in range(LBP_POINTS + 2)]
137
138    df_glcm = pd.DataFrame(glcm_features_list, columns=glcm_columns)
139    df_lbp = pd.DataFrame(lbp_features_list, columns=lbp_columns)
140
141    df_glcm["label"] = labels
142    df_lbp["label"] = labels
143
144    # Ensure output directory exists
145    Path(OUTPUT_DIR).mkdir(parents=True, exist_ok=True)
146
147    glcm_csv_path = Path(OUTPUT_DIR) / "texture_features_glcm.csv"
148    lbp_csv_path = Path(OUTPUT_DIR) / "texture_features_lbp.csv"
149
150    df_glcm.to_csv(glcm_csv_path, index=False)
151    df_lbp.to_csv(lbp_csv_path, index=False)
152
153    logging.info(f"GLCM features saved to {glcm_csv_path}")
154    logging.info(f"LBP features saved to {lbp_csv_path}")
155
156
157if __name__ == "__main__":
158    extract_features()
159