좌충우돌 마카오 현지 통합유심 직접 개통 및 헝친 포트 육로 입국기 (2026.05.07)

 

여행의 진짜 묘미는 생각지도 못했던 예상 밖의 경험에서 온다는 것을, 지난 수십번의 여행을 통해 뼈저리게 느껴왔습니다. 저에게 있어서도 여행의 즐거움은 바로 이런 변수에서 오는 것이 아닌가 싶습니다.

 

 하지만! 철저하게 세워둔 계획이 계속 어긋나기 시작하면, 즐거워야 할 여행이 순식간에 '깊은 빡침'으로 다가오기도 합니다. 특히 J성향이 강한 분들이라면 그 허무함과 당혹감이 얼마나 크게 다가오는지 격하게 공감하실 겁니다.

 

 이번 여행기에서는 마카오 현지에 도착하자마자 마카오 홍콩 중국 본토에서 모두 사용할 수 있는 로걸 유심을 개통하며 겪었던 좌충우돌 생존기를 다루어보려고 합니다. 제미나이조차 결코 알려주지 않는 여행 블로거의 피, 땀, 눈물이 섞인 생생한 경험담을 통해 여러분들께서는 더 완벽한 마카오 여행 준비하시길 바랍니다!

 

 

여행 준비에 있어 어쩌면 가장 중요한 결정 중 하나는 단연 '스마트폰 데이터를 어떻게 해결할 것인가'입니다. 저는 보통 3가지를 방법을 고려합니다.

 

 

첫 번째로 가장 편한 방법은 내 번호 그대로 해외에서 로밍 서비스를 이용하는 것입니다. 유심을 굳이 교체할 필요가 없다는 점이 가장 큰 장점입니다. 게다가 최근에는 로밍 요금이 합리적이라 과거처럼 요금 폭탄 맞을까 전전긍긍하지 않아도 되지요.

 

 단점이라면 알뜰폰 통신사를 사용하고 계신 분들의 경우 로밍 서비스가 제한되거나 특정 요금제만 지원해서 원하는 만큼 넉넉하게 쓰기 어렵습니다.

 

 

두 번째 방법은 데이터 전용 유심을 출국 전에 미리 구매하여 현지에서 개통하는 방법입니다. 제가 가장 애용하는 방법 중 하나이고, 제류 기간과 데이터 용량으 내 맘대로 조합할 수 있습니다.

 

다만 데이터 외에 문자나 통화는 아예 불가능한 경우가 태반이고, 저가형 유심의 경우 중국 통신사인 CMLink 망을  거치면서 속도가 훅 떨어지는 불상사가 발생하기도 합니다.

 

 

 세 번째 방법은 현지 통신사의 Local SIM을 사용하는 방법입니다. 로밍을 사용할 경우 데이터가 무조건 한국을 통과하다보니 현지에서 운영하는 웹사이트 조차 한국을 거쳐서 접속하기 때문에 한국의 데이터센터에 접속하는 경우를 제외하고는 속도가 굉장히 느려집니다. 특히 호주같이 광활한 곳에서는 데이터 딜레이 때문에 긴급 연락이 안 돼서 애를 먹기도 하지요.

 

 

 반면, Local SIM을 사용할 경우 현지 통신사 망에 바로 붙기 때문에 비교할 수 없는 쾌적한 속도를 자랑합니다.

 

 단점이라면, 한국에서 여행지의 SIM카드를 구하기 어려울 경우 현지에 직접 도착해서 개통해야 합니다. 대개 공항에 통신사 부스가 있어 직원들이 바로 개통까지 진행해줍니다만...

 

 

 마카오의 경우 공항 규모가 작아 통신사 직원이 상주하지 않고, 대신 공항 1층에 있는 자동판매기에서 구매할 수 있다고 합니다.

 

 

