延續昨天的實作,今天要繼續以實作的程式碼,將文字辨識結果也納入BIM模型資訊中,我們一起來看一下整個流程與步驟。
首先,一樣開啟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)
圖21.1 門物件偵測案例成果圖(OCR 轉 IFC 實測)
今天我們完成了 YOLO + OCR 的整合應用,將物件幾何與語意標註同步轉換至 IFC,實現了從影像到 BIM 模型的自動化鏈接,這種方法能有助減少人工建模與資料輸入的時間,是滿值得投入研發的一個領域。接下來,我將以柱物件偵測為案例,驗證此流程在不同構件類型上的可行性,明天見。