reyhane1222 commited on
Commit
a419469
·
verified ·
1 Parent(s): 4443d9f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +64 -429
app.py CHANGED
@@ -2,481 +2,116 @@
2
  import gradio as gr
3
  from collections import Counter
4
  from transformers import AutoImageProcessor, AutoModelForImageClassification
5
- from PIL import Image, ImageDraw
6
- import torch
7
- import math
8
- import numpy as np
9
- import matplotlib.pyplot as plt
10
- import io
11
- import base64
12
- from typing import Dict, List, Any
13
- import os
14
 
15
  # ==============================
16
- # 📦 بارگذاری مدل (یکبار کش میشه)
17
  # ==============================
 
 
18
  @torch.no_grad()
19
  def load_model():
20
  model_id = "prithivMLmods/Minc-Materials-23"
21
  processor = AutoImageProcessor.from_pretrained(model_id)
22
  model = AutoModelForImageClassification.from_pretrained(model_id)
 
23
  return processor, model
24
 
25
  processor, model = load_model()
26
 
27
  # ==============================
28
- # 📊 پارامترهای مصالح
29
  # ==============================
30
  material_params = {
31
- "brick": {"alpha": 0.3, "eps": 0.9, "I": 1600, "name": "آجر", "color": "#A52A2A", "category": "facade"},
32
- "stone": {"alpha": 0.25, "eps": 0.92, "I": 2000, "name": "سنگ", "color": "#808080", "category": "facade"},
33
- "polishedstone": {"alpha": 0.2, "eps": 0.9, "I": 2100, "name": "سنگ صیقلی", "color": "#C0C0C0", "category": "facade"},
34
- "concrete": {"alpha": 0.35, "eps": 0.9, "I": 1800, "name": "بتن", "color": "#A9A9A9", "category": "facade"},
35
- "metal": {"alpha": 0.5, "eps": 0.2, "I": 4000, "name": "فلز", "color": "#4682B4", "category": "metallic"},
36
- "glass": {"alpha": 0.1, "eps": 0.85, "I": 1500, "name": "شیشه", "color": "#87CEEB", "category": "glazing"},
37
- "wood": {"alpha": 0.35, "eps": 0.9, "I": 800, "name": "چوب", "color": "#8B4513", "category": "wood_elements"},
38
- "tile": {"alpha": 0.4, "eps": 0.9, "I": 1200, "name": "کاشی", "color": "#FF6347", "category": "facade"},
39
- "ceramic": {"alpha": 0.45, "eps": 0.92, "I": 1300, "name": "سرامیک", "color": "#FF4500", "category": "facade"},
40
- "painted": {"alpha": 0.3, "eps": 0.9, "I": 1000, "name": "سطح رنگ‌شده", "color": "#FFFF00", "category": "facade"},
41
- "plastic": {"alpha": 0.1, "eps": 0.95, "I": 800, "name": "پلاستیک", "color": "#ADFF2F", "category": "coverings"},
42
- "paper": {"alpha": 0.6, "eps": 0.95, "I": 500, "name": "کاغذ", "color": "#F5F5DC", "category": "coverings"},
43
- "mirror": {"alpha": 0.7, "eps": 0.1, "I": 2000, "name": "آینه", "color": "#E6E6FA", "category": "glazing"},
44
- "foliage": {"alpha": 0.25, "eps": 0.98, "I": 900, "name": "گیاهان", "color": "#228B22", "category": "vegetation"},
45
- "water": {"alpha": 0.06, "eps": 0.98, "I": 4200, "name": "آب", "color": "#1E90FF", "category": "water_bodies"},
46
- "sky": {"alpha": 1.0, "eps": 1.0, "I": 0, "name": "آسمان", "color": "#87CEFA", "category": "background"},
47
  }
48
 