마카오공항에 도착하고 입국장 1층으로 나오면 바로 자판기들을 발견할 수 있습니다. 중국 본토의 통신사인 차이나텔레콤과 마카오 통신사인 마카오통신(CTM)의 유심 자판기가 나란히 서 있지요.

 

 

 유심은 보통 3가지 커버리지(마카오/홍콩, 마카오/중국 본토, 3개 지역 통합)로 나뉘어 있고, 이미 유심이 있다면 충전용 카드만 살 수도 있습니다.

 

 

 여행 전 제미나이에게 물어보니 CTM의 경우 중국 본토에서 사용을  원할 경우 중간에 있는 100 파타카짜리를 사용하라고 친절하게 알려주네요. 

 

 

 자판기에 분명 홍콩달러(HKD) 사용 가능이라고 적혀있길래, 당당하게 인천공항에서 환전해온 100 홍콩달러 지폐를 밀어 넣었습니다. 그런데...

 

 

 이상하게도 제가 갖고 온 100 홍콩달러가 먹히지 않는 것입니다!! 뱉어내고, 펴서 다시 넣고, 다른 지폐를 넣어봐도 이 녀석은 제가 가진 홍콩달러르 철저하게 무시했습니다. 공항에 도착하자마자 빛의 속도로 로컬 윳미을 개통하려던 제 계획은 여기서부터 와장창 깨졌습니다.

 

 

 자판기와 씨름하며 귀한 여행 시간 1시간을 공항에서 낭비하고 나서야, 결국 공항 무료 Wi-Fi애 의존해 시내에서 유심을 구하는 방법을 검색한 뒹 서둘러 호텔 셔틀버스에 몸을 실었습니다.

 

 

 무료 셔틀버슬를 타고 일단 '갤럭시 호텔 마카오'로 대피했습니다.

 

 

 다행히도 호텔 내부에서는 무료 Wi-Fi가 잡히길래 구글 지도를 켜고 인근 편의점을 수색하기 시작했습니다.

 

 

 갤럭시 호텔 마카오에서 도보 10분 거리에 세븐일레븐과 서클케이가 있습니다. 조금 더 걸어서 서클케이에 도착했는데 세상에! 구세주처럼 차이나텔레콤 유심이 걸려있는 것을 발견했습니다!

 

 

 편의점 직원에게 파란색 유심팩과 홍콩달러를 보여주니 눈치 빠른 직원분께서 "환불 불가"를 쿨하게 안내하며 결제를 도와주셨습니다.

 

 

 천신만고 끝에 현지 유심을 손에 넣었다는 기쁨에 취해 다시 호텔 로비로 돌아와 포장을 뜯은 순간...

 

 

 세상에나, 유심핀이 없다니!!

 

 올해 초 호주 편의점에서 샀을 때는 동봉되어 있었는데, 차이나텔레콤 유심팩은 너무나도 정직하게 유심만 덩그러니 들어있었습니다...

 

 제미나이 신께 도움을 청해보니, 다음과 같은 (당장 쓸모없는) 조언을 해줍니다.

 

"맥도날드 내 게시판에 있는 클립을 펴서 써보세요!"
"호텔 로비 직원에게 빌려보세요!"
"근처 휴대폰 수리점에 가보세요!"

 

 

 이럴 땐 AI도 실질적인 도움이 안 됩니다. 그럴 듯 하지만 당장 실행하기엔 애매한 선택지들 뿐이었지요. 혹시나 주변에 통신사 대리점이 있을까 싶어 구글지도에 mobile을 검색했더니 놀랍게도 갤럭시 호텔 마카오 내에 애플스토어가 있다는 것이었습니다!!!

 

 

 뒤도 돌아보지 않고 호텔로 달려가 애플스토어 직원분께 간절하고 아련한 눈빛을 발사하며 "유심 오프너!" 라고 부탁했습니다. 직원분은 자비로운 미소와 함께 주머니에서 유심핀을 꺼내 시원하게 찔러주셨습니다!

 

 입국 3시간만에  드디어첫 번째 목표를 간신히 달성했습니다. 마음은 급했지만, 차분히 자리에 앉아 여권으로 비대면 신분 증명까지 마치고서야 바로 다음 일정을 시작할 수 있었습니다.

 

 

  유심 개통에 예상치 못한 시간을 너무 삣긴 탓에, 과감하게 마카오 시내 일정을 생략하고 바로 중국 본토로 넘어가기로 했습니다. 

 

 

목적인 '치멜롱 오션파크'로 가기 위해 가장 동선이 효율적인 헝친 포트(横琴口岸)로 항했습니다.

 

 

헝친 포트는 마카오 코타이 지역 너머에 있어, 이렇게 중국 영토 위로 고가도로가 시원하게 이어져 있습니다. 

 

 

