์ปดํจํฐ ๋น์ (Computer Vision)์ ๋จธ์ ๋ฌ๋๊ณผ ๋ฅ๋ฌ๋์ ํ์ฉํ์ฌ ์ด๋ฏธ์ง๋ ๋์์์ ๋ถ์ํ๋ ๊ธฐ์ ์ ๋๋ค. ์ด๋ฒ ๊ธ์์๋ ์ด๋ฏธ์ง ์ฒ๋ฆฌ์ ๊ธฐ๋ณธ ๊ฐ๋ ๊ณผ ํฉ์ฑ๊ณฑ ์ ๊ฒฝ๋ง(CNN)์ ์๋ฆฌ๋ฅผ ์ดํดํ๊ณ , Python์ ํ์ฉํ CNN ๊ธฐ๋ฐ์ ์ด๋ฏธ์ง ๋ถ๋ฅ ์ค์ต์ ์งํํด ๋ณด๊ฒ ์ต๋๋ค. ๋ํ ๊ฐ์ฒด ํ์ง ๋ฐ ์ด๋ฏธ์ง ์ธ๊ทธ๋ฉํ ์ด์ ํ๋ก์ ํธ ์์ด๋์ด๋ ์๊ฐํฉ๋๋ค.
[ ์์นด์ฝ ]
1. ์ปดํจํฐ ๋น์ ์ด๋ก
1.1 ์ด๋ฏธ์ง ์ฒ๋ฆฌ ๊ธฐ๋ณธ ๊ฐ๋
์ปดํจํฐ ๋น์ ์์ ์ด๋ฏธ์ง ์ฒ๋ฆฌ๋ ๋ค์ํ ๊ธฐ๋ฒ์ ํ์ฉํ์ฌ ์๋ฏธ ์๋ ์ ๋ณด๋ฅผ ์ถ์ถํ๋ ๊ณผ์ ์ ๋๋ค. ์ฃผ์ ๊ฐ๋ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ํฝ์ (Pixel): ์ด๋ฏธ์ง์ ์ต์ ๋จ์๋ก, RGB ๊ฐ(์ปฌ๋ฌ ์ด๋ฏธ์ง) ๋๋ ๊ทธ๋ ์ด์ค์ผ์ผ ๊ฐ(ํ๋ฐฑ ์ด๋ฏธ์ง)์ผ๋ก ํํ๋ฉ๋๋ค.
- ํํฐ(Filter): ํน์ ํจํด์ ๊ฐ์กฐํ๊ฑฐ๋ ์ก์์ ์ ๊ฑฐํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค.
- ์ปจ๋ณผ๋ฃจ์ (Convolution): ํํฐ๋ฅผ ์ ์ฉํ์ฌ ์ด๋ฏธ์ง์ ํน์ง์ ์ถ์ถํ๋ ์ฐ์ฐ์ ๋๋ค.
- ์์ง ๊ฒ์ถ(Edge Detection): ์ด๋ฏธ์ง ๋ด์์ ๊ฒฝ๊ณ๋ฅผ ๊ฐ์งํ๋ ๊ธฐ๋ฒ์ ๋๋ค.
1.2 ํฉ์ฑ๊ณฑ ์ ๊ฒฝ๋ง(CNN) ์ดํด
CNN(Convolutional Neural Network)์ ์ด๋ฏธ์ง ์ธ์์ ์ํ ๋ํ์ ์ธ ๋ฅ๋ฌ๋ ๋ชจ๋ธ์ ๋๋ค. ์ฃผ์ ๊ตฌ์ฑ ์์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ํฉ์ฑ๊ณฑ ๊ณ์ธต(Convolutional Layer): ์ด๋ฏธ์ง์์ ํน์ง์ ์ถ์ถํ๋ ์ญํ ์ ํฉ๋๋ค.
- ํ๋ง ๊ณ์ธต(Pooling Layer): ํน์ง ๋งต์ ํฌ๊ธฐ๋ฅผ ์ค์ฌ ์ฐ์ฐ๋์ ๊ฐ์์ํค๊ณ , ์ค์ํ ์ ๋ณด๋ฅผ ์ ์งํฉ๋๋ค.
- ์์ ์ฐ๊ฒฐ ๊ณ์ธต(Fully Connected Layer): ์ถ์ถ๋ ํน์ง์ ๋ฐํ์ผ๋ก ์ต์ข ๋ถ๋ฅ๋ฅผ ์ํํฉ๋๋ค.
CNN์ ์ด๋ฌํ ๊ณ์ธต๋ค์ ์์ฐจ์ ์ผ๋ก ์ฐ๊ฒฐํ์ฌ ์ด๋ฏธ์ง์ ๋ณต์กํ ํจํด์ ํจ๊ณผ์ ์ผ๋ก ํ์ตํ ์ ์๋๋ก ํฉ๋๋ค.
2. ์ค์ต: CNN์ ์ด์ฉํ ์ด๋ฏธ์ง ๋ถ๋ฅ
์๋ ์์ ์์๋ Python์ TensorFlow์ Keras ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํ์ฉํ์ฌ MNIST ๋ฐ์ดํฐ์ ์ ๋ถ๋ฅํ๋ CNN ๋ชจ๋ธ์ ๊ตฌํํด ๋ณด๊ฒ ์ต๋๋ค.
2.1 ์์ ์ฝ๋
# winget์ผ๋ก ์ค์น (Windows 11/10)
winget install Python.Python.3.10
# py launcher ์ค์น
pip install py
# ์ค์น๋ ๋ชจ๋ Python ๋ฒ์ ํ์ธ
py --list
# Python 3.10์ผ๋ก ์คํ
py -3.10
# pip ์ฌ์ฉํ ๋
py -3.10 -m pip install tensorflow
import tensorflow as tf
from tensorflow.keras import datasets, layers, models
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
# ํ๊ธ ํฐํธ ์ค์
plt.rcParams['font.family'] = 'Malgun Gothic' # Windows
# plt.rcParams['font.family'] = 'AppleGothic' # Mac
plt.rcParams['axes.unicode_minus'] = False # ๋ง์ด๋์ค ๊ธฐํธ ๊นจ์ง ๋ฐฉ์ง
# MNIST ๋ฐ์ดํฐ์
๋ก๋ ๋ฐ ์ ์ฒ๋ฆฌ
(train_images, train_labels), (test_images, test_labels) = datasets.mnist.load_data()
# ๋ฐ์ดํฐ ์ฐจ์ ํ์ฅ ๋ฐ ์ ๊ทํ (CNN์ 4D ํ
์๋ฅผ ์
๋ ฅ์ผ๋ก ๋ฐ์: (์ํ ์, ๋์ด, ๋๋น, ์ฑ๋))
train_images = train_images.reshape((60000, 28, 28, 1)).astype('float32') / 255.0
test_images = test_images.reshape((10000, 28, 28, 1)).astype('float32') / 255.0
# ๋ชจ๋ธ ๊ตฌ์ฑ
model = models.Sequential([
layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)),
layers.MaxPooling2D((2, 2)),
layers.Conv2D(64, (3, 3), activation='relu'),
layers.MaxPooling2D((2, 2)),
layers.Conv2D(64, (3, 3), activation='relu'),
layers.Flatten(),
layers.Dense(64, activation='relu'),
layers.Dense(10, activation='softmax') # 10๊ฐ์ ํด๋์ค (์ซ์ 0-9)
])
# ๋ชจ๋ธ ์ปดํ์ผ
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
# ๋ชจ๋ธ ์์ฝ ์ถ๋ ฅ
model.summary()
# ๋ชจ๋ธ ํ์ต
history = model.fit(train_images, train_labels, epochs=5,
validation_data=(test_images, test_labels))
# ๋ชจ๋ธ ํ๊ฐ
test_loss, test_acc = model.evaluate(test_images, test_labels)
print(f"ํ
์คํธ ์ ํ๋: {test_acc:.4f}")
# ํ์ต ๊ณผ์ ์๊ฐํ
plt.plot(history.history['accuracy'], label='ํ๋ จ ์ ํ๋')
plt.plot(history.history['val_accuracy'], label='๊ฒ์ฆ ์ ํ๋')
plt.xlabel('์ํฌํฌ')
plt.ylabel('์ ํ๋')
plt.legend()
plt.title('ํ์ต ๋ฐ ๊ฒ์ฆ ์ ํ๋')
plt.show()
2.2 ์ฝ๋ ์ค๋ช
- ๋ฐ์ดํฐ ์ ์ฒ๋ฆฌ: MNIST ๋ฐ์ดํฐ์ ์ ๋ถ๋ฌ์ ์ ๊ทํํ๊ณ CNN ์ ๋ ฅ ํํ๋ก ๋ณํํฉ๋๋ค.
- CNN ๋ชจ๋ธ ๊ตฌ์ฑ: ์ธ ๊ฐ์ ํฉ์ฑ๊ณฑ ๊ณ์ธต๊ณผ ํ๋ง ๊ณ์ธต์ ํฌํจํ ๊ฐ๋จํ CNN์ ์์ฑํฉ๋๋ค.
- ๋ชจ๋ธ ํ์ต ๋ฐ ํ๊ฐ: 5๋ฒ์ ์ํฌํฌ ๋์ ํ์ต์ ์งํํ๊ณ , ํ ์คํธ ๋ฐ์ดํฐ์์ ์ ํ๋๋ฅผ ์ธก์ ํฉ๋๋ค.
- ์๊ฐํ: ํ๋ จ ์ ํ๋์ ๊ฒ์ฆ ์ ํ๋๋ฅผ ํ๋กฏํ์ฌ ํ์ต ๊ณผ์ ์ ๋ถ์ํฉ๋๋ค.
3. ํ๋ก์ ํธ: ๊ฐ์ฒด ํ์ง ๋๋ ์ด๋ฏธ์ง ์ธ๊ทธ๋ฉํ ์ด์ ์ ํ๋ฆฌ์ผ์ด์ ๊ฐ๋ฐ
CNN์ ํ์ฉํ์ฌ ๋ณด๋ค ๋ฐ์ ๋ ์ปดํจํฐ ๋น์ ํ๋ก์ ํธ๋ฅผ ๊ฐ๋ฐํ ์ ์์ต๋๋ค.
3.1 ๊ฐ์ฒด ํ์ง(Object Detection)
๊ฐ์ฒด ํ์ง๋ ์ด๋ฏธ์ง ๋ด์ ์ฌ๋ฌ ๊ฐ์ฒด๋ฅผ ํ์งํ๊ณ , ์์น๋ฅผ ์์ธกํ๋ ๊ธฐ์ ์ ๋๋ค. ๋ํ์ ์ธ ๋ชจ๋ธ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- YOLO(You Only Look Once)
- SSD(Single Shot MultiBox Detector)
- Faster R-CNN
๊ฐ๋ฐ ์์ด๋์ด
- ์ค์๊ฐ CCTV ์์์์ ์ฌ๋ ๋๋ ์ฐจ๋ ํ์ง
- ์ค๋งํธ ํฉํ ๋ฆฌ์์ ๊ฒฐํจ ์ ํ ์๋ ๊ฐ์ง ์์คํ ๊ตฌ์ถ
3.2 ์ด๋ฏธ์ง ์ธ๊ทธ๋ฉํ ์ด์ (Image Segmentation)
์ด๋ฏธ์ง ์ธ๊ทธ๋ฉํ ์ด์ ์ ํฝ์ ๋จ์๋ก ๊ฐ์ฒด๋ฅผ ๊ตฌ๋ถํ๋ ๊ธฐ์ ๋ก, ์ฃผ์ ๋ชจ๋ธ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- U-Net: ์๋ฃ ์์ ๋ถ์์์ ๋ง์ด ์ฌ์ฉ๋จ
- Mask R-CNN: ๊ฐ์ฒด ํ์ง์ ํฝ์ ๋จ์ ๋ถํ ์ ๋์์ ์ํ
๊ฐ๋ฐ ์์ด๋์ด
- ์๋ฃ ์์์์ ์์ธํฌ ์๋ ํ์ง
- ์์จ์ฃผํ ์ฐจ๋์ ์ํ ๋๋ก ๋ฐ ์ฐจ์ ์ธ์
from ultralytics import YOLO
import cv2
import numpy as np
import torch
from ultralytics.nn.tasks import DetectionModel
from torch.nn.modules.container import Sequential
from ultralytics.nn.modules import Conv
# YOLO ๋ชจ๋ธ ๋ก๋ ์ ์ ์์ ํ ๊ธ๋ก๋ฒ ์ค์ ์ถ๊ฐ
torch.serialization.add_safe_globals([DetectionModel, Sequential, Conv])
# ์๋ณธ torch.load ํจ์ ์ ์ฅ
_original_load = torch.load
# torch.load ์ฌ์ ์
def custom_load(f, *args, **kwargs):
kwargs['weights_only'] = False
return _original_load(f, *args, **kwargs)
torch.load = custom_load
def preprocess_image(img):
# ์ด๋ฏธ์ง ํฌ๊ธฐ ์ต์ ํ
img = cv2.resize(img, (640, 640))
return img
def detect_vehicles(image_path):
# YOLO ๋ชจ๋ธ ๋ก๋ ๋ฐ ์ต์ ํ
model = YOLO('yolov8n.pt')
device = 'cuda' if torch.cuda.is_available() else 'cpu'
model = model.to(device)
if device == 'cuda':
model = model.half()
# ์ด๋ฏธ์ง ๋ก๋ ๋ฐ ์ ์ฒ๋ฆฌ
img = cv2.imread(image_path)
if img is None:
raise ValueError("์ด๋ฏธ์ง๋ฅผ ๋ถ๋ฌ์ฌ ์ ์์ต๋๋ค.")
# ์๋ณธ ์ด๋ฏธ์ง ํฌ๊ธฐ ์ ์ง
original_img = img.copy()
# ๊ฐ์ฒด ๊ฒ์ถ ์ํ
results = model(img, conf=0.3, iou=0.45)
# ๊ฒ์ถ ๋์ ํด๋์ค ID (COCO dataset ๊ธฐ์ค)
target_classes = {
0: 'person', # ์ฌ๋
2: 'car', # ์๋์ฐจ
3: 'motorcycle', # ์คํ ๋ฐ์ด
5: 'bus', # ๋ฒ์ค
7: 'truck' # ํธ๋ญ
}
detection_count = {'person': 0, 'vehicle': 0}
detected_boxes = []
# ๊ฒ์ถ๋ ๊ฐ์ฒด์ ๋ํด ์ฒ๋ฆฌ
for result in results:
boxes = result.boxes
for box in boxes:
cls = int(box.cls[0])
conf = float(box.conf[0])
# ๋์ ํด๋์ค๋ง ์ฒ๋ฆฌ
if cls in target_classes:
# ์ค๋ณต ๊ฒ์ถ ๋ฐฉ์ง๋ฅผ ์ํ IoU ์ฒดํฌ
current_box = box.xyxy[0].cpu().numpy()
is_duplicate = False
for detected_box in detected_boxes:
iou = calculate_iou(current_box, detected_box)
if iou > 0.45:
is_duplicate = True
break
if not is_duplicate:
# ์ฌ๋๊ณผ ์ฐจ๋ ์นด์ดํธ ๋ถ๋ฆฌ
if cls == 0:
detection_count['person'] += 1
color = (0, 255, 0) # ์ด๋ก์ (์ฌ๋)
else:
detection_count['vehicle'] += 1
color = (0, 0, 255) # ๋นจ๊ฐ์ (์ฐจ๋)
detected_boxes.append(current_box)
# ๋ฐ์ด๋ฉ ๋ฐ์ค ๊ทธ๋ฆฌ๊ธฐ
x1, y1, x2, y2 = map(int, current_box)
cv2.rectangle(original_img, (x1, y1), (x2, y2), color, 2)
# ํด๋์ค์ ์ ๋ขฐ๋ ํ์
label = f"{target_classes[cls]}: {conf:.2f}"
cv2.putText(original_img, label, (x1, y1-10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)
print(f"๊ฒ์ถ๋ ์ฌ๋ ์: {detection_count['person']}")
print(f"๊ฒ์ถ๋ ์ฐจ๋ ์: {detection_count['vehicle']}")
return original_img, detection_count
def calculate_iou(box1, box2):
# IoU ๊ณ์ฐ ํจ์
x1 = max(box1[0], box2[0])
y1 = max(box1[1], box2[1])
x2 = min(box1[2], box2[2])
y2 = min(box1[3], box2[3])
intersection = max(0, x2 - x1) * max(0, y2 - y1)
box1_area = (box1[2] - box1[0]) * (box1[3] - box1[1])
box2_area = (box2[2] - box2[0]) * (box2[3] - box2[1])
union = box1_area + box2_area - intersection
return intersection / union if union > 0 else 0
def save_result(img, output_path):
cv2.imwrite(output_path, img)
print(f"๊ฒฐ๊ณผ๊ฐ {output_path}์ ์ ์ฅ๋์์ต๋๋ค.")
if __name__ == "__main__":
# ์ด๋ฏธ์ง ๊ฒฝ๋ก ์ค์
input_image = "car.jpg" # ๋ถ์ํ ์ด๋ฏธ์ง ๊ฒฝ๋ก
output_image = "result2.jpg" # ๊ฒฐ๊ณผ ์ด๋ฏธ์ง ์ ์ฅ ๊ฒฝ๋ก
# ๊ฐ์ฒด ๊ฒ์ถ ์ํ
result_img, counts = detect_vehicles(input_image)
# ๊ฒฐ๊ณผ ์ ์ฅ
save_result(result_img, output_image)
์ด๋ฒ ํฌ์คํธ์์๋ ์ปดํจํฐ ๋น์ ์ ๊ฐ๋ ๊ณผ CNN์ ์๋ฆฌ๋ฅผ ์ดํดํ๊ณ , Python์ ํ์ฉํ์ฌ CNN ๊ธฐ๋ฐ์ ์ด๋ฏธ์ง ๋ถ๋ฅ ์ค์ต์ ์งํํ์ต๋๋ค. ์ด๋ฅผ ๋ฐํ์ผ๋ก ๊ฐ์ฒด ํ์ง ๋ฐ ์ด๋ฏธ์ง ์ธ๊ทธ๋ฉํ ์ด์ ๊ณผ ๊ฐ์ ๊ณ ๊ธ ์์ฉ ํ๋ก์ ํธ๋ ๊ฐ๋ฐํ ์ ์์ต๋๋ค.
์ปดํจํฐ ๋น์ ์ ๋ค์ํ ์ฐ์ ์์ ํ์ฉ๋ ์ ์๋ ๊ฐ๋ ฅํ ๊ธฐ์ ์ ๋๋ค. ์ฌ๋ฌ๋ถ๋ ์ง์ CNN์ ํ์ฉํ ํ๋ก์ ํธ๋ฅผ ์งํํด ๋ณด๋ฉด์ ๋ ๊น์ด ์๋ ๊ฒฝํ์ ์์๋ณด์๊ธธ ๋ฐ๋๋๋ค.
์ง๋ฌธ์ด๋ ์๊ฒฌ์ด ์์ผ์๋ฉด ๋๊ธ๋ก ๋จ๊ฒจ์ฃผ์ธ์! ๐
'์ ๋ฌธ์ฑ์ ๋ฌด์์ผ๋ก ๋ง๋ค์ด์ง๋๊ฐ ๐ > ์ด๋ก ๊ณผ ์ค์ต์ผ๋ก ๋ฐฐ์ฐ๋ AI ์ ๋ฌธ ๐ค' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
4. ๋ฅ๋ฌ๋ ์ ๋ฌธ (1) | 2025.01.14 |
---|---|
3. ๋จธ์ ๋ฌ๋ ๊ธฐ์ด (5) | 2025.01.05 |
2. ํ์ด์ฌ ํ๋ก๊ทธ๋๋ฐ๊ณผ ๋ฐ์ดํฐ ์ฒ๋ฆฌ (7) | 2024.12.12 |
1. ์ธ๊ณต์ง๋ฅ ๊ธฐ์ด์ ์์ด๋์ด (3) | 2024.12.09 |
0. ์ธ๊ณต์ง๋ฅ ์ ๋ฌธ ์ปค๋ฆฌํ๋ผ ์์ฑํ๊ธฐ (9) | 2024.12.03 |