49
  material_categories = {
50
- "facade": ["brick", "stone", "polishedstone", "concrete", "tile", "ceramic", "painted"],
51
- "glazing": ["glass", "mirror"],
52
- "metallic": ["metal"],
53
- "coverings": ["plastic", "paper"],
54
- "wood_elements": ["wood"],
55
- "vegetation": ["foliage"],
56
- "water_bodies": ["water"],
57
- "background": ["sky"]
58
- }
59
-
60
- # توصیه‌های بهبود یافته با تمرکز بر خنک‌کنندگی
61
- replacement_recommendations = {
62
- "facade": {
63
- "brick": {"name": "آجر روشن", "alpha": 0.25, "eps": 0.85, "I": 1600, "improvement": 0.05},
64
- "stone": {"name": "سنگ روشن با پوشش بازتابی", "alpha": 0.18, "eps": 0.88, "I": 2000, "improvement": 0.07},
65
- "polishedstone": {"name": "سنگ صیقلی با پوشش بازتابی", "alpha": 0.15, "eps": 0.85, "I": 2100, "improvement": 0.05},
66
- "concrete": {"name": "بتن روشن با پوشش بازتابی", "alpha": 0.28, "eps": 0.85, "I": 1800, "improvement": 0.07},
67
- "tile": {"name": "کاشی/سرامیک روشن", "alpha": 0.32, "eps": 0.85, "I": 1200, "improvement": 0.08},
68
- "ceramic": {"name": "سرامیک روشن با پوشش بازتابی", "alpha": 0.35, "eps": 0.88, "I": 1300, "improvement": 0.10},
69
- "painted": {"name": "رنگ بازتابی (cool paint)", "alpha": 0.22, "eps": 0.85, "I": 1000, "improvement": 0.08}
70
- },
71
- "glazing": {
72
- "glass": {"name": "شیشه دوجداره Low-E", "alpha": 0.08, "eps": 0.80, "I": 1500, "improvement": 0.02},
73
- "mirror": {"name": "شیشه مات یا بازتاب متعادل", "alpha": 0.60, "eps": 0.15, "I": 2000, "improvement": 0.10}
74
- },
75
- "metallic": {
76
- "metal": {"name": "آلومینیوم رنگ روشن", "alpha": 0.40, "eps": 0.25, "I": 4000, "improvement": 0.10}
77
- },
78
- "coverings": {
79
- "plastic": {"name": "پلاستیک روشن با پوشش بازتابی", "alpha": 0.08, "eps": 0.90, "I": 800, "improvement": 0.02},
80
- "paper": {"name": "مواد پوششی بازتابی", "alpha": 0.50, "eps": 0.90, "I": 500, "improvement": 0.10}
81
- },
82
- "wood_elements": {
83
- "wood": {"name": "چوب روشن با پوشش بازتابی", "alpha": 0.28, "eps": 0.85, "I": 800, "improvement": 0.07}
84
- },
85
- "vegetation": {
86
- "foliage": {"name": "نگهداری پوشش گیاهی", "alpha": 0.25, "eps": 0.98, "I": 900, "improvement": 0.00}
87
- },
88
- "water_bodies": {
89
- "water": {"name": "حفظ منابع آبی", "alpha": 0.06, "eps": 0.98, "I": 4200, "improvement": 0.00}
90
- },
91
- "background": {
92
- "sky": {"name": "عنصر طبیعی", "alpha": 1.0, "eps": 1.0, "I": 0, "improvement": 0.00}
93
- }
94
  }
95
 
96
  # ==============================
97
- # محاسبات
98
  # ==============================
99
  def ET_proxy(T: float, RH: float) -> float:
100
- """محاسبه فشار بخار اشباع"""
101
  es = 0.6108 * math.exp((17.27 * T) / (T + 237.3))
102
- return es * (1 - RH / 100)
103
 
104
  def calc_deltaT(material: str, T_air: float, RH: float, u: float, S: float) -> float:
105
- """محاسبه اختلاف دمای سطح مصالح"""
106
- if material not in material_params:
107
- return 0.0
108
-
109
  p = material_params[material]
110
  alpha, eps, I = p["alpha"], p["eps"], p["I"]
111
-
112
- # ضرایب معادله
113
- A, B, C, D = 1.0, 0.4, 0.8, 0.015
114
- h_c = 5.8 + 4.1 * u # ضریب انتقال حرارت جابجایی
115
-
116
- if material == "foliage":
117
- # برای گیاهان، اثر خنک‌کنندگی تبخیر و تعرق در نظر گرفته می‌شود
118
- C_m = A * (1 - alpha) - D * ET_proxy(T_air, RH)
119
  else:
120
- # برای سایر مصالح
121
- C_m = A * (1 - alpha) + B * (1 - eps) + (C / math.sqrt(max(I, 1)))
122
-
123
- gamma = S / max(h_c, 1e-6) # ضریب تابش
124
- return gamma * C_m / 1000.0
125
 