헝친 포트 건물에도 호텔 셔틀버스 정류장이 잘 마련되어 있어 접근성이 아주 좋습니다.

 

 

 건물 안으로 들어가 직원분께 외국인이라고 말하면 도착 카드(Arrival Card)를 작성하는 곳으로 친절하게 안내해 줍니다. 카드를 작성하고 나면 바로 마카오 출국 및 중국 입국 절차가 진행되는데요.

 

 여기서 헝친 포트의 엄청난 장점이 드러납니다! 유명한 궁베이 국경은 마카오 측 건물과 중국 측 건물이 따로 있어 출입국에 1시간 이상 걸린다고 하지요. 하지만 헝친 포트는 하나의 테이블에 마카오 직원과 중국 직원이 나란히 앉아 있습니다. 여권 한 번만 내밀면 출국과 입국 수속이 원스톱으로, 그것도 10분 만에 초고속으로 끝납니다!

 

 

 입국 심사를 마치고 중국 측으로 걸어 나오니 드넓은 광장에 펄럭이는 오성홍기가 비로소 이 곳이 중국 본토임을 실감나게 해줍니다.

 

 

마카오 방향을 돌아보니, 궁베이와는 비교도 안 되는 쾌적함에 루트 하나는 기가 막히게 짰다며 스스로 칭찬했습니다.

 

 

 국경 근처에 지어진 저 독특한 호텔은 마카오의 상징적인 '그랜드 리스보아' 호텔을 묘하게 의식한 듯한 나무 모양 디장니이 인상적이었습니다.

 

 

 매콤하고 쫄깃한 뱡뱡면 면발을 후루룩 넘기며 파란만장했던 마카오 첫날을 든든하게 마무리 했습니다.

 

 결론

 

 속도 빠른 로컬 유심이 꼭 필요하신 분들은 만약의 사태를 대비해서 숙소 근처 서클케이 편의점 위치를 미리 확인해 두세요.(그리고 옷핀이나 유심핀 챙겨가기 필수!!)

 

 전화나 문자는 필요 없고 오직 데이터만 터지면 된다 하시는 분들은 속 편하게 한국에서 미리 데이터 유심을 사 오시는 것을 추천드리며 글을 마칩니다 :)

300x250

Anaconda 환경에서 'ModuleNotFoundError: No module named 'pkg_resources' 에러 발생시 해결방법

공대생의 팁 2026. 4. 4. 15:11

 

 Anaconda에 새로운 환경을 구축하다보면 다양한 상황에 부딫치기 마련입니다. 이번에 조금 옛날이 3년전에 구축했던 환경을 다시 만들어보고자 하는데 아래와 같은 에러가 발생했습니다.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
