iT邦幫忙

2025 iThome 鐵人賽

DAY 21
0

  延續昨天的實作,今天要繼續以實作的程式碼,將文字辨識結果也納入BIM模型資訊中,我們一起來看一下整個流程與步驟。

21.1. 門物件偵測示範

首先,一樣開啟Colab頁面:https://colab.research.google.com/ 並新增筆記本。
Step1:安裝ifcopenshell及必要套件。

# 1. 安裝 ifcopenshell
!pip install ifcopenshell pandas openpyxl

Step2:匯入必要模組與輸出設定。

# 2. 匯入必要模組與輸出設定
import ifcopenshell
import ifcopenshell.api
import numpy as np
from google.colab import drive
# 掛載 Google Drive(方便存取輸出檔案)
drive.mount('/content/drive')
# 設定 IFC 輸出檔案路徑(Colab 會存到 Google Drive)
OUTPUT_PATH = "/content/drive/MyDrive/yolo_ocr_compare.ifc"

# 簡化示範預設類別
# =========================================================
# 在真實應用中,以下會讀取 YOLO / OCR 的結果檔案
# =========================================================
# [YOLO 偵測幾何用]:class_id, cx, cy 單位皆假設cm
CLASS_DIM = {
    0: ("單開門", 90, 210),
    1: ("雙開門", 180, 210),
}
yolo_detections = [
    (0, 2003.0, 1161.0),
    (1, 2154.5, 1296.0),
    (0, 1120.5, 1301.5),
]

# [OCR 屬性用]:text, cx, cy(門號靠近門中心)
ocr_detections = [
    ("D9", 2005.0, 1160.0),
    ("D8", 2150.0, 1298.0),
    ("D9", 1121.0, 1300.0)
]

USE_OCR = True  # 是否啟用 OCR
MATCH_TOL = 15.0 # 匹配容差(cm)

Step3:建立 IFC 專案結構。

# 3. 建立 IFC 檔與專案骨架(本程式僅為示例)
ifc = ifcopenshell.api.run("project.create_file")
project  = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcProject", name="YOLO_OCR_Compare")
site     = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcSite", name="Site")
building = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcBuilding", name="Building")
storey   = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcBuildingStorey", name="Storey")
ifcopenshell.api.run("aggregate.assign_object", ifc, products=[site], relating_object=project)
ifcopenshell.api.run("aggregate.assign_object", ifc, products=[building], relating_object=site)
ifcopenshell.api.run("aggregate.assign_object", ifc, products=[storey], relating_object=building)

# 單位皆假設cm
length_unit = ifcopenshell.api.run("unit.add_si_unit", ifc, unit_type="LENGTHUNIT", prefix="CENTI")
ifcopenshell.api.run("unit.assign_unit", ifc, units=[length_unit])

# 幾何 (讓元素「看得見」)
context  = ifcopenshell.api.run("context.add_context", ifc, context_type="Model")
body_ctx = ifcopenshell.api.run("context.add_context", ifc, context_type="Model",
                                context_identifier="Body", target_view="MODEL_VIEW", parent=context)

# =============== 小工具:YOLO↔OCR 座標匹配(距離最近且在容差內)===============
def match_ocr_to_yolo(cx, cy, ocr_list, tol=MATCH_TOL):
    best = None
    best_d = float("inf")
    for text, ox, oy in ocr_list:
        d = ((cx - ox)**2 + (cy - oy)**2) ** 0.5
        if d < best_d and d <= tol:
            best_d = d
            best = (text, ox, oy, d)
    return best  # (text, ox, oy, distance) or None

# =============== 主要流程:建立 IfcDoor(YOLO 幾何)+(可選)OCR 屬性 ===============
summary = []
for idx, (class_id, cx, cy) in enumerate(yolo_detections, start=1):

    # -------------------------
    # [YOLO 幾何]:決定門型與尺寸
    # -------------------------
    label, door_w, door_h = CLASS_DIM[class_id]

    # 建立 IfcDoor(語意層)
    door = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcDoor", name=f"{label}_{idx}")
    door.OverallWidth  = door_w
    door.OverallHeight = door_h

    # 放置(以門板左側對齊)
    m = np.eye(4)
    m[0, 3] = cx - door_w/2.0
    m[1, 3] = cy
    m[2, 3] = 0.0
    ifcopenshell.api.run("geometry.edit_object_placement", ifc, product=door, matrix=m, is_si=False)

    # 幾何(Geometry):用 IfcOpenShell 快速門形狀(底層為 IfcExtrudedAreaSolid)
    rep = ifcopenshell.api.run("geometry.add_door_representation", ifc, context=body_ctx,
                               overall_height=door_h, overall_width=door_w)
    if rep:
        ifcopenshell.api.run("geometry.assign_representation", ifc, product=door, representation=rep)

    # 掛到樓層(空間關係)
    ifcopenshell.api.run("spatial.assign_container", ifc, relating_structure=storey, products=[door])

    # -------------------------
    # [OCR 屬性]:匹配門號等文字到該門
    # -------------------------
    matched = match_ocr_to_yolo(cx, cy, ocr_detections) if USE_OCR else None
    if matched:
        ocr_text, ox, oy, dist = matched

        # 標準屬性集:將門號寫入 Reference
        pset_common = ifcopenshell.api.run("pset.add_pset", ifc, product=door, name="Pset_DoorCommon")
        ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset_common, properties={"Reference": ocr_text})

        # 自訂屬性集:保留 OCR 原始資訊
        pset_ai = ifcopenshell.api.run("pset.add_pset", ifc, product=door, name="Pset_AI_OCR")
        ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset_ai, properties={
            "ocr_text": ocr_text,
            "match_distance_cm": float(round(dist, 2))
        })
        summary.append(f"[{idx}] YOLO→IfcDoor({label} {door_w}x{door_h}) + OCR配對到『{ocr_text}』(距離 {dist:.1f}cm)")
    else:
        # 沒有 OCR 就只保留幾何
        summary.append(f"[{idx}] YOLO→IfcDoor({label} {door_w}x{door_h})— 無 OCR 配對")

Step4:儲存 IFC。

# 4. 輸出 IFC
ifc.write(OUTPUT_PATH)
print("✅ IFC 已輸出到:", OUTPUT_PATH)

https://ithelp.ithome.com.tw/upload/images/20250821/20177646znglvxxwbx.png
圖21.1 門物件偵測案例成果圖(OCR 轉 IFC 實測)

21.2. 結語

  今天我們完成了 YOLO + OCR 的整合應用,將物件幾何與語意標註同步轉換至 IFC,實現了從影像到 BIM 模型的自動化鏈接,這種方法能有助減少人工建模與資料輸入的時間,是滿值得投入研發的一個領域。接下來,我將以柱物件偵測為案例,驗證此流程在不同構件類型上的可行性,明天見。


上一篇
Day20:YOLO數據轉換BIM資料流案例
下一篇
Day22:單一元素建模自動化驗證
系列文
AI圖像辨識輔助的BIM資料流自動化流程30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言