126
- def get_patches(image: Image.Image, size: int = 224, stride: int = 200) -> List[Image.Image]:
127
- """تقسیم تصویر به پچ‌های کوچکتر برای پردازش"""
128
- patches = []
 
129
  w, h = image.size
130
-
131
- for i in range(0, w, stride):
132
- for j in range(0, h, stride):
133
- box = (i, j, min(i + size, w), min(j + size, h))
134
  patch = image.crop(box)
135
-
136
- # نادیده گرفتن پچ‌های خیلی کوچک
137
- if patch.size[0] < size // 2 or patch.size[1] < size // 2:
138
- continue
139
-
140
  patches.append(patch)
141
-
142
  return patches
143
 
144
- def find_better_material_in_category(current_material: str, T_air: float, RH: float, u: float, S: float) -> Dict[str, Any]:
145
- """پیدا کردن مصالح بهتر در همان دسته برای بهبود خنک‌کنندگی"""
146
- if current_material not in material_params:
147
- return {"found": False}
148
-
149
- category = material_params[current_material]["category"]
150
- current_dT = calc_deltaT(current_material, T_air, RH, u, S)
151
-
152
- # پیدا کردن تمام مصالح در این دسته
153
- materials_in_category = material_categories.get(category, [])
154
-
155
- # محاسبه ΔT برای همه مصالح در این دسته
156
- materials_with_dT = []
157
- for material in materials_in_category:
158
- if material != current_material:
159
- dT = calc_deltaT(material, T_air, RH, u, S)
160
- improvement = current_dT - dT # مقدار مثبت یعنی مصالح جدید خنک‌تر است
161
- materials_with_dT.append({
162
- "material": material,
163
- "name": material_params[material]["name"],
164
- "dT": dT,
165
- "improvement": improvement
166
- })
167
-
168
- # مرتب‌سازی بر اساس بهبود (بهترین بهبود اول)
169
- materials_with_dT.sort(key=lambda x: x["improvement"], reverse=True)
170
-
171
- # اگر مصالح بهتری پیدا شد
172
- if materials_with_dT and materials_with_dT[0]["improvement"] > 0:
173
- best_material = materials_with_dT[0]
174
- recommendation = replacement_recommendations[category].get(current_material, {})
175
-
176
- return {
177
- "found": True,
178
- "current_material": current_material,
179
- "current_name": material_params[current_material]["name"],
180
- "current_dT": current_dT,
181
- "better_material": best_material["material"],
182
- "better_name": best_material["name"],
183
- "better_dT": best_material["dT"],
184
- "improvement": best_material["improvement"],
185
- "recommendation": recommendation.get("name", "جایگزین بهینه"),
186
- "estimated_improvement": recommendation.get("improvement", 0.0) * 100
187
- }
188
-
189
- return {"found": False}
190
-
191
- def create_thermal_image(img: Image.Image, material_map: List[str], T_air: float, RH: float, u: float, S: float) -> str:
192
- """ایجاد تصویر حرارتی بر اساس مصالح شناسایی شده"""
193
- # ایجاد یک نقشه حرارتی مصنوعی
194
- draw = ImageDraw.Draw(img)
195
- w, h = img.size
196
-
197
- # ایجاد یک overlay برای نشان دادن مناطق مختلف
198
- overlay = Image.new('RGBA', img.size, (0, 0, 0, 0))
199
- overlay_draw = ImageDraw.Draw(overlay)
200
-
201
- # محاسبه دمای نسبی برای هر ماده
202
- material_dT = {}
203
- for material in set(material_map):
204
- material_dT[material] = calc_deltaT(material, T_air, RH, u, S)
205
-
206
- if not material_dT:
207
- return None
208
-
209
- max_dT = max(material_dT.values())
210
- min_dT = min(material_dT.values())
211
-
212
- # تقسیم تصویر به بخش‌ها و اختصاص رنگ بر اساس مصالح
213
- patch_size = max(20, min(w, h) // 20)
214
- num_patches = len(material_map)
215
-
216
- for i, material in enumerate(material_map):
217
- if i * patch_size >= h:
218
- break
219
-
220
- dT = material_dT.get(material, 0)
221
- # نرمال‌سازی دما برای رنگ (قرمز برای گرم، آبی برای خنک)
222
- temp_ratio = (dT - min_dT) / (max_dT - min_dT) if max_dT != min_dT else 0.5
223
-
224
- # رنگ‌بندی بر اساس دما
225
- red = int(255 * temp_ratio)
226
- blue = int(255 * (1 - temp_ratio))
227
- green = 50
228
- color = (red, green, blue, 150)
229
-
230
- # رسم مستطیل برای این پچ
231
- x = (i * patch_size) % w
232
- y = (i * patch_size) // w * patch_size
233
-
234
- if x + patch_size <= w and y + patch_size <= h:
235
- overlay_draw.rectangle([x, y, x + patch_size, y + patch_size], fill=color)
236
-
237
- # ترکیب تصویر اصلی با overlay
238
- img_with_overlay = Image.alpha_composite(img.convert('RGBA'), overlay).convert('RGB')
239
-
240
- # تبدیل به base64 برای نمایش در Gradio
241
- buffered = io.BytesIO()
242
- img_with_overlay.save(buffered, format="JPEG")
243
- img_str = base64.b64encode(buffered.getvalue()).decode()
244
-
245
- return f"data:image/jpeg;base64,{img_str}"
246
-
247
- def create_comparison_chart(materials: List[Dict], T_air: float, RH: float, u: float, S: float) -> str:
248
- """ایجاد نمودار مقایسه‌ای مصالح"""
249
- if not materials:
250
- return None
251
-
252
- # محاسبه ΔT برای همه مصالح
253
- material_names = []
254
- material_dTs = []
255
- material_colors = []
256
-
257
- for material_data in materials:
258
- material = material_data["material"]
259
- dT = calc_deltaT(material, T_air, RH, u, S)
260
- material_names.append(material_params[material]["name"])
261
- material_dTs.append(dT)
262
- material_colors.append(material_params[material]["color"])
263
-
264
- # ایجاد نمودار
265
- plt.figure(figsize=(10, 6))
266
- bars = plt.bar(material_names, material_dTs, color=material_colors)
267
- plt.xlabel('مصالح')
268
- plt.ylabel('ΔT (°C)')
269
- plt.title('مقایسه اختلاف دمای مصالح شناسایی شده')
270
- plt.xticks(rotation=45, ha='right')
271
-
272
- # اضافه کردن مقادیر روی نمودار
273
- for bar, dT in zip(bars, material_dTs):
274
- plt.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.05,
275
- f'{dT:.2f}', ha='center', va='bottom')
276
-
277
- plt.tight_layout()
278
-
279
- # ذخیره نمودار در بافر
280
- buf = io.BytesIO()
281
- plt.savefig(buf, format='png', bbox_inches='tight')
282
- buf.seek(0)
283
-
284
- # تبدیل به base64
285
- img_str = base64.b64encode(buf.getvalue()).decode()
286
- plt.close()
287
-
288
- return f"data:image/png;base64,{img_str}"
289
-
290
  # ==============================
