FatemehRahimi1 commited on
Commit
9f01bea
·
verified ·
1 Parent(s): 88d44d4

Upload 3 files

Browse files
Files changed (3) hide show
  1. README.md +4 -4
  2. app.py +184 -0
  3. requirements.txt +6 -0
README.md CHANGED
@@ -1,7 +1,7 @@
1
  ---
2
- title: Materials
3
- emoji: 🏃
4
- colorFrom: green
5
  colorTo: red
6
  sdk: gradio
7
  sdk_version: 5.44.1
@@ -9,4 +9,4 @@ app_file: app.py
9
  pinned: false
10
  ---
11
 
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: Material Heat Analysis
3
+ emoji: 🌡️
4
+ colorFrom: blue
5
  colorTo: red
6
  sdk: gradio
7
  sdk_version: 5.44.1
 
9
  pinned: false
10
  ---
11
 
12
+ یک اپلیکیشن برای تحلیل مصالح ساختمانی از تصویر و محاسبه ΔT سطح.
app.py ADDED
@@ -0,0 +1,184 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import gradio as gr
3
+ from collections import Counter
4
+ from transformers import AutoImageProcessor, AutoModelForImageClassification
5
+ from PIL import Image
6
+ import torch
7
+ import math
8
+
9
+ # ============================== (همان پارامترها و توابع قبلی)
10
+ material_params = {
11
+ "brick": {"alpha": 0.3, "eps": 0.9, "I": 1600},
12
+ "stone": {"alpha": 0.25, "eps": 0.92, "I": 2000},
13
+ "polishedstone": {"alpha": 0.2, "eps": 0.9, "I": 2100},
14
+ "concrete": {"alpha": 0.35, "eps": 0.9, "I": 1800},
15
+ "metal": {"alpha": 0.5, "eps": 0.2, "I": 4000},
16
+ "glass": {"alpha": 0.1, "eps": 0.85, "I": 1500},
17
+ "wood": {"alpha": 0.35, "eps": 0.9, "I": 800},
18
+ "tile": {"alpha": 0.4, "eps": 0.9, "I": 1200},
19
+ "ceramic": {"alpha": 0.45, "eps": 0.92, "I": 1300},
20
+ "painted": {"alpha": 0.3, "eps": 0.9, "I": 1000},
21
+ "plastic": {"alpha": 0.1, "eps": 0.95, "I": 800},
22
+ "paper": {"alpha": 0.6, "eps": 0.95, "I": 500},
23
+ "mirror": {"alpha": 0.7, "eps": 0.1, "I": 2000},
24
+ "foliage": {"alpha": 0.25, "eps": 0.98, "I": 900},
25
+ "water": {"alpha": 0.06, "eps": 0.98, "I": 4200},
26
+
27
+ }
28
+
29
+ material_categories = {
30
+ "facade": {"members": ["brick", "stone", "polishedstone", "concrete", "tile", "ceramic", "painted"],
31
+ "candidates": ["brick", "stone", "polishedstone", "concrete", "tile", "ceramic", "painted"]},
32
+ "glazing": {"members": ["glass", "mirror"], "candidates": ["glass", "mirror"]},
33
+ "metallic": {"members": ["metal"], "candidates": ["metal"]},
34
+ "coverings": {"members": ["plastic", "paper", "fabric"], "candidates": ["plastic", "paper", "fabric"]},
35
+ "wood_elements": {"members": ["wood"], "candidates": ["wood"]},
36
+ "vegetation": {"members": ["foliage"], "candidates": ["foliage"]},
37
+ "water_bodies": {"members": ["water"], "candidates": ["water"]},
38
+
39
+ }
40
+
41
+ replacement_text = {
42
+ "facade": {"brick": "آجر روشن یا نمای سرامیکی/تایل روشن با پوشش بازتابی (cool coating)",
43
+ "stone": "سنگ روشن یا سنگ با پوشش بازتابی",
44
+ "polishedstone": "سنگ مات روشن یا سرامیک نما روشن",
45
+ "concrete": "بتن روشن با پوشش بازتابی یا موزاییک نما روشن",
46
+ "tile": "کاشی/سرامیک روشن یا متخلخل",
47
+ "ceramic": "سرامیک روشن با نمای بازتابی",
48
+ "painted": "رنگ بازتابی (cool paint) یا پوشش نانو بازتابی"},
49
+ "glazing": {"glass": "شیشه دو جداره با پوشش Low-E یا شیشه بازتابی کنترل‌شده",
50
+ "mirror": "شیشه مات یا شیشه Low-E با فریم عایق"},
51
+ "metallic": {"metal": "آلومینیوم رنگ روشن یا پوشش پودری با بازتاب بالا"},
52
+ "coverings": {"plastic": "سنگ سبک یا چوب روکش‌دار روشن (بسته به کاربرد)",
53
+ "paper": "در نما کاربرد معمول ندارد - بررسی بهینه‌سازی طراحی",
54
+ "fabric": "پارچه با روکش بازتابی یا سایه‌انداز طبیعی"},
55
+ "wood_elements": {"wood": "چوب رنگ روشن یا چوب با روکش بازتابی/محافظ"},
56
+ "vegetation": {"foliage": None},
57
+ "water_bodies": {"water": None},
58
+
59
+ }
60
+
61
+ # ============================== (توابع کمکی)
62
+ def ET_proxy(T, RH):
63
+ es = 0.6108 * math.exp((17.27 * T) / (T + 237.3))
64
+ return es * (1 - RH / 100.0)
65
+
66
+ def calc_deltaT(material, T_air, RH=40, u=2, S=700):
67
+ if material not in material_params: return 0.0
68
+ alpha, eps, I = material_params[material]["alpha"], material_params[material]["eps"], material_params[material]["I"]
69
+ A, B, C, D = 1.0, 0.4, 0.8, 0.015
70
+ h_c = 5.8 + 4.1 * u
71
+ if material == "foliage":
72
+ C_m = A * (1 - alpha) - D * ET_proxy(T_air, RH)
73
+ else:
74
+ C_m = A * (1 - alpha) + B * (1 - eps) + (C / math.sqrt(max(I, 1)))
75
+ gamma = S / max(h_c, 1e-6)
76
+ return gamma * C_m / 1000.0
77
+
78
+ # ============================== (بارگذاری مدل)
79
+ model_id = "prithivMLmods/Minc-Materials-23"
80
+ processor = AutoImageProcessor.from_pretrained(model_id)
81
+ model = AutoModelForImageClassification.from_pretrained(model_id)
82
+
83
+ patch_size = 224
84
+ def get_patches(image, size=224, stride=100):
85
+ patches = []
86
+ w, h = image.size
87
+ for scale in [1.0, 0.75, 0.5]:
88
+ scaled_w, scaled_h = int(w * scale), int(h * scale)
89
+ if min(scaled_w, scaled_h) < size: continue
90
+ scaled_img = image.resize((scaled_w, scaled_h), Image.Resampling.LANCZOS)
91
+ for i in range(0, scaled_w, stride):
92
+ for j in range(0, scaled_h, stride):
93
+ box = (i, j, min(i+size, scaled_w), min(j+size, scaled_h))
94
+ patch = scaled_img.crop(box)
95
+ if patch.size[0] >= size and patch.size[1] >= size:
96
+ patches.append(patch)
97
+ return patches
98
+
99
+ # ============================== (تابع اصلی Gradio)
100
+ def analyze_image(image, T_air=32.0, RH=40, u=2.0, S=700):
101
+ patches = get_patches(image, size=patch_size)
102
+ all_predictions = []
103
+ for patch in patches:
104
+ inputs = processor(images=patch, return_tensors="pt")
105
+ with torch.no_grad():
106
+ outputs = model(**inputs)
107
+ probs = torch.nn.functional.softmax(outputs.logits, dim=-1)
108
+ top1 = torch.argmax(probs[0]).item()
109
+ label = model.config.id2label[top1]
110
+ all_predictions.append(label)
111
+
112
+ counter = Counter(all_predictions)
113
+ total_patches = len(patches)
114
+ MIN_COUNT = 3
115
+ ignore_classes = ["food", "skin", "other", "wallpaper", "carpet","sky"]
116
+ materials_found = {label for label, count in counter.items() if count >= MIN_COUNT and label not in ignore_classes}
117
+
118
+ if len(materials_found) == 0:
119
+ return "هیچ مصالح معتبرِ کافی در تصویر شناسایی نشد (حداقل تکرار MIN_COUNT رعایت نمی‌شود)."
120
+
121
+ material_info = {}
122
+ for label in sorted(materials_found):
123
+ count = counter[label]
124
+ share = count / total_patches
125
+ dT = calc_deltaT(label, T_air, RH, u, S)
126
+ material_info[label] = {"count": count, "share": share, "deltaT": dT}
127
+
128
+ # مقایسه درون‌دسته‌ای و توصیه
129
+ IMPROVEMENT_THRESHOLD = 0.02
130
+ SHARE_IMPORTANCE_THRESHOLD = 0.03
131
+ recommendations = []
132
+ candidate_delta_cache = {}
133
+ for cat, info in material_categories.items():
134
+ for candidate in info["candidates"]:
135
+ if candidate not in candidate_delta_cache:
136
+ candidate_delta_cache[candidate] = calc_deltaT(candidate, T_air, RH, u, S)
137
+
138
+ for label, info in material_info.items():
139
+ found_category = None
140
+ for cat, cinfo in material_categories.items():
141
+ if label in cinfo["members"]:
142
+ found_category = cat
143
+ break
144
+ if found_category is None:
145
+ recommendations.append(f"{label}: در دسته‌های پیش‌تعریف قرار ندارد.")
146
+ continue
147
+ candidates = material_categories[found_category]["candidates"]
148
+ cand_list = [(c, candidate_delta_cache.get(c, calc_deltaT(c, T_air, RH, u, S))) for c in candidates]
149
+ cand_list.sort(key=lambda x: x[1])
150
+ current_dT = info["deltaT"]
151
+ best_candidate, best_dT = cand_list[0]
152
+ improvement = current_dT - best_dT
153
+ share_pct = info["share"] * 100
154
+ if improvement >= IMPROVEMENT_THRESHOLD and best_candidate != label:
155
+ importance = "High" if info["share"] >= SHARE_IMPORTANCE_THRESHOLD else "Optional"
156
+ suggestion_text = replacement_text.get(found_category, {}).get(best_candidate, f"Consider replacing with {best_candidate}")
157
+ recommendations.append(
158
+ f"{label} ({found_category}): ΔT={current_dT:+.2f}°C → جایگزین: {best_candidate} (ΔT={best_dT:+.2f}°C) | بهبود: {improvement:+.2f}°C | اهمیت: {importance} | پیشنهاد: {suggestion_text}"
159
+ )
160
+ else:
161
+ recommendations.append(f"{label}: ΔT={current_dT:+.2f}°C → نیازی به جایگزینی ندارد.")
162
+
163
+ scene_deltaT = sum([info["share"] * info["deltaT"] for info in material_info.values()])
164
+ recommendations.append(f"ΔT میانگین وزنی کل صحنه: {scene_deltaT:+.2f}°C")
165
+ recommendations.append(f"دمای مؤثر سطح: {T_air + scene_deltaT:.2f}°C")
166
+
167
+ return "\n".join(recommendations)
168
+
169
+ # ============================== (راه‌اندازی رابط Gradio)
170
+ iface = gr.Interface(
171
+ fn=analyze_image,
172
+ inputs=[
173
+ gr.Image(type="pil", label="آپلود تصویر"),
174
+ gr.Number(value=32.0, label="دمای هوا T_air (°C)"),
175
+ gr.Number(value=40, label="رطوبت نسبی RH (%)"),
176
+ gr.Number(value=2.0, label="سرعت باد u (m/s)"),
177
+ gr.Number(value=700, label="تابش خورشیدی S (W/m²)")
178
+ ],
179
+ outputs=gr.Textbox(label="خروجی ΔT و توصیه‌ها"),
180
+ title="تحلیل مصالح و ΔT سطحی",
181
+ description="آپلود تصویر ساختمان/محیط → نمایش ΔT مصالح و توصیه جایگزینی منطقی."
182
+ )
183
+
184
+ iface.launch()
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ gradio==5.44.1
2
+ transformers==4.40.0
3
+ torch>=2.0.0
4
+ pillow>=10.0.0
5
+ numpy>=1.25.0
6
+ matplotlib>=3.8.0