
SAM 3D로 이미지 1장에서 3D 모델 생성하기: 제조업 부품의 3D화 검증
요약
Meta의 SAM 3D를 활용하여 단일 이미지로부터 3D 모델을 생성하는 파이프라인을 구현하고, 제조업 부품의 3D화 가능성을 검증합니다. SAM 3를 이용해 정교한 마스크를 생성한 뒤 SAM 3D Objects에 입력하는 것이 정밀도 확보의 핵심입니다.
핵심 포인트
- SAM 3D는 이미지 1장에서 3D 재구성을 수행하는 기술임
- SAM 3D Objects는 일반 물체 재구성에, SAM 3D Body는 인체 형상 추정에 특화됨
- 정밀한 재구성을 위해 SAM 3를 이용한 사전 마스크 준비가 필수적임
- 출력물은 Gaussian Splatting 형식을 지원하며 메쉬 변환이 가능함
「오래된 설비의 부품 도면이 남아있지 않고 사진밖에 없다」 「파손된 부품의 대체품을 발주하고 싶지만, 치수를 알 수 있는 도면이 없다」 —— 제조업 현장에서는 이러한 「물건은 있지만 도면이 없는」 상황이 상상 이상으로 많이 발생합니다.
지난 기사 「SAM 3 vs SAM 2: 비디오 추적 파이프라인 비교 구현」에서 다루었던 SAM 3의 세그멘테이션 (Segmentation) 기술은, 2025년 11월 Meta사가 발표한 「SAM 3D」를 통해 이미지 1장에서 3D 모델을 생성하는 기술까지 발전했습니다.
본 기사에서는 SAM 3D를 사용하여 사진으로부터의 3D 재구성 (Reconstruction) 파이프라인을 구현하고, 「제조업 부품의 3D화에 어디까지 사용할 수 있는가」를 치수 정밀도의 관점에서 검증합니다.
SAM 3D의 구성
SAM 3D는 SAM 3의 오픈 보캐블러리 세그멘테이션 (Open-vocabulary Segmentation)과 기하학적 형상·텍스처·공간 배치를 예측하는 생성 모델을 결합한 기술입니다. 용도별로 두 가지 모델이 제공됩니다.
SAM 3D Objects: 일반적인 물체·장면의 재구성을 대상으로 함 -
SAM 3D Body: 인체의 자세·형상 추정에 특화 (70개의 신체 키포인트 검출, 애니메이션 대응 GLB 메쉬를 출력)
제조업 부품의 3D화에는 SAM 3D Objects를 사용합니다. 오클루전 (Occlusion, 다른 물체에 가려진 부분)이나 어지러운 배경이 있어도 재구성할 수 있도록 설계되어 있으며, 기존의 단일 이미지 3D 재구성 수법과의 비교에서 5:1의 선호율 (인간 평가자가 SAM 3D의 출력을 선택한 비율)이 보고되었습니다.
셋업과 추론 파이프라인
먼저 환경을 구축합니다. SAM 3 계열의 모델은 전용 환경 분리가 필요합니다.
mamba env create -f environments/default.yml
mamba activate sam3d-objects
export PIP_EXTRA_INDEX_URL="https://pypi.ngc.nvidia.com https://download.pytorch.org/whl/cu121"
...
추론은 「대상의 마스크를 준비한다」 → 「SAM 3D로 재구성한다」라는 2단계로 이루어집니다. 마스크는 SAM 3 (지난 기사에서 다룬 검출기)로 사전에 생성합니다.
import sys
sys.path.append("notebook")
from inference import Inference, load_image, load_single_mask
...
출력은 Gaussian Splatting 형식 (.ply) 입니다. 3D 프린터로의 조형이나 CAD 툴과의 연계를 상정하는 경우에는 메쉬 (Mesh) 형식 (.glb나 .obj)으로 변환하는 후처리를 거칩니다.
나쁜 예: 여러 대상이 찍힌 이미지를 마스크 없이 그대로 전달하는 경우
# 나쁜 예: 마스크를 준비하지 않고 배경까지 통째로 재구성하려고 시도함
output = inference(image, mask=None, seed=42)
마스크를 주지 않으면 SAM 3D는 배경이나 다른 물체까지 포함하여 재구성하려고 시도하며, 대상 부품의 형상 정밀도가 크게 떨어집니다. 반드시 대상만을 잘라낸 마스크를 사전에 준비하는 것이 실무상의 철칙입니다.
좋은 예: SAM 3로 대상을 검출한 후 마스크를 전달하는 경우
from sam3.build_sam3 import build_sam3_image_model
sam3_model = build_sam3_image_model(checkpoint="checkpoints/sam3.1_image.pt")
processor = Sam3Processor(sam3_model)
...
SAM 3의 검출 결과를 그대로 SAM 3D Objects의 입력으로 전달함으로써, 대상의 추출을 수동으로 마스크 편집하는 수고를 덜 수 있습니다.
스케일을 교정하기: 단위가 없는 Gaussian Splat의 함정
간과하기 쉽지만 가장 중요한 주의점이 있습니다. SAM 3D가 출력하는 Gaussian Splat에는 실세계의 단위 (mm·cm 등)가 포함되어 있지 않습니다. 재구성 결과는 어디까지나 「상대적인 형상」이며, 그대로는 「폭 85mm」와 같은 절대 치수를 알 수 없습니다.
나쁜 예: 출력을 그대로 실측치로 취급하는 경우
나쁜 예: 재구성 결과의 바운딩 박스(Bounding Box)를 그대로 mm 단위로 취급하는 경우
dimensions = measure_reconstructed_dimensions("gate_valve_part_splat.ply")
print(f"이 부품의 폭은 {dimensions['width']}mm입니다") # 단위에 대한 보장 없이 단정 지어 버림
좋은 예: 기지의 치수를 가진 기준 물체를 함께 촬영하여 스케일을 교정하는 경우
def calibrate_scale(mesh, reference_object_pixel_length: float, reference_object_real_length_mm: float) -> float:
"""이미지 내에 함께 찍힌 기준 물체(자, 기지의 치수를 가진 동전 등)를 사용하여, 재구성 결과를 실측치로 변환하는 스케일 계수를 구함"""
scale_factor = reference_object_real_length_mm / reference_object_pixel_length
...
촬영할 때마다 대상과 함께 치수를 알고 있는 기준 물체(자, 기지의 크기를 가진 동전 등)를 동일 프레임 내에 포함시키는 것을 운용 규칙으로 정하십시오. 이를 소홀히 하면, 재구성된 3D 모델이 "외형적인 형상은 맞지만, 실측치로서는 아무것도 보장되지 않는" 상태가 되어, 앞 절에서 언급한 치수 정밀도 검증 자체가 성립하지 않게 됩니다.
제조업 부품의 3D화: 치수 정밀도를 검증하기
여기서부터가 본론입니다. "그럴싸해 보이는 3D 모델이 만들어졌다"는 것과 "제조·발주 판단에 사용할 수 있는 치수 정밀도가 있다"는 것은 완전히 다른 기준입니다. 실제로 검증해 보겠습니다.
import numpy as np
import trimesh
def measure_reconstructed_dimensions(ply_path: str) -> dict:
...
여러 부품으로 동일한 검증을 수행했을 때 실무상의 경향은 다음과 같은 결과가 나오는 경우가 많습니다 (촬영 조건 및 부품 형상에 따라 변동되므로, 반드시 자사의 대상 부품으로 검증하십시오).
| 부품 형상 | 오차 경향 |
|---|---|
| 단순한 형상 (상자형·원통형) | 수 % 정도로 수렴하기 쉬움 |
| ... |
검증 결과로부터의 결론: 어디까지 사용할 수 있는가
치수 정밀도 검증 결과를 바탕으로, SAM 3D의 제조업 부품 3D화에 있어서의 실무적 위치는 다음과 같이 정리할 수 있습니다.
적합한 용도: 형상 파악 · 도면이 없는 부품의 개관 확인 · 3D 프린터를 이용한 시제품 참고 · AR을 이용한 배치 시뮬레이션 · 파손 부품의 대략적인 형상 기록
적합하지 않은 용도: 제조·발주를 위한 정밀한 치수 산출 · 공차(Tolerance)가 필요한 기계 가공의 기준 데이터 · 단일 이미지만을 이용한 고정밀 역설계 (Reverse Engineering)
판단의 근거: "이 3D 모델의 치수가 어긋났을 때, 어떤 손해가 발생하는가"를 기준으로 생각합니다. 시제품의 외형 확인이라면 수 %의 오차는 허용 범위이지만, 발주 도면 대신 사용하려 한다면 어떠한 오차도 허용할 수 없습니다.
"사진 한 장으로 정확한 도면을 뽑아낼 수 있다"는 기대는 현시점의 기술 수준에서는 과도합니다. 반면, "도면이 완전히 유실된 부품의 대략적인 형상을 빠르게 파악한다"는 용도로는 충분히 실용적입니다. 정밀한 치수가 필요한 상황에서는 3D 스캐너(구조광·레이저)를 이용한 실측과 조합하는 하이브리드 운용이 현실적인 타협점이 됩니다.
def recommend_workflow(precision_requirement: str) -> str:
"""요구 정밀도에 따라 SAM 3D를 사용해야 할지, 3D 스캐너를 사용해야 할지를 판단함"""
if precision_requirement == "rough_visualization":
...
메쉬(Mesh) 형식으로의 변환
Gaussian Splat (.ply)는 그대로는 일반적인 CAD 툴이나 3D 프린터용 소프트웨어에서 다루기 어렵기 때문에, 메쉬 형식 (.glb, .obj)으로 변환합니다.
import trimesh
def convert_splat_to_mesh(ply_path: str, output_path: str) -> None:
"""Gaussian Splat을 폴리곤 메쉬로 변환하여 일반적인 3D 형식으로 내보냄"""
...
convex_hull
는 가장 단순한 변환 방법으로, 오목한 형상의 부품에서는 정확한 표면을 재현할 수 없습니다. 실무에서는 Open3D나 PyMeshLab이 제공하는 Poisson surface reconstruction과 같은 더 고도화된 표면 재구성 (Surface Reconstruction) 알고리즘을 사용하는 것을 권장합니다.
촬영 조건 체크리스트
재구성 정밀도는 촬영 조건에 크게 좌우됩니다. 운용 규칙으로서 체크리스트화해 두면, 현장에서의 촬영 품질 편차를 억제할 수 있습니다.
def validate_photo_conditions(image_path: str) -> list[str]:
"""촬영 조건의 간이 체크 (실제로는 CV 처리를 통해 자동 판정하는 항목도 포함)"""
warnings = []
...
이 체크 함수는 간이적인 것이지만, 현장의 촬영 담당자에게 스마트폰 앱을 통해 즉각적으로 피드백을 돌려주는 메커니즘에 포함시키면 촬영 재작업을 대폭 줄일 수 있습니다. 촬영 후 사무실로 돌아와서 "너무 어두워서 재구성할 수 없다"는 사실을 깨닫는 비용은, 현장에서의 즉시 체크에 비해 몇 배나 더 큽니다.
체크리스트의 요점은 다음과 같습니다.
- 충분한 밝기에서 촬영할 것 (음영이 너무 강하면 형상 추정에 오류가 생기기 쉬움)
- 배경을 가능한 한 단순하게 할 것 (SAM 3의 마스크 정밀도에 영향을 미침)
- 반사가 강한 금속면은 가능하다면 무광 스프레이나 매트한 소재로 덮어서 촬영할 것
- 기지 치수의 기준 물체를 반드시 동일 프레임에 넣을 것 (앞서 언급한 스케일 교정(Scale Calibration)을 위해)
- 가능하다면 여러 각도에서 촬영하여 뒷면 및 측면 정보를 남겨둘 것
3D 스캐너 투자와의 비교 시산
앞서 언급한 바와 같이, 촬영 빈도가 높은 경우에는 스캐너 투자가 현실적이 됩니다. 판단을 숫자로 뒷받침하기 위한 시산 코드입니다.
def compare_sam3d_vs_scanner_cost(
monthly_parts_count: int, sam3d_hours_per_part: float, scanner_purchase_cost: float,
scanner_hours_per_part: float, hourly_labor_cost: float, months: int = 24,
...
이 시산은 어디까지나 노무비 비교에 그칩니다. 스캐너 투자 판단에는 치수 정밀도가 애초에 SAM 3D로는 충족할 수 없는 요구 수준인가라는, 비용과는 독립된 기준도 잊지 말고 포함해 주세요. 비용 측면에서만 SAM 3D가 더 저렴하다는 결과가 나오더라도, 요구 정밀도를 만족할 수 없다면 선택지에서 제외됩니다.
여러 부품의 배치 처리 (Batch Processing)
재고 부품을 일괄적으로 3D화하고 싶은 경우, 여러 이미지를 한꺼번에 처리하는 배치 파이프라인 (Batch Pipeline)을 구축합니다.
def batch_reconstruct_parts(part_records: list[dict], output_dir: str) -> list[dict]:
"""여러 부품의 이미지와 마스크를 모아서 3D 재구성하고 결과를 기록함"""
results = []
...
나쁜 예: 1건씩 수동으로 실행하며, 실패해도 알아차리지 못함
# 나쁜 예: 배치 처리를 1건씩 수동 실행하며, 에러 처리나 로그도 없음
for record in part_records:
output = inference(load_image(record["image_path"]), load_single_mask(record["mask_path"], 0))
...
배치 처리에서는 1건의 실패가 전체를 중단시키지 않도록 예외 처리 (Exception Handling)를 반드시 포함하고, 성공 및 실패 건수를 마지막에 집계해야 합니다. 수십~수백 건 규모의 재고 부품을 일괄 처리하는 운용에서는 이러한 실패 허용 설계가 없으면, 원인 조사에 많은 시간을 빼앗기게 됩니다.
SAM 3D Body와의 용도 구분
사람이 찍힌 현장 사진 (작업자의 자세 확인, 안전 교육 용도 등)에서는 SAM 3D Objects가 아니라 인체 전용인 SAM 3D Body를 사용합니다. 70개의 신체 키포인트 (Keypoints)를 검출하고, 애니메이션 대응이 가능한 GLB 메쉬와 스켈레탈 리깅 (Skeletal Rigging)을 직접 출력하기 때문에, 자세 분석이나 안전 교육 콘텐츠의 3D화에는 이쪽이 적합합니다. 부품의 3D화와는 목적도 모델도 다르므로, 대상이 사람인지 물건인지에 따라 명확하게 구분하여 사용하십시오.
한 장의 사진에 작업자와 부품이 모두 찍혀 있는 경우에는, SAM 3로 인물과 부품을 각각 별개의 마스크 (Mask)로 검출한 뒤, 인물에는 SAM 3D Body, 부품에는 SAM 3D Objects라는 형태로 대상에 따라 적합한 모델로 배분하는 파이프라인을 구축해야 합니다.
다각도 촬영을 통한 정밀도 향상
단일 이미지에서의 재구성 (Reconstruction) 정밀도에 한계가 있는 경우, 여러 각도에서 촬영한 이미지를 사용하여 각각의 재구성 결과를 통합하는 접근 방식을 검토할 수 있습니다.
def reconstruct_from_multiple_angles(image_paths: list[str], mask_paths: list[str]) -> list:
"""여러 각도의 이미지로부터 개별적으로 재구성한 후 나중에 통합한다 (SAM 3D 자체는 단일 이미지용이므로, 다시점 통합은 별도 구현이 필요함)"""
results = []
...
SAM 3D 자체는 단일 이미지를 전제로 설계되었기 때문에, 다시점 통합 (점군 (Point Cloud)의 정렬 및 병합)은 별도의 포토그래메트리 (Photogrammetry)적인 후처리를 구축해야 합니다. 이 통합 비용과 전용 3D 스캐너를 도입하는 비용을 비교하여, 촬영 빈도가 높은 경우 (매달 다수의 부품을 3D화하는 경우)에는 스캐너 투자를, 단발적인 용도라면 SAM 3D의 단일 이미지 운용을 선택하는 것이 현실적입니다.
판단이 어려울 경우에는 먼저 단일 이미지 운용을 소규모로 시도해 보고, 실제로 몇 건의 부품에서 정밀도 부족으로 인한 재작업이 발생하는지를 기록한 후 스캐너 투자 여부를 판단하는 순서를 권장합니다. 도입 비용을 먼저 산출하기보다, 실제 실패율을 몇 건 정도 수집한 뒤에 판단하는 것이 투자 대비 효과 (ROI)를 설명하기에 더 수월합니다.
추론의 GPU 메모리 요구사항 및 실행 비용
SAM 3D Objects의 추론은 SAM 3의 검출 모델과 3D 재구성 모델의 2단계를 거치기 때문에, 단순한 세그멘테이션 (Segmentation) 태스크보다 GPU 메모리 소비가 더 큽니다. 배치 처리 (Batch Processing)를 본격적으로 운용하기 전에 실제 GPU 사용량을 실측해 두어야 합니다.
def monitor_gpu_memory_during_batch(part_records: list[dict], output_dir: str) -> dict:
"""배치 처리 중 피크 (Peak) GPU 메모리 사용량을 기록한다"""
import torch
...
나쁜 예: 1건만 테스트해서 문제가 없었으므로, 그대로 대량 배치를 실행하는 경우
# 나쁜 예: 1건의 추론이 GPU 메모리에 들어가는 것만 확인하고,
# 수백 건의 배치 처리에서도 동일한 여유가 있을 것이라고 착각하는 경우
for record in large_part_catalog: # 500건 규모
...
추론을 반복하는 루프 안에서 이전 출력값 (Gaussian Splat의 텐서 (Tensor))에 대한 참조가 계속 남아 있으면, GPU 메모리가 서서히 압박받을 수 있습니다. 배치 처리 시에는 각 이터레이션 (Iteration) 후에 명시적으로 메모리를 해제하는 처리를 넣거나, 일정 건수마다 프로세스 자체를 재시작하는 방식으로 운용하면 안정적입니다.
import gc
import torch
def reconstruct_with_memory_cleanup(record: dict) -> dict:
...
부품 카탈로그 및 PLM 시스템과의 연계
3D화된 결과는 단일 파일로 방치하지 말고, 기존의 부품 관리 시스템 (PLM: Product Lifecycle Management)이나 카탈로그 데이터베이스에 연결해야 비로소 업무적 가치가 생깁니다.
def register_reconstructed_part_to_catalog(part_id: str, ply_path: str, glb_path: str, dimensions: dict, catalog_db) -> dict:
"""재구성한 3D 모델을 치수 정보 및 신뢰도 플래그와 함께 부품 카탈로그에 등록한다"""
record = {
...
}
나쁜 예: AI 재구성 치수를 실측값과 구분하지 않고 카탈로그에 등록하는 경우
# 나쁜 예: SAM 3D로 재구성한 치수를 노기스(Vernier Caliper)로 측정한 실측값과 동일하게 취급하여 카탈로그에 등록하는 경우
catalog_db.upsert({"part_id": part_id, "dimensions_mm": reconstructed_dims})
# 나중에 이 레코드를 보는 다른 담당자가 실측값으로 오해하여 발주 도면에 전기할 위험이 있음
카탈로그에 등록할 때, 해당 치수 정보가 '실측값'인지 'AI 재구성(AI reconstruction)에 의한 개략값'인지를 데이터 자체에 명시해 두는 것이 필수적입니다. 구분 없이 등록하면, 시간이 흐른 뒤 다른 담당자가 이 수치를 실측값으로 오해하여 발주나 제조 판단에 사용하게 될 리스크가 남습니다. dimension_source
와 같은 필드를 필수 항목으로 지정하고, UI나 리포트 상에서도 시각적으로 구분할 수 있도록 설정해 두어야 합니다.
요약
SAM 3D는 도면을 분실한 부품의 형상을 빠르게 파악할 수 있는 강력한 도구이지만, 제조 및 발주 판단에 사용할 수 있는 치수 정밀도는 현 시점에서 보장되지 않습니다. '외관이 보기 좋은 3D 모델'과 '치수로서 신뢰할 수 있는 3D 모델'을 혼동하지 않고, 용도에 따라 SAM 3D와 기존의 3D 스캐너를 구분하여 사용하는 것이 실무에서의 올바른 도입 판단입니다.
도입을 검토할 때는 우선 자사에서 다루는 대표적인 부품 형상(단순 형상 및 복잡 형상 각각 수 점)에 대해 본 기사의 치수 검증 파이프라인을 테스트하여, 허용 가능한 오차 범위 내에 들어오는지 확인한 후 실제 업무 흐름(부품 카탈로그 작성, 결품 부품 기록 등)에 편입시키는 순서를 권장합니다. 스케일 교정(Scale calibration)을 운영 규칙으로 철저히 준수하는 것이 검증 결과의 신뢰성을 좌우하는 가장 큰 요인입니다.
다음 회차에서는 Gemini 계열의 이미지 생성 모델 Nano Banana Pro/2를 API를 통해 제어하는 방법을 다룹니다.
Discussion

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기