291
- # تابع اصلی
292
  # ==============================
293
- def analyze(img: Image.Image, T_air: float, RH: float = 40, u: float = 2, S: float = 700) -> Dict:
294
- """آنالیز تصویر و محاسبه پارامترهای حرارتی"""
295
  img = img.convert("RGB")
296
  patches = get_patches(img)
 
297
 
298
- if len(patches) == 0:
299
- return {
300
- "text_result": "⛔ تصویر نامعتبر است یا کوچک است.",
301
- "thermal_image": None,
302
- "comparison_chart": None
303
- }
304
-
305
- # پیش‌بینی برای هر پچ
306
  all_predictions = []
307
- confidence_scores = []
308
- material_map = [] # برای نقشه حرارتی
309
-
310
  for patch in patches:
311
- inputs = processor(images=patch, return_tensors="pt")
312
-
313
- with torch.no_grad():
314
- outputs = model(**inputs)
315
- probs = torch.nn.functional.softmax(outputs.logits, dim=-1)
316
- confidence, pred = torch.max(probs, dim=-1)
317
-
318
- label = model.config.id2label[pred.item()]
319
  all_predictions.append(label)
320
- material_map.append(label)
321
- confidence_scores.append(confidence.item())
322
 
323
- # تحلیل نتایج
324
  counter = Counter(all_predictions)
