@servantcdh/ez-planet-labeling-sam
v0.6.3
Published
`@servantcdh/ez-planet-labeling` 워크스페이스를 위한 브라우저 전용 Segment Anything 확장.
Readme
@servantcdh/ez-planet-labeling-sam
@servantcdh/ez-planet-labeling 워크스페이스를 위한 브라우저 전용 Segment Anything 확장.
백엔드 서버 없이 브라우저에서 직접 이미지 세그멘테이션과 자동 클래스 분류를 수행합니다.
Models
| 모델 | ID | 용도 | 크기 (q8) |
|------|-----|------|-----------|
| SlimSAM-77 | Xenova/slimsam-77-uniform | 이미지 세그멘테이션 | ~10-15 MB |
| CLIP ViT-B/16 | Xenova/clip-vit-base-patch16 | Zero-shot 클래스 분류 | ~85 MB |
모델은 첫 사용 시 Hugging Face Hub에서 다운로드되며, 브라우저 Cache Storage에 캐시됩니다.
설치
npm install @servantcdh/ez-planet-labeling-samPeer Dependencies (호스트 앱에서 설치)
| Package | Version | 용도 |
|---------|---------|------|
| @servantcdh/ez-planet-labeling | >=1.0.0 | 코어 라벨링 라이브러리 |
| react | ^18.0.0 | UI 런타임 |
| react-dom | ^18.0.0 | DOM 렌더링 |
| fabric | ^5.0.0 | 캔버스 엔진 |
| zustand | ^5.0.0 | 상태 관리 |
Bundled Dependencies (자동 설치)
| Package | 용도 |
|---------|------|
| @huggingface/transformers | ONNX Runtime Web 기반 브라우저 추론 |
기본 사용법
import {
LabelingWorkspace,
LabelingProviders,
useToolbarSubMenuItemsStore,
useExtensionFloatingPanelStore,
useImageTypeLabelingToolSelectionStore,
type ExtensionSubMenuItem,
} from "@servantcdh/ez-planet-labeling";
import { createSamExtension, createSamTool } from "@servantcdh/ez-planet-labeling-sam";
function App() {
// 1. Extension 등록
const extensions = useMemo(
() => [
createSamExtension({
policyClasses: [
{ index: 0, name: "Car", color: "#e74c3c" },
{ index: 1, name: "Person", color: "#2ecc71" },
{ index: 2, name: "Building", color: "#8e44ad" },
],
}),
],
[]
);
// 2. 툴바 서브메뉴 등록
useEffect(() => {
const items: ExtensionSubMenuItem[] = [
{
id: "demo-sam",
iconType: "icon-seg-anything",
name: "Segment Anything",
shortcut: { key: "s", label: "S" },
onClick: () => {
useImageTypeLabelingToolSelectionStore.getState().setTool(createSamTool());
useExtensionFloatingPanelStore.getState().openPanel("demo-sam");
},
},
];
useToolbarSubMenuItemsStore.getState().setItems(items);
return () => useToolbarSubMenuItemsStore.getState().clearItems();
}, []);
// 3. 워크스페이스에 전달
return (
<LabelingProviders data={dataCtx} mutations={mutationCtx} dataset={datasetCtx}>
<LabelingWorkspace extensions={extensions} />
</LabelingProviders>
);
}기능
Interactive Mode
캔버스에서 직접 프롬프트를 입력하여 세그멘테이션을 수행합니다.
| 입력 | 조작 | SAM Label |
|------|------|-----------|
| Positive point | 좌클릭 | 1 |
| Negative point | 우클릭 | 0 |
| Bounding box | 좌클릭 드래그 | 2 (좌상단) + 3 (우하단) |
포인트/박스를 추가할 때마다 디코더가 실시간으로 마스크를 생성합니다.
Auto Mode
그리드 포인트 기반 "Segment Everything" 모드.
- Grid 크기 선택 (8x8 ~ 32x32)
- Run 클릭
- Segmenting — 각 그리드 포인트에서 마스크 디코딩 + NMS로 중복 제거
- Classifying — CLIP으로 각 세그먼트를 policy 클래스에 자동 분류
- 결과 리스트에서 클래스를 드롭다운으로 수정 가능
- Apply — fabric 오브젝트에 클래스 정보(
labelInsertData) 적용
Auto 모드 실행 중 Stop 버튼으로 중단할 수 있습니다.
Apply / Reset / Close
| 동작 | 설명 | |------|------| | Apply | SAM 오브젝트를 확정 라벨로 승격 (Reset/Close에서 보존) | | Reset | 현재 프롬프트/마스크 초기화 (확정 라벨은 유지) | | Close | SAM 패널 닫기, 미확정 결과가 있으면 confirm 표시 |
Runtime 성능
WebGPU가 사용 가능하면 자동으로 활용하며, 불가 시 WASM으로 폴백합니다.
| 단계 | WebGPU | WASM | |------|--------|------| | 모델 로딩 (첫 실행, 네트워크 포함) | ~3-5s | ~5-10s | | 모델 로딩 (캐시) | ~0.5-1s | ~1-2s | | 이미지 인코딩 | ~2-4s | ~5-10s | | Interactive 디코딩 (클릭당) | ~50-100ms | ~200-500ms | | Auto 세그멘테이션 (16x16) | ~30s | ~60-120s | | CLIP 분류 (세그먼트당) | ~1-2s | ~3-5s |
Exports
Functions
| Export | 설명 |
|--------|------|
| createSamExtension(options?) | SAM LabelingExtension 생성 |
| createSamTool() | SAM 캔버스 도구 생성 (포인트/박스 캡처) |
Hooks
| Export | 설명 |
|--------|------|
| useSlimSam() | SAM + CLIP 추론 hook (모델 로딩, 인코딩, 디코딩, 자동 분류) |
| useSamStore() | SAM UI 상태 Zustand store |
Types
| Export | 설명 |
|--------|------|
| PolicyClassItem | { index, name, color } — 클래스 정보 |
| SamPrompt | { x, y, label } — 포인트/박스 프롬프트 |
| DecodedMask | Interactive 디코딩 결과 |
| AutoMask | Auto 세그멘테이션 결과 (classInfo 포함) |
| ClassInfo | { className, classIndex, confidence } — CLIP 분류 결과 |
| SamStatus | 모델 상태 (idle, loading-model, encoding, ready, decoding, auto, error) |
| SamMode | "interactive" \| "auto" |
| SamState | Zustand store 상태 타입 |
createSamExtension Options
interface CreateSamExtensionOptions {
policyClasses?: PolicyClassItem[];
}| Option | 설명 | 기본값 |
|--------|------|--------|
| policyClasses | Auto 모드에서 CLIP 분류에 사용할 클래스 목록 | [] (분류 비활성) |
policyClasses가 비어있으면 Auto 모드에서 세그멘테이션만 수행하고 분류는 건너뜁니다.
Architecture
@servantcdh/ez-planet-labeling (코어, peer dependency)
├── segmentAnythingTool() — 캔버스 포인트/박스 캡처
├── getCanvasInstance() — fabric.Canvas 접근
├── useExtensionFloatingPanelStore — 패널 열기/닫기
└── TOOL_INFO_SEGMENT_ANYTHING_* — 오브젝트 식별 상수
@servantcdh/ez-planet-labeling-sam (이 패키지)
├── createSamExtension() — LabelingExtension 정의
├── createSamTool() — 콜백 주입 래퍼
├── useSlimSam() — 추론 엔진 (SlimSAM + CLIP)
├── useSamStore() — UI 상태 관리
└── SamFloatingPanel — 패널 UI (모드 전환, 진행률, 결과)
@huggingface/transformers (런타임 dependency)
├── SamModel — SlimSAM 인코더/디코더
├── CLIPTextModelWithProjection — 텍스트 임베딩
├── CLIPVisionModelWithProjection — 이미지 임베딩
└── AutoProcessor / AutoTokenizer — 전처리호스트 앱의 기존 SAM과 공존
호스트가 자체 SAM 구현(예: 백엔드 API 기반)을 가지고 있는 경우, Extension ID가 다르므로 양쪽 모두 등록할 수 있습니다.
import { createSamExtension as createBrowserSam } from "@servantcdh/ez-planet-labeling-sam";
import { createSamExtension as createApiSam } from "./my-api-sam";
const extensions = [
createBrowserSam({ policyClasses }), // id: "demo-sam"
createApiSam(), // id: "my-api-sam"
];License
This software is licensed under a custom license. See LICENSE for the full text.
본 소프트웨어는 커스텀 라이선스가 적용됩니다. 한글 라이선스는 LICENSE.ko를 참조하세요.
