Getting started
1. 환경 설정
소스 코드를 준비합니다.
Python 3.11.9로 conda 환경을 생성합니다.
아래의 명령어로 dependencies를 설치합니다.
SaigeToolkit은 사내 패키지 색인에서 받으므로 설치는 사내망에서 진행합니다. 허용하는 SaigeToolkit 버전 범위는 requirements/common.txt에 있습니다.
제품은 Windows에서 구동합니다. 온보딩과 스캔 식별(identify_scan)은 렌더링에 GL context가 필요하므로, 원격 셸이나 Windows 서비스가 아닌 로그온된 데스크톱 세션에서 실행합니다. 온보딩과 추론의 연산 device 기본값은 cuda:0입니다.
2. 리소스 다운로드
필요한 모델 weight 번들을 다운로드합니다.
python -c "from core.util.weight_bundle import check_and_download_weights; check_and_download_weights()"
번들은 core/resource/deploy에 저장되며, 이미 있는 번들은 다시 다운로드하지 않습니다.
3. Python API 테스트
API 테스트로 소스 코드와 환경이 올바르게 설정되었는지 확인합니다.
마지막 줄에 failed 없이 passed가 출력되면 정상입니다. 테스트는 합성 부품을 온보딩한 뒤 이미지 식별과 스캔 검사까지 두 handler의 public 메서드를 모두 호출합니다.
4. 라이브러리 빌드 & API 테스트
원하는 경로에 3D Inspection 라이브러리를 빌드합니다. 예제에서는 deploy 폴더를 사용합니다. 지정한 폴더가 이미 있으면 삭제한 뒤 빌드합니다.
빌드 결과에는 모델 weight 번들과 THIRD_PARTY_NOTICES.md, licenses 폴더가 함께 포함됩니다.
빌드된 바이너리 라이브러리로 API 테스트를 진행합니다.
마지막 줄에 failed 없이 passed가 출력되면 정상입니다.
5. 빌드된 라이브러리 사용
빌드 폴더를 module 검색 경로에 추가한 뒤 core를 import해 필요한 기능을 사용합니다.
각 기능의 설명은 API reference에 있습니다.
6. 데모 코드
API로 CAD 부품을 온보딩하고 이미지로 부품을 식별하는 예제입니다.
import cv2
import numpy as np
from core import InferenceHandler, OnboardHandler
from core.data.catalog.catalog_data import CatalogData, CatalogEntry
err, msg, onboarder = OnboardHandler.build({"device": "cuda:0"})
parts = []
# part_id는 호출자가 부여하는 int입니다.
for part_id, path in {1024: "/cad/bracket.stp"}.items():
err, msg, record = onboarder.onboard(path)
if err < 0:
continue # 실패한 부품만 제외하고 다음 부품을 진행합니다.
parts.append(CatalogEntry(part_id=part_id, record=record))
err, msg, handler = InferenceHandler.build({"device": "cuda:0"})
err, msg, _ = handler.set_catalog(CatalogData(catalog_id="v0001", parts=parts))
err, msg, _ = handler.warmup()
# cv2.imread는 Windows에서 비 ASCII 문자가 있는 경로의 파일을 읽지 못하므로 파일 내용을 읽어 decode합니다.
image = cv2.imdecode(np.fromfile("front.jpg", dtype=np.uint8), cv2.IMREAD_COLOR)
# 이미지는 RGB uint8 [H, W, 3] 배열로 전달합니다.
images = [cv2.cvtColor(image, cv2.COLOR_BGR2RGB)]
# candidate마다 part_id, score, matched_view_indices가 있습니다.
err, msg, result = handler.identify_images(images)
3D 스캔을 검사하는 예제입니다. catalog는 위 예제와 같이 조립한 CatalogData이고, parts는 그 CatalogEntry 목록입니다.
err, msg, handler = InferenceHandler.build({"device": "cuda:0"})
err, msg, _ = handler.set_catalog(catalog)
err, msg, scan = handler.prepare_scan("scan.stl")
# 바닥 평면 (nx, ny, nz, d)이며 단위는 mm입니다. 바닥을 검출하지 못하면 None입니다.
print(scan.floor_plane)
err, msg, ident = handler.identify_scan(scan)
# score 내림차순으로 정렬된 part_id 목록입니다.
print([candidate.part_id for candidate in ident.candidates])
# top-1 candidate를 검사합니다. 호출자가 이미 아는 부품의 geometry를 전달해도 됩니다.
geometry = {part.part_id: part.record.geometry for part in parts}
err, msg, result = handler.inspect_scan(scan, geometry[ident.candidates[0].part_id])
# 4x4 부품 → 스캔 pose이며 단위는 mm입니다.
print(result.registration.transform)
# 차순위 pose 후보 점수에서 채택 pose 점수를 뺀 값입니다.
print(result.registration.runner_up_margin)
# 스캔 삼각형별 부호 있는 표면 편차이며 단위는 mm입니다.
print(result.deviation.distances_mm)
호출 순서와 반환 값 규약은 API reference에 있습니다.