Spaces:
Sleeping
Sleeping
| import numpy as np | |
| import cv2 | |
| from typing import Dict, Any, Optional | |
| class LightingAnalyzer: | |
| """ | |
| 分析圖像的光照條件,提供增強的室內or室外判斷和光照類型分類,並專注於光照分析。 | |
| """ | |
| def __init__(self, config: Optional[Dict[str, Any]] = None): | |
| """ | |
| 初始化光照分析器。 | |
| Args: | |
| config: 可選的配置字典,用於自定義分析參數 | |
| """ | |
| self.config = config or self._get_default_config() | |
| def analyze(self, image): | |
| """ | |
| 分析圖像的光照條件。 | |
| 主要分析入口點,計算基本特徵,判斷室內/室外,確定光照條件。 | |
| Args: | |
| image: 輸入圖像 (numpy array 或 PIL Image) | |
| Returns: | |
| Dict: 包含光照分析結果的字典 | |
| """ | |
| try: | |
| # 轉換圖像格式 | |
| if not isinstance(image, np.ndarray): | |
| image_np = np.array(image) | |
| else: | |
| image_np = image.copy() | |
| # 確保 RGB 格式 | |
| if image_np.shape[2] == 3 and isinstance(image_np, np.ndarray): | |
| image_rgb = cv2.cvtColor(image_np, cv2.COLOR_BGR2RGB) | |
| else: | |
| image_rgb = image_np | |
| # 計算基本特徵 | |
| features = self._compute_basic_features(image_rgb) | |
| # 分析室內or室外 | |
| indoor_result = self._analyze_indoor_outdoor(features) | |
| is_indoor = indoor_result["is_indoor"] | |
| indoor_probability = indoor_result["indoor_probability"] | |
| # 確定光照條件 | |
| lighting_conditions = self._determine_lighting_conditions(features, is_indoor) | |
| # 整合結果 | |
| result = { | |
| "time_of_day": lighting_conditions["time_of_day"], | |
| "confidence": float(lighting_conditions["confidence"]), | |
| "is_indoor": is_indoor, | |
| "indoor_probability": float(indoor_probability), | |
| "brightness": { | |
| "average": float(features["avg_brightness"]), | |
| "std_dev": float(features["brightness_std"]), | |
| "dark_ratio": float(features["dark_pixel_ratio"]) | |
| }, | |
| "color_info": { | |
| "blue_ratio": float(features["blue_ratio"]), | |
| "yellow_orange_ratio": float(features["yellow_orange_ratio"]), | |
| "gray_ratio": float(features["gray_ratio"]), | |
| "avg_saturation": float(features["avg_saturation"]), | |
| "sky_brightness": float(features["sky_brightness"]), | |
| "color_atmosphere": features["color_atmosphere"], | |
| "warm_ratio": float(features["warm_ratio"]), | |
| "cool_ratio": float(features["cool_ratio"]) | |
| } | |
| } | |
| # 添加診斷信息 | |
| if self.config["include_diagnostics"]: | |
| result["diagnostics"] = { | |
| "feature_contributions": indoor_result.get("feature_contributions", {}), | |
| "lighting_diagnostics": lighting_conditions.get("diagnostics", {}) | |
| } | |
| return result | |
| except Exception as e: | |
| print(f"Error in lighting analysis: {str(e)}") | |
| import traceback | |
| traceback.print_exc() | |
| return { | |
| "time_of_day": "unknown", | |
| "confidence": 0, | |
| "error": str(e) | |
| } | |
| def _compute_basic_features(self, image_rgb): | |
| """ | |
| 計算圖像的基本光照特徵(徹底優化版本)。 | |
| Args: | |
| image_rgb: RGB 格式的圖像 (numpy array) | |
| Returns: | |
| Dict: 包含計算出的特徵值 | |
| """ | |
| # 獲取圖像尺寸 | |
| height, width = image_rgb.shape[:2] | |
| # 根據圖像大小自適應縮放因子 | |
| base_scale = 4 | |
| scale_factor = base_scale + min(8, max(0, int((height * width) / (1000 * 1000)))) | |
| # 創建縮小的圖像以加速處理 | |
| small_rgb = cv2.resize(image_rgb, (width//scale_factor, height//scale_factor)) | |
| # 一次性轉換所有顏色空間,避免重複計算 | |
| hsv_img = cv2.cvtColor(image_rgb, cv2.COLOR_RGB2HSV) | |
| gray_img = cv2.cvtColor(image_rgb, cv2.COLOR_RGB2GRAY) | |
| small_gray = cv2.resize(gray_img, (width//scale_factor, height//scale_factor)) | |
| # 分離HSV通道 | |
| h_channel = hsv_img[:,:,0] | |
| s_channel = hsv_img[:,:,1] | |
| v_channel = hsv_img[:,:,2] | |
| # 基本亮度特徵 | |
| avg_brightness = np.mean(v_channel) | |
| brightness_std = np.std(v_channel) | |
| dark_pixel_ratio = np.sum(v_channel < 50) / (height * width) | |
| # 顏色特徵 | |
| yellow_orange_mask = ((h_channel >= 15) & (h_channel <= 40)) | |
| yellow_orange_ratio = np.sum(yellow_orange_mask) / (height * width) | |
| blue_mask = ((h_channel >= 90) & (h_channel <= 130)) | |
| blue_ratio = np.sum(blue_mask) / (height * width) | |
| # 特別檢查圖像上部區域,尋找藍天特徵 | |
| upper_region_h = h_channel[:height//4, :] | |
| upper_region_s = s_channel[:height//4, :] | |
| upper_region_v = v_channel[:height//4, :] | |
| # 藍天通常具有高飽和度的藍色 | |
| sky_blue_mask = ((upper_region_h >= 90) & (upper_region_h <= 130) & | |
| (upper_region_s > 70) & (upper_region_v > 150)) | |
| sky_blue_ratio = np.sum(sky_blue_mask) / max(1, upper_region_h.size) | |
| gray_mask = (s_channel < 50) & (v_channel > 100) | |
| gray_ratio = np.sum(gray_mask) / (height * width) | |
| avg_saturation = np.mean(s_channel) | |
| # 天空亮度 | |
| upper_half = v_channel[:height//2, :] | |
| sky_brightness = np.mean(upper_half) | |
| # 色調分析 | |
| warm_colors = ((h_channel >= 0) & (h_channel <= 60)) | (h_channel >= 300) | |
| warm_ratio = np.sum(warm_colors) / (height * width) | |
| cool_colors = (h_channel >= 180) & (h_channel <= 270) | |
| cool_ratio = np.sum(cool_colors) / (height * width) | |
| # 確定色彩氛圍 | |
| if warm_ratio > 0.4: | |
| color_atmosphere = "warm" | |
| elif cool_ratio > 0.4: | |
| color_atmosphere = "cool" | |
| else: | |
| color_atmosphere = "neutral" | |
| # 只在縮小的圖像上計算梯度,大幅提高效能 | |
| gx = cv2.Sobel(small_gray, cv2.CV_32F, 1, 0, ksize=3) | |
| gy = cv2.Sobel(small_gray, cv2.CV_32F, 0, 1, ksize=3) | |
| vertical_strength = np.mean(np.abs(gy)) | |
| horizontal_strength = np.mean(np.abs(gx)) | |
| gradient_ratio = vertical_strength / max(horizontal_strength, 1e-5) | |
| # 亮度的均勻性(分布) | |
| brightness_uniformity = 1 - min(1, brightness_std / max(avg_brightness, 1e-5)) | |
| # -- 高效的天花板分析 -- | |
| # 使用更大的下採樣率分析頂部區域 | |
| top_scale = scale_factor * 2 # 更積極的下採樣 | |
| top_region = v_channel[:height//4:top_scale, ::top_scale] | |
| top_region_std = np.std(top_region) | |
| ceiling_uniformity = 1.0 - min(1, top_region_std / max(np.mean(top_region), 1e-5)) | |
| # 使用更簡單的方法檢測上部水平線 | |
| top_gradients = np.abs(gy[:small_gray.shape[0]//4, :]) | |
| horizontal_lines_strength = np.mean(top_gradients) | |
| # 標準化 | |
| horizontal_line_ratio = min(1, horizontal_lines_strength / 40) | |
| # 極簡的亮點檢測 | |
| sampled_v = v_channel[::scale_factor*2, ::scale_factor*2] | |
| light_threshold = min(220, avg_brightness + 2*brightness_std) | |
| is_bright = sampled_v > light_threshold | |
| bright_spot_count = np.sum(is_bright) | |
| # 圓形光源分析的簡化替代方法 | |
| circular_light_score = 0 | |
| indoor_light_score = 0 | |
| light_distribution_uniformity = 0.5 | |
| # 只有當檢測到亮點,且不是大量亮點時(可能是室外光反射)才進行光源分析 | |
| if 1 < bright_spot_count < 20: | |
| # 簡單統計亮點分布 | |
| bright_y, bright_x = np.where(is_bright) | |
| if len(bright_y) > 1: | |
| # 檢查亮點是否成組出現 - 室內照明常見模式 | |
| mean_x = np.mean(bright_x) | |
| mean_y = np.mean(bright_y) | |
| dist_from_center = np.sqrt((bright_x - mean_x)**2 + (bright_y - mean_y)**2) | |
| # 如果亮點分布較集中,可能是燈具 | |
| if np.std(dist_from_center) < np.mean(dist_from_center): | |
| circular_light_score = min(3, len(bright_y) // 2) | |
| light_distribution_uniformity = 0.7 | |
| # 評估亮點是否位於上部區域,常見於室內頂燈 | |
| if np.mean(bright_y) < sampled_v.shape[0] / 2: | |
| indoor_light_score = 0.6 | |
| else: | |
| indoor_light_score = 0.3 | |
| # 使用邊緣區域梯度來快速估計邊界 | |
| edge_scale = scale_factor * 2 | |
| # 只採樣圖像邊緣部分進行分析 | |
| left_edge = small_gray[:, :small_gray.shape[1]//6] | |
| right_edge = small_gray[:, 5*small_gray.shape[1]//6:] | |
| top_edge = small_gray[:small_gray.shape[0]//6, :] | |
| # 計算每個邊緣區域的梯度強度 | |
| left_gradient = np.mean(np.abs(cv2.Sobel(left_edge, cv2.CV_32F, 1, 0, ksize=3))) | |
| right_gradient = np.mean(np.abs(cv2.Sobel(right_edge, cv2.CV_32F, 1, 0, ksize=3))) | |
| top_gradient = np.mean(np.abs(cv2.Sobel(top_edge, cv2.CV_32F, 0, 1, ksize=3))) | |
| # 標準化 | |
| left_edge_density = min(1, left_gradient / 50) | |
| right_edge_density = min(1, right_gradient / 50) | |
| top_edge_density = min(1, top_gradient / 50) | |
| # 封閉環境通常在圖像邊緣有較強的梯度 | |
| boundary_edge_score = (left_edge_density + right_edge_density + top_edge_density) / 3 | |
| # 簡單估計整體邊緣密度 | |
| edges_density = min(1, (np.mean(np.abs(gx)) + np.mean(np.abs(gy))) / 100) | |
| street_line_score = 0 | |
| # 檢查下半部分是否有強烈的垂直線條 | |
| bottom_half = small_gray[small_gray.shape[0]//2:, :] | |
| bottom_vert_gradient = cv2.Sobel(bottom_half, cv2.CV_32F, 0, 1, ksize=3) | |
| strong_vert_lines = np.abs(bottom_vert_gradient) > 50 | |
| if np.sum(strong_vert_lines) > (bottom_half.size * 0.05): # 如果超過5%的像素是強垂直線 | |
| street_line_score = 0.7 | |
| # 整合所有特徵 | |
| features = { | |
| # 基本亮度和顏色特徵 | |
| "avg_brightness": avg_brightness, | |
| "brightness_std": brightness_std, | |
| "dark_pixel_ratio": dark_pixel_ratio, | |
| "yellow_orange_ratio": yellow_orange_ratio, | |
| "blue_ratio": blue_ratio, | |
| "sky_blue_ratio": sky_blue_ratio, | |
| "gray_ratio": gray_ratio, | |
| "avg_saturation": avg_saturation, | |
| "sky_brightness": sky_brightness, | |
| "color_atmosphere": color_atmosphere, | |
| "warm_ratio": warm_ratio, | |
| "cool_ratio": cool_ratio, | |
| # 結構特徵 | |
| "gradient_ratio": gradient_ratio, | |
| "brightness_uniformity": brightness_uniformity, | |
| "bright_spot_count": bright_spot_count, | |
| "vertical_strength": vertical_strength, | |
| "horizontal_strength": horizontal_strength, | |
| # 室內/室外判斷特徵 | |
| "ceiling_uniformity": ceiling_uniformity, | |
| "horizontal_line_ratio": horizontal_line_ratio, | |
| "indoor_light_score": indoor_light_score, | |
| "circular_light_count": circular_light_score, | |
| "light_distribution_uniformity": light_distribution_uniformity, | |
| "boundary_edge_score": boundary_edge_score, | |
| "top_region_std": top_region_std, | |
| "edges_density": edges_density, | |
| # 室外特定特徵 | |
| "street_line_score": street_line_score | |
| } | |
| return features | |
| def _analyze_indoor_outdoor(self, features): | |
| """ | |
| 使用多特徵融合進行室內/室外判斷 | |
| Args: | |
| features: 特徵字典 | |
| Returns: | |
| Dict: 室內/室外判斷結果 | |
| """ | |
| # 獲取配置中的特徵權重 | |
| weights = self.config["indoor_outdoor_weights"] | |
| # 初始概率值 - 開始時中性評估 | |
| indoor_score = 0 | |
| feature_contributions = {} | |
| diagnostics = {} | |
| # 1. 藍色區域(天空)特徵 - 藍色區域多通常表示室外 | |
| if features.get("blue_ratio", 0) > 0.2: | |
| # 檢查是否有室內指標,如果有明顯的室內特徵,則減少藍色的負面影響 | |
| if (features.get("ceiling_uniformity", 0) > 0.5 or | |
| features.get("boundary_edge_score", 0) > 0.3 or | |
| features.get("indoor_light_score", 0) > 0.2 or | |
| features.get("bright_spot_count", 0) > 0): | |
| blue_score = -weights["blue_ratio"] * features["blue_ratio"] * 8 | |
| else: | |
| blue_score = -weights["blue_ratio"] * features["blue_ratio"] * 15 | |
| else: | |
| blue_score = -weights["blue_ratio"] * features["blue_ratio"] * 15 | |
| indoor_score += blue_score | |
| feature_contributions["blue_ratio"] = blue_score | |
| # 判斷視角 - 如果上部有藍天而上下亮度差異大,可能是仰視室外建築 | |
| if (features.get("sky_blue_ratio", 0) > 0.01 and | |
| features["sky_brightness"] > features["avg_brightness"] * 1.1): | |
| viewpoint_outdoor_score = -1.8 # 強烈的室外指標 | |
| indoor_score += viewpoint_outdoor_score | |
| feature_contributions["outdoor_viewpoint"] = viewpoint_outdoor_score | |
| # 2. 亮度均勻性特徵 - 室內通常光照更均勻 | |
| uniformity_score = weights["brightness_uniformity"] * features["brightness_uniformity"] | |
| indoor_score += uniformity_score | |
| feature_contributions["brightness_uniformity"] = uniformity_score | |
| # 3. 天花板特徵 - 強化天花板檢測的權重 | |
| ceiling_contribution = 0 | |
| if "ceiling_uniformity" in features: | |
| ceiling_uniformity = features["ceiling_uniformity"] | |
| horizontal_line_ratio = features.get("horizontal_line_ratio", 0) | |
| # 增強天花板檢測的影響 | |
| if ceiling_uniformity > 0.5: | |
| ceiling_weight = 3 | |
| ceiling_contribution = weights.get("ceiling_features", 1.5) * ceiling_weight | |
| if horizontal_line_ratio > 0.2: # 如果有水平線條,進一步增強 | |
| ceiling_contribution *= 1.5 | |
| elif ceiling_uniformity > 0.4: | |
| ceiling_contribution = weights.get("ceiling_features", 1.5) * 1.2 | |
| indoor_score += ceiling_contribution | |
| feature_contributions["ceiling_features"] = ceiling_contribution | |
| # 4. 強化吊燈的檢測 | |
| light_contribution = 0 | |
| if "indoor_light_score" in features: | |
| indoor_light_score = features["indoor_light_score"] | |
| circular_light_count = features.get("circular_light_count", 0) | |
| # 加強對特定類型光源的檢測 | |
| if circular_light_count >= 1: # 即便只有一個圓形光源也很可能是室內 | |
| light_contribution = weights.get("light_features", 1.2) * 2 | |
| elif indoor_light_score > 0.3: | |
| light_contribution = weights.get("light_features", 1.2) * 1 | |
| indoor_score += light_contribution | |
| feature_contributions["light_features"] = light_contribution | |
| # 5. 環境封閉度特徵 | |
| boundary_contribution = 0 | |
| if "boundary_edge_score" in features: | |
| boundary_edge_score = features["boundary_edge_score"] | |
| edges_density = features.get("edges_density", 0) | |
| # 高邊界評分暗示封閉環境(室內) | |
| if boundary_edge_score > 0.3: | |
| boundary_contribution = weights.get("boundary_features", 1.2) * 2 | |
| elif boundary_edge_score > 0.2: | |
| boundary_contribution = weights.get("boundary_features", 1.2) * 1.2 | |
| indoor_score += boundary_contribution | |
| feature_contributions["boundary_features"] = boundary_contribution | |
| if (features.get("edges_density", 0) > 0.2 and | |
| features.get("bright_spot_count", 0) > 5 and | |
| features.get("vertical_strength", 0) > features.get("horizontal_strength", 0) * 1.5): | |
| # 商業街道特徵:高邊緣密度 + 多亮點 + 強垂直特徵 | |
| street_feature_score = -weights.get("street_features", 1.2) * 1.5 | |
| indoor_score += street_feature_score | |
| feature_contributions["street_features"] = street_feature_score | |
| # 添加對亞洲商業街道的專門檢測 | |
| if (features.get("edges_density", 0) > 0.25 and # 高邊緣密度 | |
| features.get("vertical_strength", 0) > features.get("horizontal_strength", 0) * 1.8 and # 更強的垂直結構 | |
| features.get("brightness_uniformity", 0) < 0.6): # 較低的亮度均勻性(招牌、燈光等造成) | |
| asian_street_score = -2.2 # 非常強的室外代表性特徵 | |
| indoor_score += asian_street_score | |
| feature_contributions["asian_commercial_street"] = asian_street_score | |
| # 6. 垂直/水平梯度比率 | |
| gradient_contribution = 0 | |
| if features["gradient_ratio"] > 2: | |
| combined_uniformity = (features["brightness_uniformity"] + | |
| features.get("ceiling_uniformity", 0)) / 2 | |
| if combined_uniformity > 0.5: | |
| gradient_contribution = weights["gradient_ratio"] * 0.7 | |
| else: | |
| gradient_contribution = -weights["gradient_ratio"] * 0.3 | |
| indoor_score += gradient_contribution | |
| feature_contributions["gradient_ratio"] = gradient_contribution | |
| # 7. 亮點檢測(光源) | |
| bright_spot_contribution = 0 | |
| bright_spot_count = features["bright_spot_count"] | |
| circular_light_count = features.get("circular_light_count", 0) | |
| # 調整亮點分析邏輯 | |
| if circular_light_count >= 1: # 即使只有一個圓形光源 | |
| bright_spot_contribution = weights["bright_spots"] * 1.5 | |
| elif bright_spot_count < 5: # 適當放寬閾值 | |
| bright_spot_contribution = weights["bright_spots"] * 0.5 | |
| elif bright_spot_count > 15: # 大量亮點比較有可能為室外 | |
| bright_spot_contribution = -weights["bright_spots"] * 0.4 | |
| indoor_score += bright_spot_contribution | |
| feature_contributions["bright_spots"] = bright_spot_contribution | |
| # 8. 色調分析 | |
| yellow_contribution = 0 | |
| if features["avg_brightness"] < 150 and features["yellow_orange_ratio"] > 0.15: | |
| if features.get("indoor_light_score", 0) > 0.2: | |
| yellow_contribution = weights["color_tone"] * 0.8 | |
| else: | |
| yellow_contribution = weights["color_tone"] * 0.5 | |
| indoor_score += yellow_contribution | |
| feature_contributions["yellow_tone"] = yellow_contribution | |
| if features.get("blue_ratio", 0) > 0.7: | |
| # 檢查是否有室內指標,如果有明顯的室內特徵,則減少藍色的負面影響 | |
| if (features.get("ceiling_uniformity", 0) > 0.6 or | |
| features.get("boundary_edge_score", 0) > 0.3 or | |
| features.get("indoor_light_score", 0) > 0): | |
| blue_score = -weights["blue_ratio"] * features["blue_ratio"] * 10 | |
| else: | |
| blue_score = -weights["blue_ratio"] * features["blue_ratio"] * 18 | |
| else: | |
| blue_score = -weights["blue_ratio"] * features["blue_ratio"] * 18 | |
| # 9. 上半部與下半部亮度對比 | |
| sky_contribution = 0 | |
| if features["sky_brightness"] > features["avg_brightness"] * 1.3: | |
| if features["blue_ratio"] > 0.15: | |
| sky_contribution = -weights["sky_brightness"] * 0.9 | |
| else: | |
| sky_contribution = -weights["sky_brightness"] * 0.6 | |
| indoor_score += sky_contribution | |
| feature_contributions["sky_brightness"] = sky_contribution | |
| # 加入餐廳特徵檢測邏輯 | |
| dining_feature_contribution = 0 | |
| # 檢測中央懸掛式燈具,有懸掛燈代表有天花板,就代表是室內 | |
| if circular_light_count >= 1 and features.get("light_distribution_uniformity", 0) > 0.4: | |
| dining_feature_contribution = 1.5 | |
| indoor_score += dining_feature_contribution | |
| feature_contributions["dining_features"] = dining_feature_contribution | |
| # 10. 增強的藍天的檢測,即便是小面積的藍天也是很強的室外指標 | |
| sky_contribution = 0 | |
| if "sky_blue_ratio" in features: | |
| # 只有當藍色區域集中在上部且亮度高時,才認為是藍天 | |
| if features["sky_blue_ratio"] > 0.01 and features["sky_brightness"] > features.get("avg_brightness", 0) * 1.2: | |
| sky_outdoor_score = -2.5 * features["sky_blue_ratio"] * weights.get("blue_ratio", 1.2) | |
| indoor_score += sky_outdoor_score | |
| feature_contributions["sky_blue_detection"] = sky_outdoor_score | |
| asian_street_indicators = 0 | |
| # 1: 高垂直結構強度 | |
| vertical_ratio = features.get("vertical_strength", 0) / max(features.get("horizontal_strength", 1e-5), 1e-5) | |
| if vertical_ratio > 1.8: | |
| asian_street_indicators += 1 | |
| # 2: 高邊緣密度 + 路面標記特徵 | |
| if features.get("edges_density", 0) > 0.25 and features.get("street_line_score", 0) > 0.2: | |
| asian_street_indicators += 2 | |
| # 3: 多個亮點 + 亮度不均勻 | |
| if features.get("bright_spot_count", 0) > 5 and features.get("brightness_uniformity", 0) < 0.6: | |
| asian_street_indicators += 1 | |
| # 4: 藍色區域小(天空被高樓遮擋)但亮度高 | |
| if features.get("blue_ratio", 0) < 0.1 and features.get("sky_brightness", 0) > features.get("avg_brightness", 0) * 1.1: | |
| asian_street_indicators += 1 | |
| # 如果滿足至少 3 個指標,調整權重變成偏向室外的判斷 | |
| if asian_street_indicators >= 3: | |
| # 記錄檢測到的模式 | |
| feature_contributions["asian_street_pattern"] = -2.5 | |
| indoor_score += -2.5 # 明顯向室外傾斜 | |
| # 降低室內指標的權重 | |
| if "boundary_features" in feature_contributions: | |
| adjusted_contribution = feature_contributions["boundary_features"] * 0.4 | |
| indoor_score -= (feature_contributions["boundary_features"] - adjusted_contribution) | |
| feature_contributions["boundary_features"] = adjusted_contribution | |
| if "ceiling_features" in feature_contributions: | |
| adjusted_contribution = feature_contributions["ceiling_features"] * 0.3 | |
| indoor_score -= (feature_contributions["ceiling_features"] - adjusted_contribution) | |
| feature_contributions["ceiling_features"] = adjusted_contribution | |
| # 添加信息到診斷數據 | |
| diagnostics["asian_street_detected"] = True | |
| diagnostics["asian_street_indicators"] = asian_street_indicators | |
| bedroom_indicators = 0 | |
| # 1: 窗戶和牆壁形成的直角 | |
| if features.get("brightness_uniformity", 0) > 0.6 and features.get("boundary_edge_score", 0) > 0.3: | |
| bedroom_indicators += 1.5 # 增加權重 | |
| # 2: 天花板和光源 | |
| if features.get("ceiling_uniformity", 0) > 0.5 and features.get("bright_spot_count", 0) > 0: | |
| bedroom_indicators += 2.5 | |
| # 3: 良好對比度的牆壁顏色,適合臥房還有客廳 | |
| if features.get("brightness_uniformity", 0) > 0.6 and features.get("avg_saturation", 0) < 100: | |
| bedroom_indicators += 1.5 | |
| # 特殊的檢測 4: 檢測窗戶 | |
| if features.get("boundary_edge_score", 0) > 0.25 and features.get("brightness_std", 0) > 40: | |
| bedroom_indicators += 1.5 | |
| # 如果滿足足夠的家居指標,提高多點室內判斷分數 | |
| if bedroom_indicators >= 3: | |
| # 增加家居環境評分 | |
| home_env_score = 3 | |
| indoor_score += home_env_score | |
| feature_contributions["home_environment_pattern"] = home_env_score | |
| elif bedroom_indicators >= 2: | |
| # 適度增加家居環境評分 | |
| home_env_score = 2 | |
| indoor_score += home_env_score | |
| feature_contributions["home_environment_pattern"] = home_env_score | |
| # 根據總分轉換為概率(使用sigmoid函數) | |
| indoor_probability = 1 / (1 + np.exp(-indoor_score * 0.22)) | |
| # 判斷結果 | |
| is_indoor = indoor_probability > 0.5 | |
| return { | |
| "is_indoor": is_indoor, | |
| "indoor_probability": indoor_probability, | |
| "indoor_score": indoor_score, | |
| "feature_contributions": feature_contributions, | |
| "diagnostics": diagnostics | |
| } | |
| def _determine_lighting_conditions(self, features, is_indoor): | |
| """ | |
| 基於特徵和室內/室外判斷確定光照條件。 | |
| Args: | |
| features: 特徵字典 | |
| is_indoor: 是否是室內環境 | |
| Returns: | |
| Dict: 光照條件分析結果 | |
| """ | |
| # 初始化 | |
| time_of_day = "unknown" | |
| confidence = 0.5 | |
| diagnostics = {} | |
| avg_brightness = features["avg_brightness"] | |
| dark_pixel_ratio = features["dark_pixel_ratio"] | |
| yellow_orange_ratio = features["yellow_orange_ratio"] | |
| blue_ratio = features["blue_ratio"] | |
| gray_ratio = features["gray_ratio"] | |
| # 基於室內/室外分別判斷 | |
| if is_indoor: | |
| # 計算室內住宅自然光指標 | |
| natural_window_light = 0 | |
| # 檢查窗戶特徵和光線特性 | |
| if (features.get("blue_ratio", 0) > 0.1 and | |
| features.get("sky_brightness", 0) > avg_brightness * 1.1): | |
| natural_window_light += 1 | |
| # 檢查均勻柔和的光線分布 | |
| if (features.get("brightness_uniformity", 0) > 0.65 and | |
| features.get("brightness_std", 0) < 70): | |
| natural_window_light += 1 | |
| # 檢查暖色調比例 | |
| if features.get("warm_ratio", 0) > 0.2: | |
| natural_window_light += 1 | |
| # 家居環境指標 | |
| home_env_score = features.get("home_environment_pattern", 0) | |
| if home_env_score > 1.5: | |
| natural_window_light += 1 | |
| # 1. 室內明亮環境,可能有窗戶自然光 | |
| if avg_brightness > 130: | |
| # 檢測自然光住宅空間 - 新增類型! | |
| if natural_window_light >= 2 and home_env_score > 1.5: | |
| time_of_day = "indoor_residential_natural" # 家裡的自然光類型 | |
| confidence = 0.8 | |
| diagnostics["reason"] = "Bright residential space with natural window lighting" | |
| # 檢查窗戶特徵 - 如果有明亮的窗戶且色調為藍 | |
| elif features.get("blue_ratio", 0) > 0.1 and features.get("sky_brightness", 0) > 150: | |
| time_of_day = "indoor_bright" | |
| confidence = 0.8 | |
| diagnostics["reason"] = "Bright indoor scene with window light" | |
| else: | |
| time_of_day = "indoor_bright" | |
| confidence = 0.75 | |
| diagnostics["reason"] = "High brightness in indoor environment" | |
| # 2. 室內中等亮度環境 | |
| elif avg_brightness > 100: | |
| time_of_day = "indoor_moderate" | |
| confidence = 0.7 | |
| diagnostics["reason"] = "Moderate brightness in indoor environment" | |
| # 3. 室內低光照環境 | |
| else: | |
| time_of_day = "indoor_dim" | |
| confidence = 0.65 + dark_pixel_ratio / 3 | |
| diagnostics["reason"] = "Low brightness in indoor environment" | |
| # 1. 檢測設計師風格住宅,可以偵測到比較多種類的狀況 | |
| designer_residential_score = 0 | |
| # 檢測特色燈具 | |
| if (features.get("circular_light_count", 0) > 0 or features.get("bright_spot_count", 0) > 2): | |
| designer_residential_score += 1 | |
| # 檢測高品質均勻照明 | |
| if features.get("brightness_uniformity", 0) > 0.7: | |
| designer_residential_score += 1 | |
| # 檢測溫暖色調 | |
| if features.get("warm_ratio", 0) > 0.3: | |
| designer_residential_score += 1 | |
| # 檢測家居環境特徵 | |
| if home_env_score > 1.5: | |
| designer_residential_score += 1 | |
| if designer_residential_score >= 3 and home_env_score > 1.5: | |
| time_of_day = "indoor_designer_residential" | |
| confidence = 0.85 | |
| diagnostics["special_case"] = "Designer residential lighting with decorative elements" | |
| # 2. 檢測餐廳/酒吧場景 | |
| elif avg_brightness < 150 and yellow_orange_ratio > 0.2: | |
| if features["warm_ratio"] > 0.4: | |
| time_of_day = "indoor_restaurant" | |
| confidence = 0.65 + yellow_orange_ratio / 4 | |
| diagnostics["special_case"] = "Warm, yellow-orange lighting suggests restaurant/bar setting" | |
| # 3. 檢測商業照明空間 | |
| elif avg_brightness > 120 and features["bright_spot_count"] > 4: | |
| # 增加商業照明判別的精確度 | |
| commercial_score = 0 | |
| # 多個亮點 | |
| commercial_score += min(1.0, features["bright_spot_count"] * 0.05) | |
| # 不太可能是住宅的指標 | |
| if features.get("home_environment_pattern", 0) < 1.5: | |
| commercial_score += 0.5 | |
| # 整體照明結構化布局 | |
| if features.get("light_distribution_uniformity", 0) > 0.6: | |
| commercial_score += 0.5 | |
| if commercial_score > 0.6 and designer_residential_score < 3: | |
| time_of_day = "indoor_commercial" | |
| confidence = 0.7 + commercial_score / 5 | |
| diagnostics["special_case"] = "Multiple structured light sources suggest commercial lighting" | |
| else: | |
| # 室外場景判斷保持不變 | |
| if avg_brightness < 90: # 降低夜間判斷的亮度閾值 | |
| # 檢測是否有車燈/街燈 | |
| has_lights = features["bright_spot_count"] > 3 | |
| if has_lights: | |
| time_of_day = "night" | |
| confidence = 0.8 + dark_pixel_ratio / 5 | |
| diagnostics["reason"] = "Low brightness with light sources detected" | |
| # 檢查是否是霓虹燈場景 | |
| if yellow_orange_ratio > 0.15 and features["bright_spot_count"] > 5: | |
| time_of_day = "neon_night" | |
| confidence = 0.75 + yellow_orange_ratio / 3 | |
| diagnostics["special_case"] = "Multiple colorful light sources suggest neon lighting" | |
| else: | |
| time_of_day = "night" | |
| confidence = 0.7 + dark_pixel_ratio / 3 | |
| diagnostics["reason"] = "Low brightness outdoor scene" | |
| elif avg_brightness < 130 and yellow_orange_ratio > 0.2: | |
| time_of_day = "sunset/sunrise" | |
| confidence = 0.7 + yellow_orange_ratio / 3 | |
| diagnostics["reason"] = "Moderate brightness with yellow-orange tones" | |
| elif avg_brightness > 150 and blue_ratio > 0.15: | |
| time_of_day = "day_clear" | |
| confidence = 0.7 + blue_ratio / 3 | |
| diagnostics["reason"] = "High brightness with blue tones (likely sky)" | |
| elif avg_brightness > 130: | |
| time_of_day = "day_cloudy" | |
| confidence = 0.7 + gray_ratio / 3 | |
| diagnostics["reason"] = "Good brightness with higher gray tones" | |
| else: | |
| # 默認判斷 | |
| if yellow_orange_ratio > gray_ratio: | |
| time_of_day = "sunset/sunrise" | |
| confidence = 0.6 + yellow_orange_ratio / 3 | |
| diagnostics["reason"] = "Yellow-orange tones dominant" | |
| else: | |
| time_of_day = "day_cloudy" | |
| confidence = 0.6 + gray_ratio / 3 | |
| diagnostics["reason"] = "Gray tones dominant" | |
| # 檢查是否是特殊室外場景(如體育場) | |
| if avg_brightness > 120 and features["brightness_uniformity"] > 0.8: | |
| # 高亮度且非常均勻的光照可能是體育場燈光 | |
| time_of_day = "stadium_lighting" | |
| confidence = 0.7 | |
| diagnostics["special_case"] = "Uniform bright lighting suggests stadium/sports lighting" | |
| # 檢查是否是混合光照(如室內/室外過渡區) | |
| if 100 < avg_brightness < 150 and 0.1 < blue_ratio < 0.2: | |
| if features["gradient_ratio"] > 1.5: | |
| time_of_day = "mixed_lighting" | |
| confidence = 0.65 | |
| diagnostics["special_case"] = "Features suggest indoor-outdoor transition area" | |
| # 確保信心值在 0-1 範圍內 | |
| confidence = min(0.95, max(0.5, confidence)) | |
| if time_of_day in ["indoor_residential_natural", "indoor_designer_residential"] and hasattr(self, "config"): | |
| # 確保 LIGHTING_CONDITIONS 中有這些新類型的描述 | |
| if time_of_day == "indoor_residential_natural": | |
| lightingType = { | |
| "template_modifiers": { | |
| "indoor_residential_natural": "naturally-lit residential" | |
| }, | |
| "time_descriptions": { | |
| "indoor_residential_natural": { | |
| "general": "The scene is captured in a residential space with ample natural light from windows.", | |
| "bright": "The residential space is brightly lit with natural daylight streaming through windows.", | |
| "medium": "The home environment has good natural lighting providing a warm, inviting atmosphere.", | |
| "dim": "The living space has soft natural light filtering through windows or openings." | |
| } | |
| } | |
| } | |
| elif time_of_day == "indoor_designer_residential": | |
| lightingType = { | |
| "template_modifiers": { | |
| "indoor_designer_residential": "designer-lit residential" | |
| }, | |
| "time_descriptions": { | |
| "indoor_designer_residential": { | |
| "general": "The scene is captured in a residential space with carefully designed lighting elements.", | |
| "bright": "The home features professionally designed lighting with decorative fixtures creating a bright atmosphere.", | |
| "medium": "The residential interior showcases curated lighting design balancing form and function.", | |
| "dim": "The living space has thoughtfully placed designer lighting creating an intimate ambiance." | |
| } | |
| } | |
| } | |
| return { | |
| "time_of_day": time_of_day, | |
| "confidence": confidence, | |
| "diagnostics": diagnostics | |
| } | |
| def _get_default_config(self): | |
| """ | |
| 返回優化版本的默認配置參數。 | |
| """ | |
| return { | |
| "indoor_outdoor_weights": { | |
| "blue_ratio": 0.6, | |
| "brightness_uniformity": 1.2, | |
| "gradient_ratio": 0.7, | |
| "bright_spots": 0.8, | |
| "color_tone": 0.5, | |
| "sky_brightness": 0.9, | |
| "brightness_variation": 0.7, | |
| "ceiling_features": 1.5, | |
| "light_features": 1.1, | |
| "boundary_features": 2.8, | |
| "street_features": 2, | |
| "building_features": 1.6 | |
| }, | |
| "include_diagnostics": True | |
| } | |