File "D:\miniconda3\envs\torch2.1.2\Lib\site-packages\mmengine\runner\runner.py", line 462in from_cfg
    runner = cls(
             ^^^^
 
File "D:\miniconda3\envs\torch2.1.2\Lib\site-packages\mmengine\runner\runner.py", line 403in __init__
    self._log_env(env_cfg)
File "D:\miniconda3\envs\torch2.1.2\Lib\site-packages\mmengine\runner\runner.py", line 2368in _log_env
    env = collect_env()
          ^^^^^^^^^^^^^
 
File "D:\miniconda3\envs\torch2.1.2\Lib\site-packages\mmengine\utils\dl_utils\collect_env.py", line 73in collect_env
    CUDA_HOME = _get_cuda_home()
                ^^^^^^^^^^^^^^^^
 
File "D:\miniconda3\envs\torch2.1.2\Lib\site-packages\mmengine\utils\dl_utils\collect_env.py", line 25in _get_cuda_home
    from torch.utils.cpp_extension import CUDA_HOME
File "D:\miniconda3\envs\torch2.1.2\Lib\site-packages\torch\utils\cpp_extension.py", line 28in <module>
    from pkg_resources import packaging  # type: ignore[attr-defined]
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
ModuleNotFoundError: No module named 'pkg_resources'
cs

 

 conda와 pip의 설정이 꼬인 Pain Point로 예상되어 pip 위주로 설치를 시도해 보았으나 여전히 에러가 해결되지 않았습니다. 결국 Claude 선생에게 물어보았더니 setuptools 최신 버전이 충돌을 일으켜서 그렇다는 판단을 해주길래 과거의 버전으로 설치를 시도해 보았습니다.

 

$ pip install setuptools==68.0.0

 

 Claude 선생께서 추천해주신대로 setuptools 구버전을 설치하니 문제가 깔끔하게 해결되었습니다!

300x250

FiftyOne 라이브러리로 Segmentation 데이터셋 볼 때 각 클래스별로 따로 볼 수 있도록 설정하는 방법

공대생의 팁 2026. 3. 21. 15:27

 

 

 Vision AI엔지니어로서 8년째 일하고 있음에도 최근까지 AI모델에만 매달리다가 현장에서 갓 생산된 데이터를 AI모델이 쉽게 받아들이도록 가공해야 성능 향상에 도움이 된다는 것을 최근에야 깨닫게 되었고, 실제 데이터 중심의 연구를 수행하는 AI엔지니어들이 현장에서 더 많은 역할을 하고 있음을 확인할 수 있었습니다. 좋은 데이터를 통해 좋은 AI모델이 만들어짐을 알지만, 어떻게 하면 우리들이 원하는 데이터로 만들 수 있는지 탐색하는 것도 쉽지 않았는데, 이러단 Vision 데이터셋들을 쉽게 관리할 수 있는 FiftyOne 라이브러리가 존재함을 알게 되었습니다.

 

 FiftyOne 라이브러리는 컴퓨터 비전 데이터셋을 구축, 시각화, 평가할 수 있는 강력한 오픈소스 데이터 관리 툴입니다. 대규모 이미지나 비디오 데이터를 효율적으로 탐색하고, 모델의 예측 결과를 직관적으로 분석할 수 있어 AI 연구 및 실무에서 실제 널리 활용되고 있다합니다. 다만, 라이브러리 자체에서 제공하는 기능들을 내가 원하는 대로 쓰기 위해서는 어느 정도 데이터 가공이 필요했습니다. 특히 Semantic Segmentation 모델을 주로 사용해온 저에게는 좋은 도구가 있음에도 쉽게 사용하지 못해 약간의 장벽을 느끼기도 하지만 우리의 훌륭하신 GPT 형님들이 친절하게 사용방법을 잘 알려주십니다.

 

 본 글에서는 FiftyOne 환경에서 Semantic Segmentation 모델의 데이터를 다룰 때 발생하는 시각화의 한계를 짚어보고, 이를 극복하여 분석 효율을 극대화하는 실무적인 데이터 전처리 기법을 소개합니다.


 Semantic Segmentation 모델을 Fiftyone에서 사용할 때 발생하는 문제점들

 

 FiftyOne을 활용해 Semantic Segmentation 데이터셋을 분석하고자 할 때, 흔히 직면하는 구조적인 제약이 있습니다. Instance Segmentation 데이터와 달리, Semantic Segmentation은 일반적으로 하나의 마스크(Mask) 이미지 내에 모든 클래스(Class) 정보가 픽셀 값으로 통합되어 저장된다는 점입니다. 이로 인해 FiftyOne 뷰어 상에서 내가 원하는 특정 클래스만 독립적으로 분리하여 시각화하거나 분석하는 데 어려움이 따릅니다.

 그래서 아래의 코드를 통해 GT 혹은 Pred 데이터에서 각각의 Class를 별도로 추출한 다음, 이를 FiftyOne DB에 적재하여 각 class별로 데이터를 확인할 수 있도록 하였습니다.

 

※ 본 소스코드는 Fiftyone 1.2.0 버전을 기준으로 작성되었습니다.

 

fiftyone_loader.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
import fiftyone as fo
import os
import numpy as np
from PIL import Image
 
# ==========================================
# 1. Dataset Classes (클래스 매핑)
# ==========================================
VOC_CLASSES = {
    0"background"1"aeroplane"2"bicycle"3"bird"4"boat"
    5"bottle"6"bus"7"car"8"cat"9"chair"10"cow"
    11"diningtable"12"dog"13"horse"14"motorbike"15"person"
    16"pottedplant"17"sheep"18"sofa"19"train"20"tvmonitor"
    255"void"
}
 
CITYSCAPES_CLASSES = {
    0"road"1"sidewalk"2"building"3"wall"4"fence"
    5"pole"6"traffic light"7"traffic sign"8"vegetation"
    9"terrain"10"sky"11"person"12"rider"13"car"
    14"truck"15"bus"16"train"17"motorcycle"18"bicycle"
    255"unlabeled"
}
 
ADE20K_CLASSES = {
    0"background"1"wall"2"building"3"sky"4"floor"
    5"tree"6"ceiling"7"road"8"bed"9"windowpane",
    # 필요시 추가 클래스 확장 (최대 150개)
}
 
MAPILLARY_CLASSES = {
    0"Bird"1"Ground Animal"2"Curb"3"Fence"4"Guard Rail"
    5"Barrier"6"Wall"7"Bike Lane"8"Crosswalk"9"Curb Cut",
    # 필요시 추가 클래스 확장 (최대 65/124개)
}
 
# ==========================================
# 2. 데이터셋 포맷별 디폴트 설정 (Suffix 꼬리표 포함)
# ==========================================
DATASET_DEFAULTS = {
    "VOC": {
        "image_folder""JPEGImages""gt_folder""SegmentationClass"
        "image_ext"".jpg""mask_ext"".png",
        "image_suffix""""gt_suffix""",  
        "classes": VOC_CLASSES
    },
    "CITYSCAPES": {
        "image_folder""leftImg8bit""gt_folder""gtFine"
        "image_ext"".png""mask_ext"".png",
        "image_suffix""_leftImg8bit",       
        "gt_suffix""_gtFine_labelIds",      
        "classes": CITYSCAPES_CLASSES
    },
    "ADE20K": {
        "image_folder""images""gt_folder""annotations"
        "image_ext"".jpg""mask_ext"".png",
        "image_suffix""""gt_suffix""",
        "classes": ADE20K_CLASSES
    },
    "MAPILLARY": {
        "image_folder""images""gt_folder""instances"
        "image_ext"".jpg""mask_ext"".png",
        "image_suffix""""gt_suffix""",
        "classes": MAPILLARY_CLASSES
    }
}
 
# ==========================================
# 3. 데이터셋 로더 함수 (치환 및 마스크 분리 로직 포함)
# ==========================================
def load_custom_segmentation_dataset(
    dataset_name, 
    dataset_format, 
    base_dir=""
    # 사용자 지정 경로
    custom_image_dir=None,  
    custom_gt_dir=None,     
    custom_pred_dir=None,   
    # 사용자 지정 꼬리표
    custom_image_suffix=None,
    custom_gt_suffix=None,
    custom_pred_suffix=None,
    # 적재 옵션
    load_gt=True,
    load_pred=True
):
    format_info = DATASET_DEFAULTS.get(dataset_format.upper())
    if not format_info:
        raise ValueError(f"지원하지 않는 포맷입니다: {dataset_format}")
 
    # 1. 경로 세팅 (사용자 지정 우선, 없으면 디폴트)
    image_dir = custom_image_dir or os.path.join(base_dir, format_info["image_folder"])
    gt_dir = custom_gt_dir or os.path.join(base_dir, format_info["gt_folder"])
    pred_dir = custom_pred_dir or os.path.join(base_dir, "preds")
 
    image_ext = format_info["image_ext"]
    mask_ext = format_info["mask_ext"]
 
    # 2. 꼬리표(Suffix) 세팅 (사용자 지정 우선, 없으면 디폴트)
    img_suf = custom_image_suffix if custom_image_suffix is not None else format_info["image_suffix"]
    gt_suf = custom_gt_suffix if custom_gt_suffix is not None else format_info["gt_suffix"]
    pred_suf = custom_pred_suffix if custom_pred_suffix is not None else gt_suf 
 
    # 3. FiftyOne 데이터셋 초기화
    if dataset_name in fo.list_datasets():
        fo.delete_dataset(dataset_name)
    dataset = fo.Dataset(dataset_name)
    
    # 스키마 미리 선언 (클래스명_gt, 클래스명_pred 순서로 UI에 강제 생성)
    ignore_classes = ["background""void""unlabeled"]
    for cls_id, cls_name in format_info["classes"].items():
        if cls_name.lower() in ignore_classes:
            continue
            
        if load_gt:
            dataset.add_sample_field(f"{cls_name}_gt", fo.core.fields.EmbeddedDocumentField, embedded_doc_type=fo.Segmentation)
        if load_pred:
            dataset.add_sample_field(f"{cls_name}_pred", fo.core.fields.EmbeddedDocumentField, embedded_doc_type=fo.Segmentation)
 
    # UI 색상 매핑 통일
    dataset.default_mask_targets = format_info["classes"]
    
    samples = []
    
    if not os.path.exists(image_dir):
        raise FileNotFoundError(f"이미지 폴더를 찾을 수 없습니다: {image_dir}")
 
    # 4. 파일 순회 및 분리 적재 로직
    for filename in os.listdir(image_dir):
        if not filename.endswith(image_ext):
            continue
            
        image_path = os.path.join(image_dir, filename)
        sample = fo.Sample(filepath=image_path)
        
        # 순수 파일명 추출 및 꼬리표 조립
        base_name = filename[:-len(image_ext)]
        if img_suf and base_name.endswith(img_suf):
            core_name = base_name[:-len(img_suf)]
        else:
            core_name = base_name
            
        gt_filename = f"{core_name}{gt_suf}{mask_ext}"
        pred_filename = f"{core_name}{pred_suf}{mask_ext}"
        
        # GT 적재 (마스크를 클래스별로 쪼개기)
        if load_gt:
            gt_path = os.path.join(gt_dir, gt_filename)
            if os.path.exists(gt_path):
                gt_img = np.array(Image.open(gt_path))
                
                for cls_id, cls_name in format_info["classes"].items():
                    if cls_name.lower() in ignore_classes:
                        continue
                        
                    bin_mask = (gt_img == cls_id)
                    if np.any(bin_mask):
                        # 저장 필드명을 '클래스명_gt'로 변경
                        sample[f"{cls_name}_gt"= fo.Segmentation(mask=bin_mask.astype(np.uint8) * cls_id)
            else:
                print(f"[경고] GT 마스크 누락: {gt_path}")
        
        # Pred 적재 (마스크를 클래스별로 쪼개기)
        if load_pred:
            pred_path = os.path.join(pred_dir, pred_filename)
            if os.path.exists(pred_path):
                pred_img = np.array(Image.open(pred_path))
                
                for cls_id, cls_name in format_info["classes"].items():
                    if cls_name.lower() in ignore_classes:
                        continue
                        
                    bin_mask = (pred_img == cls_id)
                    if np.any(bin_mask):
                        # [수정됨] 저장 필드명을 '클래스명_pred'로 변경
                        sample[f"{cls_name}_pred"= fo.Segmentation(mask=bin_mask.astype(np.uint8) * cls_id)
                
        samples.append(sample)
        
    dataset.add_samples(samples)
    print(f"'{dataset_name}' 데이터셋 구축 완료! (총 {len(samples)}장 적재)")
    
    return dataset
 
# ==========================================
# 4. 실행 예시 (main 함수)
# ==========================================
if __name__ == "__main__":
    
    # [사용자 설정 영역] 직관적으로 이미지, GT, Pred 경로를 한 곳에서 관리
    IMG_DIR  = "/path/to/dataset/images"
    GT_DIR   = "/path/to/dataset/ground_truth"
    PRED_DIR = "/path/to/dataset/model_predictions"
    
    # 데이터셋 구축
    my_dataset = load_custom_segmentation_dataset(
        dataset_name="Segmentation_Analysis_Project",
        dataset_format="CITYSCAPES",  # VOC, CITYSCAPES, ADE20K, MAPILLARY 중 택 1
        
        # 경로 연결
        custom_image_dir=IMG_DIR, custom_gt_dir=GT_DIR, custom_pred_dir=PRED_DIR,
        
        # 꼬리표(Suffix) 설정 (파일명이 모두 동일하다면 빈 문자열("") 지정)
        custom_image_suffix="_leftImg8bit",
        custom_gt_suffix="_gtFine_labelIds",
        custom_pred_suffix="_pred",
        
        # 적재 여부 선택
        load_gt=True,
        load_pred=False
    )
    
    # FiftyOne App 실행
    session = fo.launch_app(my_dataset)
    session.wait()
cs

 

 위에서 각각의 클래스를 별개로 저장한 다음 FiftyOne에 적재하면 각 Class마다 데이터를 별개로 제어할 수 있는 것을 확인할 수 있습니다.

 

 

위 데이터셋에서 'horse_gt'와 'car_gt'를 해제하면 말과 자동차의 Segment가 사라지는 것을 확인하실 수 있습니다.

 

300x250