100 lines
3.6 KiB
Python
100 lines
3.6 KiB
Python
import numpy as np
|
|
import cv2
|
|
from skimage.feature import graycomatrix, graycoprops
|
|
import pandas as pd
|
|
from sqlalchemy import Extract
|
|
|
|
class FeatureExtractor:
|
|
def __init__(self):
|
|
# Fitur: Average RGB (3) + GLCM (4) = 7 features total
|
|
self.feature_names = ['avg_red', 'avg_green', 'avg_blue',
|
|
'contrast', 'homogeneity', 'correlation', 'energy']
|
|
|
|
def extract_rgb_average(self, image_rgb):
|
|
"""Extract average values for R, G, B channels
|
|
|
|
Parameters:
|
|
- image_rgb: RGB image (uint8)
|
|
|
|
Return: list [avg_red, avg_green, avg_blue]
|
|
"""
|
|
if image_rgb is None:
|
|
print("[WARNING] image_rgb is None in extract_rgb_average")
|
|
return [0.0, 0.0, 0.0]
|
|
|
|
try:
|
|
avg_red = np.mean(image_rgb[:, :, 0])
|
|
avg_green = np.mean(image_rgb[:, :, 1])
|
|
avg_blue = np.mean(image_rgb[:, :, 2])
|
|
return [avg_red, avg_green, avg_blue]
|
|
except Exception as e:
|
|
print(f"[ERROR] extract_rgb_average failed: {str(e)}")
|
|
return [0.0, 0.0, 0.0]
|
|
|
|
def glcm_features(self, gray_image):
|
|
"""Extract GLCM texture features (4)
|
|
|
|
Parameters:
|
|
- gray_image: Grayscale image hasil threshold (uint8)
|
|
|
|
Return: list [contrast, homogeneity, correlation, energy]
|
|
"""
|
|
# Validate input
|
|
if gray_image is None:
|
|
print("[WARNING] gray_image is None in glcm_features")
|
|
return [0.0, 0.0, 0.0, 0.0]
|
|
|
|
try:
|
|
gray = gray_image.astype(np.uint8)
|
|
|
|
glcm = graycomatrix(gray, distances=[1, 2, 3],
|
|
angles=[0, np.pi/4, np.pi/2, 3*np.pi/4],
|
|
levels=256, symmetric=True, normed=True)
|
|
|
|
features = []
|
|
for prop in ['contrast', 'homogeneity', 'correlation', 'energy']:
|
|
prop_values = graycoprops(glcm, prop)
|
|
features.append(np.mean(prop_values))
|
|
|
|
return features
|
|
except Exception as e:
|
|
print(f"[ERROR] glcm_features failed: {str(e)}")
|
|
return [0.0, 0.0, 0.0, 0.0]
|
|
|
|
def extract_all_features(self, image_rgb, gray_processed):
|
|
"""Extract 7 features: Average RGB (3) + GLCM (4)
|
|
|
|
Parameters:
|
|
- image_rgb: RGB image from preprocessing pipeline (uint8)
|
|
- gray_processed: Grayscale hasil threshold dari preprocessing pipeline (uint8)
|
|
|
|
Return: list of 7 features
|
|
"""
|
|
# Validate inputs
|
|
if image_rgb is None:
|
|
print("[ERROR] image_rgb is None in extract_all_features")
|
|
return [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
|
|
if gray_processed is None:
|
|
print("[ERROR] gray_processed is None in extract_all_features")
|
|
return [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
|
|
|
|
# Extract average RGB values (3)
|
|
rgb_features = self.extract_rgb_average(image_rgb)
|
|
|
|
# Extract GLCM texture features (4)
|
|
glcm_features_list = self.glcm_features(gray_processed)
|
|
|
|
all_features = rgb_features + glcm_features_list
|
|
|
|
return all_features
|
|
|
|
def save_features_to_csv(self, features_list, labels, filename):
|
|
"""Save extracted features to CSV"""
|
|
df = pd.DataFrame(features_list, columns=self.feature_names)
|
|
df['label'] = labels
|
|
|
|
# Save to CSV
|
|
df.to_csv(filename, index=False)
|
|
print(f"Fitur disimpan ke: {filename}")
|
|
|
|
return df |