Spaces:
Running
on
Zero
Running
on
Zero
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 | |
} | |