1. Segmentation
* Segmentation은 컴퓨터 비전에서 이미지나 영상을 픽셀 단위로 분할하여 각 영역이 무엇을 나타내는지 구분하는 기술입니다.
* 이는 크게 Semantic Segmentation과 Instance Segmentation으로 나뉘는데, Semantic Segmentation은 같은 종류의 객체를 동일한 클래스로 분류하는 반면, Instance Segmentation은 같은 클래스 내에서도 개별 객체를 구분합니다.
* 이를 통해 의료 영상 분석, 자율주행, 위성 이미지 처리 등 다양한 분야에서 정밀한 객체 인식을 수행할 수 있습니다.
* Segmentation 모델로는 U-Net, DeepLab, Mask R-CNN 등이 널리 사용됩니다.
압축을 푼 후 활용 하세영~~
예시 1)
!pip install -q ultralytics opencv-python
예시 2)
import ultralytics
ultralytics.checks()
-->
Ultralytics 8.3.88 🚀 Python-3.11.11 torch-2.5.1+cu124 CUDA:0 (Tesla T4, 15095MiB)
Setup complete ✅ (2 CPUs, 12.7 GB RAM, 40.8/112.6 GB disk)
예시 3)
import os
import random
import shutil
from tqdm import tqdm
import cv2
import glob
import json
import matplotlib.pyplot as plt
import numpy as np
from pycocotools import mask as maskUtils
from torchvision import transforms
예시 4)
# 현재 경로
%pwd
-->
/content/drive/MyDrive/KDT 시즌 4/13. 컴퓨터 비전/resource/starbucks
예시 5)
%cd /content/drive/MyDrive/KDT 시즌 4/13. 컴퓨터 비전
예시 6)
data_root = '/content/drive/MyDrive/KDT 시즌 4/13. 컴퓨터 비전/resource/starbucks'
예시 7)
data_list = glob.glob( f'{data_root}/data/*.jpg' )
data_list
예시 8)
## COCO JSON 파일 로드
def load_coco_annotations(json_path):
with open(json_path, 'r') as f:
data = json.load(f)
return data
예시 9)
# json 파일의 확인용 데이터
load_coco_annotations(f'{data_root}/data/instances_default.json')
예시 10)
import cv2
# 이미지 파일 불러오는 함수
def load_image(image_path):
# OpenCV를 사용하여 이미지 파일을 읽어옴
image = cv2.imread(image_path)
# 파일이 존재하지 않거나 로드할 수 없는 경우 예외 발생
if image is None:
raise FileNotFoundError(f'File not found: {image_path}')
# OpenCV는 기본적으로 BGR 형식으로 이미지를 로드하므로, 이를 RGB 형식으로 변환하여 반환
return cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
예시 11)
load_image(data_list[2])
--->
예시 12)
import cv2
import numpy as np
from pycocotools import mask as maskUtils
# 폴리곤 및 RLE 주석을 이미지 위에 그리기
# RLE(Run-Length Encoding) : 이미지 압축 및 데이터 압축을 위한 기법 중 하나.
# 특히 COCO Datasets의 객체 분할시 정보를 저장할때 많이 사용함
# 주어진 이미지에 어노테이션을 그리는 함수
def draw_annotations(image, annotations, image_id):
for ann in annotations:
# 현재 어노테이션이 지정된 image_id와 일치하는지 확인
if ann['image_id'] == image_id and 'segmentation' in ann:
segmentation = ann['segmentation']
# RLE (Run-Length Encoding) 형식 - 딕셔너리 타입
if isinstance(segmentation, dict) and 'counts' in segmentation:
try:
# 'counts'가 리스트 형태인 경우 RLE 변환 수행
if isinstance(segmentation['counts'], list):
rle = maskUtils.frPyObjects(segmentation, segmentation['size'][0], segmentation['size'][1])
mask = maskUtils.decode(rle) # 마스크 디코딩
else:
mask = maskUtils.decode(segmentation) # 바로 디코딩 가능
# 마스크에서 윤곽선(contour) 검출
contours, _ = cv2.findContours(mask.astype(np.uint8), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# 검출된 윤곽선을 이미지에 그림 (파란색)
cv2.drawContours(image, contours, -1, (255, 0, 0), 2)
except Exception as e:
print(f'에러가 발생: {e}')
# 폴리곤 (Polygon) 형식 - 리스트 타입
elif isinstance(segmentation, list):
for seg in segmentation:
# 폴리곤 점 리스트가 6개 이상이어야 유효한 다각형이 됨
if isinstance(seg, list) and len(seg) >= 6:
# 리스트를 numpy 배열로 변환하고 정수형 좌표로 변환
points = np.array(seg).reshape(-1, 2).astype(np.int32)
# 폴리라인을 이미지에 그림 (녹색)
cv2.polylines(image, [points], isClosed=True, color=(0, 255, 0), thickness=2)
return image # 어노테이션이 적용된 이미지를 반환
예시 13)
import os
import json
import cv2
import numpy as np
import matplotlib.pyplot as plt
from pycocotools import mask as maskUtils
# COCO JSON 파일에서 어노테이션 데이터를 로드하는 함수
def load_coco_annotations(json_path):
with open(json_path, 'r', encoding='utf-8') as f:
coco_data = json.load(f)
return coco_data
# 이미지 파일 불러오기 함수
def load_image(image_path):
image = cv2.imread(image_path)
if image is None:
raise FileNotFoundError(f'File not found: {image_path}')
return cv2.cvtColor(image, cv2.COLOR_BGR2RGB) # OpenCV의 BGR 형식을 RGB로 변환
# 이미지에 어노테이션을 그리는 함수
def draw_annotations(image, annotations, image_id):
for ann in annotations:
# 현재 어노테이션이 지정된 image_id와 일치하는 경우만 처리
if ann['image_id'] == image_id and 'segmentation' in ann:
segmentation = ann['segmentation']
# RLE (Run-Length Encoding) 방식
if isinstance(segmentation, dict) and 'counts' in segmentation:
try:
if isinstance(segmentation['counts'], list):
rle = maskUtils.frPyObjects(segmentation, segmentation['size'][0], segmentation['size'][1])
mask = maskUtils.decode(rle)
else:
mask = maskUtils.decode(segmentation)
# 마스크에서 윤곽선(contour) 검출
contours, _ = cv2.findContours(mask.astype(np.uint8), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# 검출된 윤곽선을 이미지에 그림 (파란색)
cv2.drawContours(image, contours, -1, (255, 0, 0), 2)
except Exception as e:
print(f'에러 발생: {e}')
# 폴리곤 (Polygon) 방식
elif isinstance(segmentation, list):
for seg in segmentation:
if isinstance(seg, list) and len(seg) >= 6:
points = np.array(seg).reshape(-1, 2).astype(np.int32)
# 폴리라인을 이미지에 그림 (녹색)
cv2.polylines(image, [points], isClosed=True, color=(0, 255, 0), thickness=2)
return image # 어노테이션이 적용된 이미지를 반환
# COCO 데이터셋을 기반으로 이미지와 어노테이션을 시각화하는 메인 실행 함수
def visualize_coco(json_path, image_folder, image_id):
# COCO 어노테이션 데이터 로드
coco_data = load_coco_annotations(json_path)
# image_id에 해당하는 이미지 정보 찾기
image_info = next((img for img in coco_data['images'] if img['id'] == image_id), None)
if not image_info:
raise ValueError(f'Image ID {image_id} not found in COCO JSON file')
# 이미지 파일 경로 생성 및 이미지 로드
image_path = os.path.join(image_folder, image_info['file_name'])
image = load_image(image_path)
# 이미지에 어노테이션 적용
annotated_image = draw_annotations(image, coco_data['annotations'], image_id)
# 이미지 시각화
plt.figure(figsize=(8, 6))
plt.imshow(annotated_image)
plt.axis('off')
plt.title(f'Image ID: {image_id} with Annotations')
plt.show()
예시 14)
#coco로 이미지 출력
visualize_coco( f'{data_root}/data/instances_default.json', f'{data_root}/data', 20)
--->
예시 15)
import os
import json
import cv2
import numpy as np
from pycocotools import mask as maskUtils
# COCO JSON 파일 경로 및 YOLO 라벨 저장 폴더 설정
data_root = 'your/dataset/path' # 데이터셋 경로 (적절히 변경해야 함)
coco_json_path = f'{data_root}/data/instances_default.json' # COCO JSON 파일 경로
yolo_output_folder = f'{data_root}/data' # YOLO 형식의 라벨을 저장할 폴더
image_folder = f'{data_root}/data/' # 이미지가 저장된 폴더 경로
# YOLO 라벨 폴더 생성 (폴더가 없으면 자동으로 생성)
os.makedirs(yolo_output_folder, exist_ok=True)
# COCO JSON 데이터 로드
with open(coco_json_path, 'r', encoding='utf-8') as f:
coco_data = json.load(f)
# 이미지 정보 불러오기 (딕셔너리로 변환하여 image_id로 빠르게 검색 가능)
image_dict = {img['id']: img for img in coco_data['images']}
# COCO -> YOLO 변환 시작
for ann in coco_data['annotations']:
image_id = ann['image_id'] # 어노테이션이 적용될 이미지 ID
category_id = ann['category_id'] - 1 # YOLO는 클래스 ID가 0부터 시작하므로 1을 빼줌
segmentation = ann['segmentation'] # segmentation 정보 가져오기
# 해당 이미지의 정보를 딕셔너리에서 가져옴
image_info = image_dict.get(image_id)
if not image_info:
continue # 해당 image_id가 없는 경우 스킵
img_width, img_height = image_info['width'], image_info['height'] # 이미지의 너비와 높이 정보 가져오기
yolo_label_path = os.path.join(yolo_output_folder, f"{os.path.splitext(image_info['file_name'])[0]}.txt") # YOLO 라벨 저장 파일 경로
yolo_lines = [] # YOLO 형식의 어노테이션을 저장할 리스트
# RLE 형식 (Run-Length Encoding 방식의 마스크)
if isinstance(segmentation, dict) and 'counts' in segmentation:
# RLE 데이터를 마스크로 변환
rle = maskUtils.frPyObjects(segmentation, img_height, img_width)
mask = maskUtils.decode(rle)
# 마스크에서 윤곽선(contour) 검출
contours, _ = cv2.findContours(mask.astype(np.uint8), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
for contour in contours:
if len(contour) >= 3: # 최소한 세 개의 점이 있어야 다각형이 됨
# 좌표를 YOLO 포맷(0~1 범위)으로 변환
normalized_points = [(x / img_width, y / img_height) for x, y in contour.reshape(-1, 2)]
# YOLO 형식: "class_id x1 y1 x2 y2 x3 y3 ..." (정규화된 좌표)
yolo_line = f'{category_id} ' + ' '.join([f'{x:.6f} {y:.6f}' for x, y in normalized_points])
yolo_lines.append(yolo_line)
# 폴리곤 형식 (Polygon 방식의 마스크)
elif isinstance(segmentation, list):
for seg in segmentation:
if isinstance(seg, list) and len(seg) >= 6: # 최소한 세 개의 점이 필요 (x, y 페어로 최소 6개 값)
# 좌표를 YOLO 포맷(0~1 범위)으로 변환
normalized_points = [(seg[i] / img_width, seg[i+1] / img_height) for i in range(0, len(seg), 2)]
# YOLO 형식으로 변환하여 저장
yolo_line = f'{category_id} ' + ' '.join([f'{x:.6f} {y:.6f}' for x, y in normalized_points])
yolo_lines.append(yolo_line)
# 변환된 YOLO 형식 데이터를 파일로 저장
if yolo_lines:
with open(yolo_label_path, 'w', encoding='utf-8') as f:
f.write('\n'.join(yolo_lines))
print(f'COCO -> YOLO 변환 완료!')
예시 16)
import random
import glob
# 랜덤 시드 설정 (재현 가능성을 위해 설정)
random.seed(2025)
# 데이터셋 경로 설정 (JPG 및 JPEG 이미지 파일을 리스트에 저장)
data_list = glob.glob(f'{data_root}/data/*.jpg') + glob.glob(f'{data_root}/data/*.jpeg')
# 데이터를 랜덤하게 섞음
random.shuffle(data_list)
# 테스트 데이터 비율 설정
test_ratio = 0.2 # 데이터의 20%를 테스트 세트로 사용
# 전체 데이터 개수 확인
num_data = len(data_list)
# 데이터셋을 train/valid/test로 분할
test_list = data_list[:int(num_data * test_ratio)] # 첫 20%를 테스트 세트
valid_list = data_list[int(num_data * test_ratio):int(num_data * test_ratio) * 2] # 다음 20%를 검증 세트
train_list = data_list[int(num_data * test_ratio) * 2:] # 나머지 60%를 학습 세트
# 각 세트의 크기 출력
len(test_list), len(valid_list), len(train_list)
-->
(6, 6, 18)
예시 17)
import os
# 데이터셋의 루트 경로 설정
file_root = f'./{data_root}/data' # 데이터 파일이 있는 경로
# 학습(train), 검증(valid), 테스트(test) 데이터가 저장될 폴더 경로 설정
train_root = f'{data_root}/train'
valid_root = f'{data_root}/valid'
test_root = f'{data_root}/test'
# 위에서 설정한 train, valid, test 폴더가 존재하지 않으면 생성
for folder in [train_root, valid_root, test_root]:
if not os.path.exists(folder):
os.makedirs(folder) # 폴더 생성
예시 18)
import os
import shutil
# 파일 리스트를 대상 폴더로 복사하는 함수
def copy_files(file_list, dest_folder):
for file_path in file_list:
# 파일 이름과 확장자 분리
file_name = os.path.basename(file_path) # 파일명 추출 (예: 'image1.jpg')
file_base, ext = os.path.splitext(file_name) # 파일명과 확장자 분리 (예: 'image1', '.jpg')
# 원본(이미지) 파일을 대상 폴더로 복사
dest_path = os.path.join(dest_folder, file_name)
shutil.copy(file_path, dest_path)
# 같은 이름의 어노테이션 파일(.txt)도 존재하면 함께 복사
txt_file_path = os.path.join(os.path.dirname(file_path), f'{file_base}.txt') # 동일한 파일명의 .txt 경로 설정
if os.path.exists(txt_file_path): # 어노테이션 파일이 존재하는지 확인
dest_txt_path = os.path.join(dest_folder, f'{file_base}.txt') # 대상 폴더 내 복사 경로 설정
shutil.copy(txt_file_path, dest_txt_path) # 어노테이션 파일 복사
예시 19)
# 학습(train), 검증(valid), 테스트(test) 데이터를 각 폴더로 복사
copy_files(train_list, train_root) # 학습 데이터 및 YOLO 라벨 복사
copy_files(valid_list, valid_root) # 검증 데이터 및 YOLO 라벨 복사
copy_files(test_list, test_root) # 테스트 데이터 및 YOLO 라벨 복사
예시 20)
# Google Drive 내 저장 경로 설정
train_root = f'/content/drive/MyDrive/KDT 시즌 4/13. 컴퓨터 비전/resource/starbucks/train'
valid_root = f'/content/drive/MyDrive/KDT 시즌 4/13. 컴퓨터 비전/resource/starbucks/valid'
test_root = f'/content/drive/MyDrive/KDT 시즌 4/13. 컴퓨터 비전/resource/starbucks/test'
예시 21)
import yaml
# YOLO 학습을 위한 설정 데이터를 저장할 딕셔너리 생성
data = dict()
# 학습(train), 검증(val), 테스트(test) 데이터셋의 경로 지정
data['train'] = train_root # 학습 데이터 경로
data['val'] = valid_root # 검증 데이터 경로
data['test'] = test_root # 테스트 데이터 경로
# 클래스 개수 (nc: number of classes)
data['nc'] = 2 # 총 2개의 클래스 존재
# 클래스 이름 리스트 (YOLO에서 사용할 라벨 이름)
data['names'] = ['logo', 'text'] # 0: logo, 1: text
# YAML 파일을 생성하여 저장
with open('./resource/starbucks/starbucks.yaml', 'w') as f:
yaml.dump(data, f)
예시 22)
%pwd
/content/drive/MyDrive/KDT 시즌 4/13. 컴퓨터 비전
%cd /content/drive/MyDrive/KDT 시즌 4/13. 컴퓨터 비전/resource/starbucks
예시 23)
from ultralytics import YOLO
# YOLOv8 세그멘테이션 모델 불러오기
model = YOLO('yolov8s-seg.pt') # YOLOv8 small segmentation 모델 로드
예시 24)
# YOLOv8 모델 학습 실행
results = model.train(
data='./starbucks.yaml', # 학습 데이터셋 설정 파일 (YOLO 포맷)
epochs=10, # 학습 반복 횟수 (Epochs)
batch=8, # 미니배치 크기 (Batch Size)
imgsz=224, # 입력 이미지 크기 (224x224 픽셀)
device=0, # GPU 사용 (0: 첫 번째 GPU, 'cpu' 사용 가능)
workers=2, # 데이터 로딩을 위한 병렬 작업 수
amp=False, # Automatic Mixed Precision (AMP) 비활성화 (기본값=True)
name='starbucks_s' # 학습 결과를 저장할 실험 이름
)
-->
albumentations: Blur(p=0.01, blur_limit=(3, 7)), MedianBlur(p=0.01, blur_limit=(3, 7)), ToGray(p=0.01, num_output_channels=3, method='weighted_average'), CLAHE(p=0.01, clip_limit=(1.0, 4.0), tile_grid_size=(8, 8))
Epoch GPU_mem box_loss seg_loss cls_loss dfl_loss Instances Size
1/10 1.11G 2.295 2.907 4.347 1.541 2 224: 100%|██████████| 3/3 [00:00<00:00, 4.51it/s]
Class Images Instances Box(P R mAP50 mAP50-95) Mask(P R mAP50 mAP50-95): 100%|██████████| 1/1 [00:00<00:00, 10.82it/s] all 6 8 0.662 0.125 0.127 0.126 0.662 0.125 0.131 0.127
Epoch GPU_mem box_loss seg_loss cls_loss dfl_loss Instances Size
2/10 1.11G 1.396 2.208 2.751 1.179 2 224: 100%|██████████| 3/3 [00:01<00:00, 2.82it/s]
Class Images Instances Box(P R mAP50 mAP50-95) Mask(P R mAP50 mAP50-95): 100%|██████████| 1/1 [00:00<00:00, 10.98it/s] all 6 8 0.82 0.25 0.231 0.207 0.82 0.25 0.231 0.171
Epoch GPU_mem box_loss seg_loss cls_loss dfl_loss Instances Size
3/10 1.11G 0.8579 1.832 1.567 0.9745 2 224: 100%|██████████| 3/3 [00:00<00:00, 6.29it/s]
Class Images Instances Box(P R mAP50 mAP50-95) Mask(P R mAP50 mAP50-95): 100%|██████████| 1/1 [00:00<00:00, 8.14it/s] all 6 8 0.8 0.25 0.241 0.206 0.8 0.25 0.241 0.182
Epoch GPU_mem box_loss seg_loss cls_loss dfl_loss Instances Size
4/10 1.11G 0.9759 1.249 1.252 1.089 2 224: 100%|██████████| 3/3 [00:00<00:00, 6.64it/s]
Class Images Instances Box(P R mAP50 mAP50-95) Mask(P R mAP50 mAP50-95): 100%|██████████| 1/1 [00:00<00:00, 11.98it/s] all 6 8 0.82 0.25 0.289 0.217 0.82 0.25 0.288 0.156
Epoch GPU_mem box_loss seg_loss cls_loss dfl_loss Instances Size
5/10 1.11G 1.264 2.288 2.349 0.9394 1 224: 100%|██████████| 3/3 [00:00<00:00, 3.07it/s]
Class Images Instances Box(P R mAP50 mAP50-95) Mask(P R mAP50 mAP50-95): 100%|██████████| 1/1 [00:00<00:00, 6.76it/s] all 6 8 0.316 0.25 0.247 0.194 0.316 0.25 0.218 0.149
Epoch GPU_mem box_loss seg_loss cls_loss dfl_loss Instances Size
6/10 1.11G 1.042 1.12 1.854 0.9422 2 224: 100%|██████████| 3/3 [00:00<00:00, 7.42it/s]
Class Images Instances Box(P R mAP50 mAP50-95) Mask(P R mAP50 mAP50-95): 100%|██████████| 1/1 [00:00<00:00, 12.19it/s] all 6 8 0.322 0.25 0.277 0.198 0.322 0.25 0.226 0.153
Epoch GPU_mem box_loss seg_loss cls_loss dfl_loss Instances Size
7/10 1.11G 1.141 1.069 1.368 1.07 2 224: 100%|██████████| 3/3 [00:00<00:00, 6.24it/s]
Class Images Instances Box(P R mAP50 mAP50-95) Mask(P R mAP50 mAP50-95): 100%|██████████| 1/1 [00:00<00:00, 11.34it/s] all 6 8 0.744 0.25 0.282 0.198 0.744 0.25 0.231 0.17
Epoch GPU_mem box_loss seg_loss cls_loss dfl_loss Instances Size
8/10 1.11G 0.9192 0.9936 1.104 0.9793 2 224: 100%|██████████| 3/3 [00:00<00:00, 8.36it/s]
Class Images Instances Box(P R mAP50 mAP50-95) Mask(P R mAP50 mAP50-95): 100%|██████████| 1/1 [00:00<00:00, 8.43it/s] all 6 8 0.795 0.364 0.377 0.238 0.795 0.364 0.337 0.222
Epoch GPU_mem box_loss seg_loss cls_loss dfl_loss Instances Size
9/10 1.11G 1.185 1.879 1.635 1.023 2 224: 100%|██████████| 3/3 [00:00<00:00, 8.37it/s]
Class Images Instances Box(P R mAP50 mAP50-95) Mask(P R mAP50 mAP50-95): 100%|██████████| 1/1 [00:00<00:00, 11.78it/s] all 6 8 0.795 0.375 0.379 0.243 0.795 0.375 0.348 0.232
Epoch GPU_mem box_loss seg_loss cls_loss dfl_loss Instances Size
10/10 1.11G 0.7996 1.08 1.393 0.9292 2 224: 100%|██████████| 3/3 [00:00<00:00, 6.94it/s]
Class Images Instances Box(P R mAP50 mAP50-95) Mask(P R mAP50 mAP50-95): 100%|██████████| 1/1 [00:00<00:00, 8.03it/s] all 6 8 0.794 0.375 0.334 0.206 0.794 0.375 0.308 0.192
10 epochs completed in 0.006 hours.
Optimizer stripped from runs/segment/starbucks_s2/weights/last.pt, 23.8MB
Optimizer stripped from runs/segment/starbucks_s2/weights/best.pt, 23.8MB
Validating runs/segment/starbucks_s2/weights/best.pt...
Ultralytics 8.3.88 🚀 Python-3.11.11 torch-2.5.1+cu124 CUDA:0 (Tesla T4, 15095MiB)
YOLOv8s-seg summary (fused): 85 layers, 11,780,374 parameters, 0 gradients, 42.4 GFLOPs
Class Images Instances Box(P R mAP50 mAP50-95) Mask(P R mAP50 mAP50-95): 100%|██████████| 1/1 [00:00<00:00, 13.54it/s]
all 6 8 0.794 0.375 0.379 0.243 0.794 0.375 0.348 0.232
logo 4 4 0.589 0.75 0.633 0.457 0.589 0.75 0.573 0.422
text 2 4 1 0 0.125 0.0285 1 0 0.123 0.0431
Speed: 0.1ms preprocess, 4.1ms inference, 0.0ms loss, 1.7ms postprocess per image
Results saved to runs/segment/starbucks_s2
예시 25)
from ultralytics import YOLO
# 학습된 YOLOv8 모델 로드 (가장 성능이 좋은 'best.pt' 사용)
model = YOLO('runs/segment/starbucks_s/weights/best.pt')
# 테스트 데이터셋을 사용하여 예측 수행
results = model.predict(
source='/content/drive/MyDrive/KDT 시즌 4/13. 컴퓨터 비전/resource/starbucks/test', # 테스트 데이터 경로
imgsz=224, # 입력 이미지 크기 (224x224 픽셀)
conf=0.25, # 신뢰도(confidence) 임계값 (0.25 이상인 경우만 탐지)
device=0, # GPU 사용 (0: 첫 번째 GPU, 'cpu'로 변경 가능)
save=True, # 탐지된 결과를 이미지 파일로 저장
save_conf=True # 탐지된 객체의 신뢰도 점수를 결과 이미지에 저장
)
--->
728x90
LIST
'컴퓨터 비전' 카테고리의 다른 글
차량파손 데이터셋 (0) | 2025.03.13 |
---|---|
이안류 CCTV 데이터셋 (0) | 2025.03.11 |
Object Detection (2) | 2025.03.07 |
OCR (6) | 2025.03.06 |
4-(2). OpenCV (0) | 2025.03.05 |