import torch import matplotlib matplotlib.use('Agg') # 設置非 GUI 後端,避免 Tkinter 錯誤 import matplotlib.pyplot as plt from PIL import Image import numpy as np import os from skimage.segmentation import slic from skimage.util import img_as_float from skimage.color import label2rgb from scipy.spatial.distance import cdist # 設置全局中文字體支持 plt.rcParams['font.sans-serif'] = ['Microsoft YaHei', 'SimHei', 'Arial Unicode MS', 'DejaVu Sans'] plt.rcParams['axes.unicode_minus'] = False from utils.Stomach_Config import Loading_Config, Save_Result_File_Config from Load_process.LoadData import Loding_Data_Root from Load_process.file_processing import Process_File from merge_class.merge import merge from model_data_processing.processing import make_label_list from Load_process.LoadData import Load_Data_Prepare def save_superpixel_regions(image_array, segments, save_dir, image_name, max_regions=50): """ Save individual superpixel regions as separate images. Args: - image_array: Original image array (H, W, 3) - segments: Superpixel segmentation labels (H, W) - save_dir: Directory to save superpixel region images - image_name: Base name for the image files - max_regions: Maximum number of regions to save (to avoid too many files) Returns: - saved_regions: List of saved region information """ os.makedirs(save_dir, exist_ok=True) saved_regions = [] unique_segments = np.unique(segments) # Limit the number of regions to save if len(unique_segments) > max_regions: print(f"⚠️ 超像素數量 ({len(unique_segments)}) 超過限制 ({max_regions}),只保存前 {max_regions} 個") unique_segments = unique_segments[:max_regions] print(f"💾 保存 {len(unique_segments)} 個超像素區域到: {save_dir}") for i, segment_id in enumerate(unique_segments): # Get mask for current superpixel mask = segments == segment_id # Get bounding box of the region y_coords, x_coords = np.where(mask) if len(y_coords) == 0: continue min_y, max_y = y_coords.min(), y_coords.max() min_x, max_x = x_coords.min(), x_coords.max() # Extract the region with some padding padding = 5 min_y = max(0, min_y - padding) max_y = min(image_array.shape[0], max_y + padding + 1) min_x = max(0, min_x - padding) max_x = min(image_array.shape[1], max_x + padding + 1) # Extract region from original image region_image = image_array[min_y:max_y, min_x:max_x].copy() region_mask = mask[min_y:max_y, min_x:max_x] # Apply mask to make background transparent/black region_image[~region_mask] = [0, 0, 0] # Set non-region pixels to black # Convert to PIL Image and save region_pil = Image.fromarray(region_image.astype(np.uint8)) # Create filename region_filename = f"{image_name}_superpixel_{segment_id:03d}_region_{i+1:03d}.png" region_path = os.path.join(save_dir, region_filename) # Save the region region_pil.save(region_path) # Calculate region statistics region_pixels = image_array[mask] mean_color = np.mean(region_pixels, axis=0) region_area = np.sum(mask) centroid_y = np.mean(y_coords) centroid_x = np.mean(x_coords) region_info = { 'segment_id': segment_id, 'filename': region_filename, 'path': region_path, 'area': region_area, 'centroid': (centroid_x, centroid_y), 'mean_color': mean_color, 'bbox': (min_x, min_y, max_x, max_y) } saved_regions.append(region_info) print(f"✅ 成功保存 {len(saved_regions)} 個超像素區域影像") return saved_regions def calculate_optimal_superpixel_params(image_size): """ Calculate optimal superpixel parameters based on image size. Args: - image_size: Total number of pixels (width * height) Returns: - n_segments: Number of superpixel segments - compactness: Compactness parameter for SLIC """ # 根據圖片大小動態調整參數 if image_size < 50000: # 小圖片 (< 224x224) n_segments = min(100, max(50, image_size // 500)) compactness = 15 elif image_size < 200000: # 中等圖片 (< 447x447) n_segments = min(300, max(100, image_size // 800)) compactness = 12 elif image_size < 500000: # 大圖片 (< 707x707) n_segments = min(500, max(200, image_size // 1000)) compactness = 10 else: # 超大圖片 n_segments = min(800, max(300, image_size // 1500)) compactness = 8 return int(n_segments), compactness def extract_superpixel_features(image_array, segments): """ Extract features for each superpixel region. Args: - image_array: Original image array (H, W, 3) - segments: Superpixel segmentation labels (H, W) Returns: - features: Array of features for each superpixel (N_superpixels, 5) [mean_R, mean_G, mean_B, norm_centroid_x, norm_centroid_y] - centroids: Array of centroid positions for each superpixel (N_superpixels, 2) """ n_segments = len(np.unique(segments)) features = [] centroids = [] for segment_id in np.unique(segments): # Get mask for current superpixel mask = segments == segment_id # Extract color features (mean RGB) region_pixels = image_array[mask] mean_color = np.mean(region_pixels, axis=0) # Extract position features (centroid) y_coords, x_coords = np.where(mask) centroid_y = np.mean(y_coords) centroid_x = np.mean(x_coords) # Combine features: [mean_R, mean_G, mean_B, centroid_x, centroid_y] # Normalize centroid coordinates to [0, 1] range norm_centroid_x = centroid_x / image_array.shape[1] norm_centroid_y = centroid_y / image_array.shape[0] feature_vector = np.concatenate([mean_color, [norm_centroid_x, norm_centroid_y]]) features.append(feature_vector) centroids.append([centroid_x, centroid_y]) return np.array(features), np.array(centroids) def fuzzy_c_means(data, n_clusters, m=2.0, max_iter=100, tol=1e-4, random_state=None): """ Fuzzy C-means clustering algorithm implementation. Args: - data: Input data array (N_samples, N_features) - n_clusters: Number of clusters - m: Fuzziness parameter (m > 1, typically 2.0) - max_iter: Maximum number of iterations - tol: Tolerance for convergence - random_state: Random seed for reproducibility Returns: - centers: Cluster centers (n_clusters, N_features) - membership: Membership matrix (N_samples, n_clusters) - labels: Hard cluster assignments (N_samples,) - objective: Final objective function value - n_iter: Number of iterations performed """ if random_state is not None: np.random.seed(random_state) torch.manual_seed(random_state) # Convert to torch tensor device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') X = torch.from_numpy(data).float().to(device) n_samples, n_features = X.shape # Initialize membership matrix randomly U = torch.rand(n_samples, n_clusters, device=device) U = U / U.sum(dim=1, keepdim=True) # Normalize so each row sums to 1 print(f"🔄 開始 Fuzzy C-means 聚類: {n_clusters} 個聚類中心, 模糊度參數 m={m}") for iteration in range(max_iter): U_old = U.clone() # Update cluster centers Um = U ** m # Membership matrix raised to power m centers = (Um.T @ X) / Um.sum(dim=0, keepdim=True).T # Update membership matrix # Calculate distances from each point to each center distances = torch.cdist(X, centers) # (n_samples, n_clusters) # Avoid division by zero distances = torch.clamp(distances, min=1e-10) # Calculate new membership values power = 2.0 / (m - 1.0) distance_matrix = distances ** power # For each sample, calculate membership to each cluster for i in range(n_samples): for j in range(n_clusters): denominator = torch.sum((distance_matrix[i, j] / distance_matrix[i, :])) U[i, j] = 1.0 / denominator # Check for convergence diff = torch.norm(U - U_old) if diff < tol: print(f"✅ Fuzzy C-means 收斂於第 {iteration + 1} 次迭代 (差異: {diff:.6f})") break if (iteration + 1) % 20 == 0: print(f" 迭代 {iteration + 1}/{max_iter}, 差異: {diff:.6f}") # Calculate final objective function value Um = U ** m distances_squared = torch.cdist(X, centers) ** 2 objective = torch.sum(Um * distances_squared).item() # Get hard cluster assignments (highest membership) labels = torch.argmax(U, dim=1) # Convert back to numpy centers_np = centers.cpu().numpy() membership_np = U.cpu().numpy() labels_np = labels.cpu().numpy() print(f"🎯 Fuzzy C-means 完成: 目標函數值 = {objective:.4f}") return centers_np, membership_np, labels_np, objective, iteration + 1 def determine_optimal_clusters(data, gamma_values, max_clusters=10, min_clusters=2): """ Determine optimal number of clusters using gamma values from density peak analysis and fuzzy clustering validation indices. Args: - data: Input data array (N_samples, N_features) - gamma_values: Gamma values from density peak analysis - max_clusters: Maximum number of clusters to test - min_clusters: Minimum number of clusters to test Returns: - optimal_k: Optimal number of clusters - scores: Dictionary containing validation scores for each k """ n_samples = len(data) max_clusters = min(max_clusters, n_samples - 1) # Method 1: Use gamma values to estimate cluster centers # Sort gamma values and look for significant drops sorted_gamma = np.sort(gamma_values)[::-1] # Descending order gamma_diffs = np.diff(sorted_gamma) # Find the largest drop in gamma values (elbow method) if len(gamma_diffs) > 0: elbow_idx = np.argmax(np.abs(gamma_diffs)) + 1 gamma_suggested_k = min(max_clusters, max(min_clusters, elbow_idx)) else: gamma_suggested_k = min_clusters print(f"📊 基於 Gamma 值分析建議的聚類數: {gamma_suggested_k}") # Method 2: Test different k values with fuzzy clustering validation scores = {} best_k = gamma_suggested_k best_score = -np.inf print(f"🔍 測試聚類數從 {min_clusters} 到 {max_clusters}...") for k in range(min_clusters, max_clusters + 1): try: # Perform fuzzy c-means clustering centers, membership, labels, objective, n_iter = fuzzy_c_means( data, k, m=2.0, max_iter=50, random_state=42 ) # Calculate Partition Coefficient (PC) - higher is better pc = np.mean(np.sum(membership ** 2, axis=1)) # Calculate Partition Entropy (PE) - lower is better pe = -np.mean(np.sum(membership * np.log(membership + 1e-10), axis=1)) # Calculate Modified Partition Coefficient (MPC) - higher is better mpc = 1 - k / (k - 1) * (1 - pc) if k > 1 else pc # Combined score (higher is better) combined_score = pc - 0.1 * pe + 0.5 * mpc scores[k] = { 'pc': pc, 'pe': pe, 'mpc': mpc, 'combined_score': combined_score, 'objective': objective, 'n_iter': n_iter } print(f" K={k}: PC={pc:.3f}, PE={pe:.3f}, MPC={mpc:.3f}, 組合分數={combined_score:.3f}") if combined_score > best_score: best_score = combined_score best_k = k except Exception as e: print(f" K={k}: 聚類失敗 - {e}") scores[k] = {'error': str(e)} print(f"🎯 最佳聚類數: {best_k} (組合分數: {best_score:.3f})") return best_k, scores def visualize_clustering_results(image_array, segments, labels, centers, membership, save_path): """ Visualize fuzzy clustering results on the original image. Args: - image_array: Original image array (H, W, 3) - segments: Superpixel segmentation labels (H, W) - labels: Hard cluster assignments for each superpixel - centers: Cluster centers - membership: Fuzzy membership matrix - save_path: Path to save the visualization """ # 設置中文字體支持 plt.rcParams['font.sans-serif'] = ['Microsoft YaHei', 'SimHei', 'DejaVu Sans'] plt.rcParams['axes.unicode_minus'] = False fig, axes = plt.subplots(2, 3, figsize=(18, 12)) # Original image axes[0, 0].imshow(image_array) axes[0, 0].set_title('原始影像', fontsize=14) axes[0, 0].axis('off') # Superpixel segmentation superpixel_img = label2rgb(segments, image_array, kind='avg', bg_label=0) axes[0, 1].imshow(superpixel_img) axes[0, 1].set_title(f'超像素分割 ({len(np.unique(segments))} 個區域)', fontsize=14) axes[0, 1].axis('off') # Hard clustering result n_clusters = len(centers) colors = plt.cm.Set3(np.linspace(0, 1, n_clusters)) # Create clustering visualization cluster_img = np.zeros_like(image_array) for segment_id in np.unique(segments): if segment_id < len(labels): cluster_id = labels[segment_id] mask = segments == segment_id cluster_img[mask] = colors[cluster_id][:3] axes[0, 2].imshow(cluster_img) axes[0, 2].set_title(f'硬聚類結果 ({n_clusters} 個聚類)', fontsize=14) axes[0, 2].axis('off') # Fuzzy membership visualization for top 3 clusters for i in range(min(3, n_clusters)): fuzzy_img = np.zeros(image_array.shape[:2]) for segment_id in np.unique(segments): if segment_id < len(membership): mask = segments == segment_id fuzzy_img[mask] = membership[segment_id, i] im = axes[1, i].imshow(fuzzy_img, cmap='hot', vmin=0, vmax=1) axes[1, i].set_title(f'聚類 {i+1} 的模糊隸屬度', fontsize=14) axes[1, i].axis('off') plt.colorbar(im, ax=axes[1, i], fraction=0.046, pad=0.04) plt.tight_layout() plt.savefig(save_path, dpi=300, bbox_inches='tight') plt.close() print(f"📊 聚類結果可視化已保存至: {save_path}") def compute_decision_graph(image_path, Save_Root, dc=None, use_gaussian=False, threshold_factor=2.0, use_superpixels=True, n_segments=None, compactness=None, save_regions=True, max_regions=50): """ Process a single image to compute the decision graph using Density Peak Clustering principles. Identifies potential cluster centers without performing full clustering. Also computes gamma (rho * delta) and n (index in descending order of gamma) values. Args: - image_path: Path to the image file. - dc: Cut-off distance. If None, approximates it as 2% of average neighbors. - use_gaussian: If True, uses Gaussian kernel for density; else cut-off kernel. - threshold_factor: Factor for std deviation to determine thresholds for centers. - use_superpixels: If True, uses SLIC superpixel segmentation instead of raw pixels. - n_segments: Number of superpixel segments (only used if use_superpixels=True). - compactness: Compactness parameter for SLIC algorithm (only used if use_superpixels=True). Returns: - dict: Contains center_indices, center_points, rho, delta, gamma, and n arrays. gamma = rho * delta (product of local density and minimum distance) n = index in descending order of gamma (1-indexed as per Density Peak convention) If use_superpixels=True, also contains 'segments' and 'superpixel_features'. """ # Load image img = Image.open(image_path).convert('RGB') img_array = np.array(img) / 255.0 # Normalize to [0, 1] image_size = img_array.shape[0] * img_array.shape[1] # 強制使用 Superpixel 分割,並動態計算參數 if n_segments is None or compactness is None: n_segments, compactness = calculate_optimal_superpixel_params(image_size) print(f"🖼️ 圖像大小: {img.size} ({image_size:,} 像素)") print(f"🔧 使用動態 Superpixel 參數: n_segments={n_segments}, compactness={compactness}") # Apply SLIC superpixel segmentation (強制使用) print(f"🎯 應用 SLIC 超像素分割,目標 {n_segments} 個區域...") segments = slic(img_array, n_segments=n_segments, compactness=compactness, start_label=1, enforce_connectivity=True) # Extract features for each superpixel superpixel_features, superpixel_centroids = extract_superpixel_features(img_array, segments) points = torch.from_numpy(superpixel_features).float() print(f"✅ 成功從 {img_array.shape[0] * img_array.shape[1]:,} 像素壓縮到 {len(superpixel_features)} 個超像素") # Save superpixel regions if requested if save_regions: # Get image name without extension image_name = os.path.splitext(os.path.basename(image_path))[0] superpixel_regions_dir = os.path.join(Save_Root, f"{image_name}_superpixel_regions") # Convert back to 0-255 range for saving img_array_255 = (img_array * 255).astype(np.uint8) saved_regions = save_superpixel_regions(img_array_255, segments, superpixel_regions_dir, image_name, max_regions) print(f"💾 已保存 {len(saved_regions)} 個超像素區域影像到: {superpixel_regions_dir}") device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') points = points.to(device) N = points.shape[0] print(f"🔄 處理圖像: {os.path.basename(image_path)} 在 {device} 上 (使用超像素分割)") # Compute pairwise distances dist = torch.cdist(points, points) # Approximate dc if not provided (using a sample for efficiency) if dc is None: # Sample 1000 points to estimate dc sample_size = min(1000, N) sample_idx = torch.randperm(N)[:sample_size] sample_dist = torch.cdist(points[sample_idx], points) sample_dist_flat = sample_dist.flatten() sample_dist_flat = sample_dist_flat[sample_dist_flat > 0] # Exclude zeros sorted_dist = torch.sort(sample_dist_flat)[0] pos = int(len(sorted_dist) * 0.02) dc = sorted_dist[pos].item() print(f"Approximated dc: {dc}") # Compute local density rho if use_gaussian: rho = torch.exp(-(dist ** 2) / (2 * dc ** 2)).sum(dim=1) - 1 else: rho = (dist < dc).float().sum(dim=1) - 1 # Compute delta sorted_rho, sorted_idx = torch.sort(rho, descending=True) delta = torch.full((N,), 0.0, device=device) nn = torch.full((N,), -1, dtype=torch.long, device=device) # For the highest density point delta[sorted_idx[0]] = dist[sorted_idx[0]].max() # For others for i in range(1, N): higher_idx = sorted_idx[:i] cur_idx = sorted_idx[i] dists_to_higher = dist[cur_idx, higher_idx] min_dist_idx = torch.argmin(dists_to_higher) delta[cur_idx] = dists_to_higher[min_dist_idx] nn[cur_idx] = higher_idx[min_dist_idx] # Calculate gamma (rho * delta) and n (index in descending order of gamma) gamma = rho * delta sorted_gamma_indices = torch.argsort(gamma, descending=True) n = torch.empty_like(sorted_gamma_indices) n[sorted_gamma_indices] = torch.arange(1, N + 1, device=device) # Plot decision graph with two subplots fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 6)) # Decision graph (rho vs delta) rho_np = rho.cpu().numpy() delta_np = delta.cpu().numpy() # 使用顏色映射來顯示密度 scatter1 = ax1.scatter(rho_np, delta_np, c=gamma.cpu().numpy(), s=8, alpha=0.7, cmap='viridis') ax1.set_xlabel('Rho (Local Density)', fontsize=12) ax1.set_ylabel('Delta (Min Distance to Higher Density)', fontsize=12) ax1.set_title(f'Decision Graph - {os.path.basename(image_path)}\n(Superpixels: {len(rho_np)})', fontsize=14) ax1.grid(True, alpha=0.3) # 添加顏色條 cbar1 = plt.colorbar(scatter1, ax=ax1) cbar1.set_label('Gamma (Rho × Delta)', fontsize=10) # Gamma vs n plot - with data validation for log scale gamma_np = gamma.cpu().numpy() n_np = n.cpu().numpy() # Filter out non-positive values for log scale positive_mask = gamma_np > 0 if positive_mask.sum() > 0: scatter2 = ax2.scatter(n_np[positive_mask], gamma_np[positive_mask], c=rho_np[positive_mask], s=8, alpha=0.7, cmap='plasma') ax2.set_yscale('log') # 添加顏色條 cbar2 = plt.colorbar(scatter2, ax=ax2) cbar2.set_label('Rho (Local Density)', fontsize=10) else: # Fallback to linear scale if no positive values ax2.scatter(n_np, gamma_np, s=8, alpha=0.7, color='blue') print("⚠️ Warning: No positive gamma values found, using linear scale instead of log scale") ax2.set_xlabel('N (Index in descending order of Gamma)', fontsize=12) ax2.set_ylabel('Gamma (Rho × Delta)', fontsize=12) ax2.set_title('Gamma vs N Plot\n(Cluster Center Selection)', fontsize=14) ax2.grid(True, alpha=0.3) # Apply tight_layout with error handling try: plt.tight_layout() except Exception as e: print(f"Warning: tight_layout failed ({e}), using default layout") # Use manual spacing as fallback plt.subplots_adjust(left=0.1, right=0.95, top=0.9, bottom=0.1, wspace=0.3) file = Process_File() file.JudgeRoot_MakeDir(Save_Root) # 使用原始檔名而不是索引編號 original_filename = os.path.basename(image_path) path = file.Make_Save_Root(original_filename, Save_Root) plt.savefig(path, dpi=300, bbox_inches='tight') plt.close() print(f"Decision graph and gamma vs n plot saved to: {path}") # Identify potential cluster centers (high rho and high delta) mean_rho = rho.mean() std_rho = rho.std() threshold_rho = mean_rho + threshold_factor * std_rho mean_delta = delta.mean() std_delta = delta.std() threshold_delta = mean_delta + threshold_factor * std_delta is_center = (rho > threshold_rho) & (delta > threshold_delta) # Properly handle torch.nonzero result to avoid issues with empty tensors center_nonzero = torch.nonzero(is_center) if center_nonzero.numel() > 0: center_indices = center_nonzero.squeeze().cpu().numpy() # Ensure center_indices is always a 1D array, even for single element if center_indices.ndim == 0: center_indices = np.array([center_indices.item()]) else: center_indices = np.array([]) # 識別潛在的聚類中心(超像素) center_points = superpixel_features[center_indices] if len(center_indices) > 0 else np.array([]) print(f"🎯 發現潛在聚類中心: {len(center_indices)} 個超像素") for idx in center_indices: print(f" 中心超像素 {idx}: RGB({superpixel_features[idx][0]:.3f}, {superpixel_features[idx][1]:.3f}, {superpixel_features[idx][2]:.3f})") # ========== Fuzzy C-means 聚類分析 ========== print(f"\n🔄 開始 Fuzzy C-means 聚類分析...") # 確定最佳聚類數 gamma_np = gamma.cpu().numpy() optimal_k, cluster_scores = determine_optimal_clusters( superpixel_features, gamma_np, max_clusters=8, min_clusters=2 ) # 執行 Fuzzy C-means 聚類 print(f"\n🎯 使用最佳聚類數 {optimal_k} 進行 Fuzzy C-means 聚類...") cluster_centers, membership_matrix, cluster_labels, objective_value, n_iterations = fuzzy_c_means( superpixel_features, optimal_k, m=2.0, max_iter=100, random_state=42 ) # 計算聚類統計信息 cluster_stats = {} for cluster_id in range(optimal_k): cluster_mask = cluster_labels == cluster_id cluster_size = np.sum(cluster_mask) avg_membership = np.mean(membership_matrix[cluster_mask, cluster_id]) cluster_stats[cluster_id] = { 'size': cluster_size, 'avg_membership': avg_membership, 'center': cluster_centers[cluster_id] } print(f" 聚類 {cluster_id}: {cluster_size} 個超像素, 平均隸屬度: {avg_membership:.3f}") # 生成聚類結果可視化 print(f"\n📊 生成聚類結果可視化...") # 將圖像數組轉換回0-255範圍用於可視化 img_array_255 = (img_array * 255).astype(np.uint8) # 創建可視化保存路徑 original_filename = os.path.basename(image_path) clustering_viz_path = os.path.join(Save_Root, f"clustering_results_{original_filename}") # 生成可視化 visualize_clustering_results( img_array_255, segments, cluster_labels, cluster_centers, membership_matrix, clustering_viz_path ) # Prepare return dictionary (包含所有信息:密度峰值分析 + 模糊聚類結果) result = { # 原有的密度峰值分析結果 'center_indices': center_indices, 'center_points': center_points, 'rho': rho.cpu().numpy(), 'delta': delta.cpu().numpy(), 'gamma': gamma.cpu().numpy(), 'n': n.cpu().numpy(), 'segments': segments, 'superpixel_features': superpixel_features, 'superpixel_centroids': superpixel_centroids, 'n_superpixels': len(superpixel_features), 'compression_ratio': len(superpixel_features) / image_size, # 新增的 Fuzzy C-means 聚類結果 'optimal_clusters': optimal_k, 'cluster_centers': cluster_centers, 'membership_matrix': membership_matrix, 'cluster_labels': cluster_labels, 'cluster_stats': cluster_stats, 'clustering_objective': objective_value, 'clustering_iterations': n_iterations, 'cluster_scores': cluster_scores, 'clustering_viz_path': clustering_viz_path } return result # Example usage: if __name__ == "__main__": Label_Length = len(Loading_Config["Training_Labels"]) Merge = merge() Prepare = Load_Data_Prepare() load = Loding_Data_Root(Loading_Config["Training_Labels"], Loading_Config["Train_Data_Root"], Loading_Config["ImageGenerator_Data_Root"]) Data_Dict_Data = load.process_main(False) Total_Size_List = [] for label in Loading_Config["Training_Labels"]: Total_Size_List.append(len(Data_Dict_Data[label])) # 做出跟資料相同數量的Label Classes = [] i = 0 for encording in Loading_Config["Training_Labels"]: Classes.append(make_label_list(Total_Size_List[i], encording)) i += 1 # 將資料做成Dict的資料型態 Prepare.Set_Final_Dict_Data(Loading_Config["Training_Labels"], Data_Dict_Data, Classes, Label_Length) Final_Dict_Data = Prepare.Get_Final_Data_Dict() keys = list(Final_Dict_Data.keys()) Training_Data = Merge.merge_all_image_data(Final_Dict_Data[keys[0]], Final_Dict_Data[keys[1]]) # 將訓練資料合併成一個list for i in range(2, Label_Length): Training_Data = Merge.merge_all_image_data(Training_Data, Final_Dict_Data[keys[i]]) # 將訓練資料合併成一個list Training_Label = Merge.merge_all_image_data(Final_Dict_Data[keys[Label_Length]], Final_Dict_Data[keys[Label_Length + 1]]) #將訓練資料的label合併成一個label的list for i in range(Label_Length + 2, 2 * Label_Length): Training_Label = Merge.merge_all_image_data(Training_Label, Final_Dict_Data[keys[i]]) # 將訓練資料合併成一個list for i in range(len(Training_Data)): print(f"\n{'='*60}") print(f"🖼️ 處理圖像 {i+1}/{len(Training_Data)}: {Training_Data[i]}") # 所有圖片都使用 Superpixel 分割進行 Density Peak 分析 print("🎯 使用 SLIC 超像素分割進行 Density Peak 分析") try: result_superpixels = compute_decision_graph( Training_Data[i], f'{Save_Result_File_Config["Density_Peak_Save_Root"]}/{Training_Label[i]}_superpixels', use_superpixels=True, save_regions=True, max_regions=50 ) # 獲取圖片信息用於統計 test_image = Image.open(Training_Data[i]) image_size = test_image.size[0] * test_image.size[1] print(f"\n✅ 超像素處理成功:") print(f"📊 超像素數量: {len(result_superpixels['rho'])} 個數據點") print(f"📈 壓縮比例: {len(result_superpixels['rho']) / image_size:.6f}") print(f"🔄 壓縮倍數: {image_size / len(result_superpixels['rho']):.1f}x") print(f"🎯 Decision-graph 已生成並保存") # 顯示 Fuzzy C-means 聚類結果 print(f"\n🎯 Fuzzy C-means 聚類結果:") print(f"📊 最佳聚類數: {result_superpixels['optimal_clusters']}") print(f"🔄 聚類迭代次數: {result_superpixels['clustering_iterations']}") print(f"📈 目標函數值: {result_superpixels['clustering_objective']:.4f}") # 顯示各聚類的詳細信息 print(f"📋 各聚類詳細信息:") for cluster_id, stats in result_superpixels['cluster_stats'].items(): print(f" 聚類 {cluster_id}: {stats['size']} 個超像素 (平均隸屬度: {stats['avg_membership']:.3f})") center = stats['center'] print(f" 中心特徵: RGB({center[0]:.3f}, {center[1]:.3f}, {center[2]:.3f}), 位置({center[3]:.3f}, {center[4]:.3f})") print(f"📊 聚類可視化已保存至: {result_superpixels['clustering_viz_path']}") # 顯示聚類品質評估 if 'cluster_scores' in result_superpixels and result_superpixels['optimal_clusters'] in result_superpixels['cluster_scores']: scores = result_superpixels['cluster_scores'][result_superpixels['optimal_clusters']] print(f"📈 聚類品質評估:") print(f" 分割係數 (PC): {scores['pc']:.3f}") print(f" 分割熵 (PE): {scores['pe']:.3f}") print(f" 修正分割係數 (MPC): {scores['mpc']:.3f}") print(f" 綜合分數: {scores['combined_score']:.3f}") except Exception as e: print(f"❌ 超像素處理失敗: {e}") continue print(f"\n💾 結果保存至: {Save_Result_File_Config['Density_Peak_Save_Root']}")