325
- total_patches = len(patches)
326
-
327
- # فیلتر مواد با فراوانی کافی و اعتبار سنجی
328
- materials_found = []
329
- for m, c in counter.items():
330
- if c >= max(3, total_patches * 0.05) and m in material_params:
331
- materials_found.append({
332
- "material": m,
333
- "count": c,
334
- "share": c / total_patches,
335
- "name": material_params[m]["name"],
336
- "category": material_params[m]["category"]
337
- })
338
-
339
- if not materials_found:
340
- return {
341
- "text_result": "⛔ هیچ مصالح معتبری شناسایی نشد.",
342
- "thermal_image": None,
343
- "comparison_chart": None
344
- }
345
-
346
- # ایجاد گزارش متنی
347
- text_result = "📋 نتایج تحلیل مصالح:\n\n"
348
-
349
- # بخش اول: مصالح شناسایی شده
350
- text_result += "🔍 مصالح شناسایی شده:\n"
351
- for material_data in materials_found:
352
- m = material_data["material"]
353
- dT = calc_deltaT(m, T_air, RH, u, S)
354
- text_result += f"• {material_data['name']}: سهم={material_data['share']*100:.1f}% | ΔT={dT:+.2f}°C\n"
355
-
356
- text_result += "\n"
357
-
358
- # بخش دوم: مقایسه و توصیه‌های بهبود
359
- text_result += "💡 توصیه‌های بهینه‌سازی:\n"
360
- improvement_recommendations = []
361
-
362
- for material_data in materials_found:
363
- m = material_data["material"]
364
- better_material = find_better_material_in_category(m, T_air, RH, u, S)
365
-
366
- if better_material["found"]:
367
- improvement_recommendations.append(better_material)
368
- text_result += f"• برای {better_material['current_name']} (ΔT={better_material['current_dT']:+.2f}°C):\n"
369
- text_result += f" → پیشنهاد: {better_material['better_name']} (ΔT={better_material['better_dT']:+.2f}°C)\n"
370
- text_result += f" → بهبود预计: {better_material['improvement']:.2f}°C\n"
371
- text_result += f" → توصیه: {better_material['recommendation']}\n\n"
372
-
373
- if not improvement_recommendations:
374
- text_result += "✅ مصالح شناسایی شده از نظر حرارتی بهینه هستند.\n\n"
375
-
376
- # بخش سوم: خلاصه نتایج
377
- scene_deltaT = sum(material_data["share"] * calc_deltaT(material_data["material"], T_air, RH, u, S)
378
- for material_data in materials_found)
379
- effective_temp = T_air + scene_deltaT
380
-
381
- text_result += f"📊 خلاصه نتایج:\n"
382
- text_result += f"• ΔT میانگین وزنی: {scene_deltaT:+.2f} °C\n"
383
- text_result += f"• دمای مؤثر سطح: {effective_temp:.2f} °C\n"
384
- text_result += f"• دمای هوا: {T_air} °C\n"
385
- text_result += f"• تعداد پچ‌های تحلیل شده: {total_patches}\n"
386
-
387
- # ایجاد ویژوال‌ها
388
- thermal_image = create_thermal_image(img, material_map, T_air, RH, u, S)
389
- comparison_chart = create_comparison_chart(materials_found, T_air, RH, u, S)
390
-
391
- return {
392
- "text_result": text_result,
393
- "thermal_image": thermal_image,
394
- "comparison_chart": comparison_chart
395
- }
396
 
397
  # ==============================
398
- # رابط کاربری Gradio بهبود یافته
399
  # ==============================
400
- css = """
401
- .gradio-container {
402
- font-family: 'Vazir', 'Segoe UI', Tahoma, sans-serif;
403
- }
404
- .header {
405
- text-align: center;
406
- padding: 20px;
407
- background: linear-gradient(135deg, #2c3e50, #3498db);
408
- color: white;
409
- border-radius: 10px;
410
- margin-bottom: 20px;
411
- }
412
- .result-box {
413
- padding: 15px;
414
- border-radius: 10px;
415
- background-color: #f8f9fa;
416
- border-left: 5px solid #3498db;
417
- margin-bottom: 15px;
418
- }
419
- .positive {
420
- color: #27ae60;
421
- font-weight: bold;
422
- }
423
- .negative {
424
- color: #e74c3c;
425
- font-weight: bold;
426
- }
427
- """
428
-
429
- with gr.Blocks(css=css, title="تحلیل هوشمند مصالح ساختمانی") as demo:
430
- gr.Markdown("""
431
- <div class="header">
432
- <h1>🏗️ تحلیل هوشمند مصالح ساختمانی</h1>
433
- <p>این سامانه با استفاده از هوش مصنوعی، مصالح را شناسایی کرده و با تحلیل حرارتی، بهینه‌ترین گزینه‌ها را پیشنهاد می‌دهد</p>
434
- </div>
435
- """)
436
-
437
- with gr.Row():
438
- with gr.Column(scale=1):
439
- gr.Markdown("### ⚙️ پارامترهای محیطی")
440
- img_input = gr.Image(type="pil", label="📷 تصویر نمای ساختمان")
441
- T_air = gr.Slider(minimum=-10, maximum=50, value=32, step=1, label="🌡️ دمای هوا (°C)")
442
- RH = gr.Slider(minimum=0, maximum=100, value=40, step=5, label="💧 رطوبت نسبی (%)")
443
- u = gr.Slider(minimum=0, maximum=10, value=2, step=0.5, label="💨 سرعت باد (m/s)")
444
- S = gr.Slider(minimum=0, maximum=1500, value=700, step=50, label="☀️ تابش خورشیدی (W/m²)")
445
- btn = gr.Button("تحلیل تصویر", variant="primary", size="lg")
446
-
447
- with gr.Column(scale=2):
448
- gr.Markdown("### 📊 نتایج تحلیل")
449
- text_output = gr.Textbox(label="نتایج تحلیل", lines=18)
450
-
451
- with gr.Row():
452
- thermal_output = gr.Image(label="نقشه حرارتی مصالح", interactive=False)
453
- chart_output = gr.Image(label="مقایسه مصالح", interactive=False)
454
-
455
- # حذف مثال‌های مشکل‌ساز
456
- # gr.Examples(
457
- # examples=[
458
- # ["example_building.jpg", 35, 45, 1.5, 800],
459
- # ["example_facade.jpg", 30, 50, 2.0, 750]
460
- # ],
461
- # inputs=[img_input, T_air, RH, u, S],
462
- # outputs=[text_output, thermal_output, chart_output],
463
- # fn=analyze,
464
- # cache_examples=True
465
- # )
466
-
467
- btn.click(
468
- fn=analyze,
469
- inputs=[img_input, T_air, RH, u, S],
470
- outputs=[text_output, thermal_output, chart_output]
471
- )
472
-
473
- # پاورقی
474
- gr.Markdown("""
475
- <div style="text-align: center; margin-top: 30px; padding: 15px; background-color: #f8f9fa; border-radius: 10px;">
476
- <p>سامانه تحلیل هوشمند مصالح ساختمانی | توسعه یافته برای کاربردهای علمی و پژوهشی</p>
477
- <p>این ابزار از مدل هوش مصنوعی برای شناسایی مصالح استفاده می‌کند و نتایج آن بر اساس محاسبات ترمودینامیکی ارائه می‌شود.</p>
478
- </div>
479
- """)
480
 
481
- if __name__ == "__main__":
482
- demo.launch()
 
2
  import gradio as gr
3
  from collections import Counter
4
  from transformers import AutoImageProcessor, AutoModelForImageClassification
5
+ from PIL import Image
6
+ import torch, math
7
+ from typing import List, Dict, Any
8
+ import base64, io
 
 
 
 
 
9
 
10
  # ==============================
11
+ # 📦 بارگذاری مدل بهینه
12
  # ==============================
13
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
14
+
15
  @torch.no_grad()
16
  def load_model():
17
  model_id = "prithivMLmods/Minc-Materials-23"
18
  processor = AutoImageProcessor.from_pretrained(model_id)
19
  model = AutoModelForImageClassification.from_pretrained(model_id)
20
+ model.to(device).eval()
21
  return processor, model
22
 
23
  processor, model = load_model()
24
 
25
  # ==============================
26
+ # پارامتر مصالح (همانند نسخه قبلی)
27
  # ==============================
28
  material_params = {
29
+ "brick": {"alpha":0.3, "eps":0.9, "I":1600, "name":"آجر", "category":"facade"},
30
+ "stone": {"alpha":0.25, "eps":0.92, "I":2000, "name":"سنگ", "category":"facade"},
31
+ "polishedstone":{"alpha":0.2,"eps":0.9,"I":2100,"name":"سنگ صیقلی","category":"facade"},
32
+ # بقیه مصالح ...
 
 
 
 
 
 
 
 
 
 
 
 
33
  }
34
 
35
  material_categories = {
36
+ "facade":["brick","stone","polishedstone"],
37
+ "glazing":["glass","mirror"],
38
+ "metallic":["metal"],
39
+ "coverings":["plastic","paper"],
40
+ "wood_elements":["wood"],
41
+ "vegetation":["foliage"],
42
+ "water_bodies":["water"],
43
+ "background":["sky"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  }
45
 
46
  # ==============================
47
+ # محاسبات ΔT
48
  # ==============================
49
  def ET_proxy(T: float, RH: float) -> float:
 
50
  es = 0.6108 * math.exp((17.27 * T) / (T + 237.3))
51
+ return es * (1 - RH/100)
52
 
53
  def calc_deltaT(material: str, T_air: float, RH: float, u: float, S: float) -> float:
54
+ if material not in material_params: return 0.0
 
 
 
55
  p = material_params[material]
56
  alpha, eps, I = p["alpha"], p["eps"], p["I"]
57
+ A,B,C,D = 1.0,0.4,0.8,0.015
58
+ h_c = 5.8 + 4.1*u
59
+ if material=="foliage":
60
+ C_m = A*(1-alpha)-D*ET_proxy(T_air,RH)
 
 
 
 
61
  else:
62
+ C_m = A*(1-alpha)+B*(1-eps)+(C/math.sqrt(max(I,1)))
63
+ gamma = S/max(h_c,1e-6)
64
+ return gamma*C_m/1000.0
 
 
65
 
66
+ # ==============================
67
+ # بهینه سازی پچ‌بندی
68
+ # ==============================
69
+ def get_patches(image: Image.Image, size: int=224, stride: int=224) -> List[Image.Image]:
70
  w, h = image.size
71
+ patches = []
72
+ for i in range(0,w,stride):
73
+ for j in range(0,h,stride):
74
+ box = (i,j,min(i+size,w),min(j+size,h))
75
  patch = image.crop(box)
76
+ if patch.size[0]<size//2 or patch.size[1]<size//2: continue
 
 
 
 
77
  patches.append(patch)
 
78
  return patches
79
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
  # ==============================
81
+ # تحلیل تصویر
82
  # ==============================
83
+ def analyze(img: Image.Image, T_air: float, RH: float=40, u: float=2, S: float=700) -> str:
 
84
  img = img.convert("RGB")
85
  patches = get_patches(img)
86
+ if not patches: return "⛔ تصویر نامعتبر است."
87
 
 
 
 
 
 
 
 
 
88
  all_predictions = []
 
 
 
89
  for patch in patches:
90
+ inputs = processor(images=patch, return_tensors="pt").to(device)
91
+ outputs = model(**inputs)
92
+ probs = torch.nn.functional.softmax(outputs.logits, dim=-1)
93
+ pred = torch.argmax(probs[0]).item()
94
+ label = model.config.id2label[pred]
 
 
 
95
  all_predictions.append(label)
 
 
96
 
 
97
  counter = Counter(all_predictions)
98
+ total = len(patches)
99
+ results = []
100
+ for m,c in counter.items():
101
+ if m in material_params:
102
+ dT = calc_deltaT(m,T_air,RH,u,S)
103
+ results.append(f"{material_params[m]['name']} | سهم={c/total*100:.1f}% | ΔT={dT:+.2f}°C")
104
+ return "\n".join(results) if results else "⛔ هیچ مصالح معتبری شناسایی نشد."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
 
106
  # ==============================
107
+ # رابط کاربری ساده
108
  # ==============================
109
+ demo = gr.Interface(
110
+ fn=analyze,
111
+ inputs=[gr.Image(type="pil"), gr.Slider(-10,50,value=32,step=1), gr.Slider(0,100,value=40), gr.Slider(0,10,value=2), gr.Slider(0,1500,value=700)],
112
+ outputs="textbox",
113
+ title="تحلیل مصالح بهینه"
114
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
 
116
+ if __name__=="__main__":
117
+ demo.launch(share=True)