딥러닝 프레임워크/이미지 처리

CNN_고급활용

Zoo_10th 2024. 4. 8.

1. CV : Computer Vision

컴퓨터 비전은 디지털 이미지나 비디오를 분석하여 사람처럼 이해하려는 기술 분야이다.

1) 분류(Classification)

이미지 전체를 보고 그 이미지가 어떤 범주(클래스)에 속하는지 결정한다.

예를 들어, 이미지에 고양이가 있는지, 개가 있는지 분류할 수 있다.

2) 검출(Detection)

이미지 내에서 특정 객체의 존재와 그 위치를 찾는다.

예를 들어, 이미지 내에서 고양이가 어디에 있는지를 찾아내는 것이다.

3) 분할(Segmentation)

이미지를 여러 부분으로 나누어 각 부분이 어떤 객체에 속하는지를 결정한다.

예를 들어, 이미지의 각 픽셀이 고양이에 속하는지, 배경에 속하는지 분류한다.

4) 추적(Tracking)

비디오 내에서 시간에 따라 객체의 움직임을 추적한다.

예를 들어, 비디오에서 고양이가 어떻게 움직이는지 추적할 수 있다.

5) 행동 분류(Action Recognition)

비디오를 분석하여 특정 행동이나 활동을 인식한다.

예를 들어, 비디오에서 사람이 달리는지, 걷는지를 분류한다.

1-1. 비교

1) 유연성

사람은 다양한 환경과 맥락에서 객체를 인식할 수 있는 능력이 있다. 반면, 컴퓨터 비전 시스템은 훈련 데이터와 알고리즘의 한계로 인해 특정 조건에서만 효과적으로 작동할 수 있다.

2) 속도

단순한 인식 작업에서 컴퓨터 비전 시스템은 사람보다 훨씬 빠를 수 있다. 하지만 복잡한 장면에서의 전체적인 이해와 추론에서는 사람이 컴퓨터 비전을 능가한다.

3) 확장성

컴퓨터 비전은 대량의 데이터를 처리하는 데 매우 효과적이며, 반복적인 작업에서 일관된 성능을 보인다. 사람은 이러한 대규모 데이터 처리에 취약할 수 있다.

2. 검출(Detection)

검출(Detection) 작업은 컴퓨터 비전 분야에서 중요한 문제 중 하나이다. 검출 작업의 목표는 이미지 내의 여러 객체를 식별하고, 각 객체의 위치를 바운딩 박스(Bounding Box)로 표시하며, 해당 객체의 부류(Category)를 지정하는 것이다. 이 과정에서 검출 모델의 성능을 평가하기 위해 몇 가지 핵심적인 성능 척도를 사용한다.

2-1. 성능 척도

1) IoU (Intersection over Union)

 - IoU는 예측된 바운딩 박스와 실제 바운딩 박스(ground truth)의 겹치는 영역 대비 합쳐진 영역의 비율을 측정한다. 이 값은 0과 1 사이의 값으로 표현되며, 1에 가까울수록 예측된 바운딩 박스가 실제 바운딩 박스와 잘 일치한다는 것을 의미한다.

2) mAP (Mean Average Precision)

 - mAP는 모든 부류에 대한 평균 정밀도(Average Precision, AP)의 평균값이다. 각 객체 부류에 대해 정밀도-재현율 곡선을 계산하고, 이 곡선 아래의 면적을 AP로 정의한다. mAP는 이러한 AP값들의 평균을 나타내며, 객체 검출 모델의 전반적인 성능을 나타내는 지표로 사용된다.

 - 정밀도: 예측된 객체 중 실제 객체로 올바르게 예측된 비율이다. 높은 정밀도는 오진(False Positive)이 적음을 의미한다.

 -  실제 객체 중 모델이 올바르게 예측한 객체의 비율이다. 높은 재현율은 미검출(False Negative)이 적음을 의미한다.

2-2. RCNN

R-CNN(Regions with Convolutional Neural Networks)은 객체 검출 분야에서 혁신적인 발전을 이끈 중요한 알고리즘 중 하나이다. Ross Girshick 등에 의해 2014년에 제안되었다. R-CNN의 핵심 아이디어는 이미지에서 객체 후보 영역(Region Proposals)을 추출하고, 각 영역에 대해 CNN을 적용하여 특징을 추출한 뒤, 분류기(SVM)를 사용하여 각 영역의 객체를 분류하는 것이다. 이 과정을 통해 이미지 내의 다양한 객체를 정확하게 검출할 수 있다.

2-3. R-CNN의 주요 단계

1) 지역 제안(Region Proposal) 생성

선택적 검색(Selective Search) 알고리즘을 사용하여 약 2000개의 지역 제안을 생성한다. 이 지역 제안들은 이미지에서 객체가 존재할 가능성이 있는 영역들이다.

2) CNN을 통한 특징 추출

각 지역 제안을 고정된 크기로 조정하고, 사전 훈련된 CNN(예: AlexNet)을 통과시켜 특징 벡터를 추출한다.

3) SVM을 사용한 객체 분류

추출된 특징 벡터를 사용하여 각 지역 제안에 대한 객체의 클래스를 분류합니다. 각 클래스에 대해 독립적인 이진 SVM 분류기가 사용된다.

4) 경계 상자 회귀(Bounding Box Regression)

SVM에 의해 분류된 지역 제안의 위치를 보다 정확하게 조정하기 위해 경계 상자 회귀 분석을 수행한다.

2-4. 선택적 검색(Selective Search)

선택적 검색은 지역 제안을 생성하기 위한 알고리즘으로, 초기 하위 분할에서 시작하여 유사한 영역을 재귀적으로 결합하는 방식으로 작동한다. 이 과정에서 색상, 텍스처, 크기 및 채우기 비율과 같은 다양한 유사성 기준을 고려한다.

2-5. 장점과 한계

1) 장점

R-CNN은 이전 방법들에 비해 높은 정확도를 달성했다. 특히, 각 객체 후보에 대해 딥러닝 기반의 특징을 추출함으로써 객체 검출의 성능을 크게 향상시켰다.

2) 한계

R-CNN의 가장 큰 단점은 계산 비용이다. 2000개의 지역 제안 각각에 대해 CNN을 독립적으로 실행해야 하기 때문에, 추론 시간이 매우 길다는 단점이 있다. 또한, SVM 분류기와 경계 상자 회귀기를 별도로 학습시켜야 한다는 점에서 학습 과정이 복잡하다.

2-5. Fast R-CNN과 Faster R-CNN

R-CNN의 계산 비용 문제를 해결하기 위해 Fast R-CNN과 Faster R-CNN이 제안되었다. Fast R-CNN은 이미지 전체를 CNN에 한 번만 통과시킨 뒤, ROI Pooling을 사용하여 각 지역 제안의 특징을 추출하는 방법을 도입함으로써 추론 속도를 크게 향상시켰다. 더 나아가, Faster R-CNN은 선택적 검색 대신 Region Proposal Network(RPN)를 사용하여 지역 제안을 생성하는 방식을 도입함으로써, 지역 제안 생성과정을 CNN과 통합하고 전체 모델을 end-to-end로 학습할 수 있게 되었다. 이러한 발전을 통해 객체 검출의 속도와 정확도가 크게 개선되었다.

2-6. Fast RCNN

1) 전체 이미지 특징 추출

이미지 전체를 CNN에 한 번만 통과시킨 후, 후보 영역에 해당하는 특징을 ROI Pooling을 통해 추출한다. 이는 각 후보 영역마다 CNN을 실행하는 것보다 훨씬 효율적이다.

2) Multi-task Loss

객체 분류와 Bounding Box Regression을 동시에 수행하는 하나의 네트워크를 학습한다. 이는 성능을 개선하고 학습 과정을 단순화한다.

2-7. Faster RCNN

Faster RCNN은 2015년에 Fast RCNN을 더욱 발전시킨 모델로, Selective Search 대신 객체 후보 영역을 추출하기 위해 별도의 신경망인 Region Proposal Network(RPN)을 사용한다.

1) Region Proposal Network

RPN은 이미지에서 객체 후보 영역을 빠르게 예측한다. 이는 합성곱 특징 맵 위에서 슬라이딩 윈도우 방식으로 작동한다.

2) End-to-End 학습

RPN과 Fast RCNN을 하나의 네트워크로 통합하여, 전체 모델을 end-to-end로 학습할 수 있다. 이는 학습과 추론 과정의 효율성을 대폭 개선한다.

3. Yolo

YOLO (You Only Look Once) v2는 실시간 객체 감지 시스템에서 중요한 발전을 이룬 모델이다. Joseph Redmon과 Ali Farhadi가 개발한 이 모델은 기존의 YOLO 모델을 개선하여 더 높은 정확도와 더 빠른 처리 속도를 달성했다. YOLO v2는 다양한 크기의 객체를 감지할 수 있으며, 다양한 객체 클래스에 대한 강력한 인식 능력을 제공한다.

3-1. YOLO v2의 핵심 개선 사항

1) 아키텍처 변경 (Darknet-19)

 - YOLO v1에 비해 정확도와 속도 측면에서 개선된 Darknet-19 아키텍처를 도입했다. 이 아키텍처는 19개의 컨볼루션 레이어와 5개의 맥스 풀링 레이어로 구성되어 있다.

 - 배치 정규화(Batch Normalization)를 각 컨볼루션 레이어에 추가하여 학습을 가속화하고 과적합을 줄였다.

2) 고해상도 분류기

 - 학습 초기 단계에서는 224x224 해상도를 사용하고, 이후 감지 단계에서는 448x448 해상도로 전환하여 높은 해상도에서 네트워크가 작동할 수 있도록 했다. 이를 통해 mAP가 4% 향상되었다.

3) 앵커 박스 사용

 - 앵커 박스를 도입하여 객체의 형태와 크기를 더 잘 예측할 수 있게 되었다. 이를 통해 모델은 다양한 형태와 크기의 객체를 보다 정확하게 감지할 수 있게 되었다.

4) 차원 클러스터링

 - 경계 상자의 차원을 최적화하기 위해 k-평균 클러스터링을 사용하여 앵커 박스의 차원을 결정했다. 이 방법은 모델의 정확도를 높이는 데 기여했다.

5) 직접 위치 예측

 - 위치 예측의 안정성을 높이기 위해 그리드 셀 위치에서 바운딩 박스의 중심을 예측하는 방식을 사용했다. 이는 모델의 예측 정확도를 더욱 향상시켰다.

6) 다중 규모 훈련

 - 네트워크가 다양한 크기의 이미지에 대해 학습할 수 있도록, 학습 중 이미지 크기를 동적으로 조정하는 다중 규모 훈련 방식을 적용했다.

3-2. 결과 및 성과

YOLO v2는 PASCAL VOC 2007 데이터셋에서 76.8%의 mAP를 달성했으며, VOC 2012에서는 78.6%의 mAP를 기록했다. 이러한 결과는 당시 다른 최첨단 모델들보다 우수한 성능을 보여주었다. YOLO v2는 높은 정확도와 더불어 실시간 처리가 가능한 빠른 속도를 제공함으로써, 실시간 비디오 스트림 분석 및 대규모 이미지 데이터셋 처리에 효과적인 솔루션을 제공했다.

YOLO v2의 성공은 객체 감지 분야에 큰 영향을 미쳤으며, 이후 버전의 YOLO 및 다른 객체 감지 모델 개발에 중요한 기초를 마련했다. YOLO 시리즈의 계속되는 발전은 컴퓨터 비전 분야에서의 실시간 객체 감지 기술의 발전을 이끌고 있다.

4. Yolo 객체 탐지

import numpy as np
import cv2
import sys

path = 'dataset/'

def construct_yolo_v3():
  
  ## coco dataset 클래스 이름을 가져오기
  f = open( path + 'coco_names.txt', 'r')
  class_names = [line.strip() for line in f.readlines()]

  ## YOLO v3 모델과 가중치 로드
  model = cv2.dnn.readNet(path + 'yolov3.weights', path + 'yolov3.cfg')

  ## 각 레이어의 이름 정보 추출
  layer_names = model.getLayerNames()

  ## 3개의 출력 레이어 결정
  out_layers = [layer_names[i -1] for i in model.getUnconnectedOutLayers()]

  return model, out_layers, class_names

def yolo_detect(img, yolo_model, out_layers):
  ## 이미지의 크기정보
  height, width = img.shape[:2]

  ## 이미지에서 네트워크에 입력할 blob을 생성
  ## 데이터 전처리 작업
  test_img = cv2.dnn.blobFromImage(img, 1.0 / 255, (448, 448), (0,0,0), swapRB=True)

  ## test_img를 입력으로 사용
  ## Yolo의 입력으로 테스트 데이터 사용
      # 생성된 blob을 네트워크의 입력으로 설정합니다.
  yolo_model.setInput(test_img)
    
    # 네트워크를 실행하여 출력 레이어에서 결과를 얻습니다.
  output3 = yolo_model.forward(out_layers)

  ## 검출된 박스, 신뢰도, 각 클래스 ID 
  box, conf, id = [], [], []
  
  ## 반복문을 사용하여 Box 생성
  for output in output3:
    for detection in output:
      scores = detection[5:]
      class_id = np.argmax(scores)
      confidence = scores[class_id]
      if confidence > 0.5:
        center_x, center_y = int(detection[0] * width), int(detection[1] * height)
        w, h = int(detection[2] * width), int(detection[3] * height)
        x, y = int(center_x - w / 2), int(center_y - h / 2)
        box.append([x,y,x+w, y+h])
        conf.append(float(confidence))
        id.append(class_id)

  ## NMS를 사용해서 중복된 박스를 제거합니다.
  indices = cv2.dnn.NMSBoxes(box, conf, 0.5, 0.4)
  objects = [box[i] + [conf[i]] + [id[i]] for i in range(len(box)) if i in indices]

  return objects

## 모델 생성
model, out_layers, class_names = construct_yolo_v3()

## 클래스별로 색상지정
colors = np.random.uniform(0, 255, size=(len(class_names), 3))

## 이미지 불러오기
img = cv2.imread(path + 'soccer.jpg')
if img is None:
  sys.exit('파일 없음')

## Yolo Detecting
res = yolo_detect(img, model, out_layers)

for i in range(len(res)):
  x1, y1, x2, y2, confidence, id = res[i]
  text = f"{class_names[id]}: {confidence: .3f}"
  cv2.rectangle(img, (x1, y1), (x2, y2), colors[id], 2)
  cv2.putText(img, text, (x1, y1 + 30), cv2.FONT_HERSHEY_PLAIN, 1.5, colors[id], 2)

## 결과 표시
cv2.imshow("YOLO V3_Object Detection ", img)
cv2.waitKey()
cv2.destroyAllWindows()

4-1. Yolo 비디오 객체 탐지

pip install pytube
from pytube import YouTube
import cv2 as cv
import numpy as np
import sys

# 유튜브 동영상 다운로드 함수
def download_youtube_video(url, save_path='downloaded_video.mp4'):
    yt = YouTube(url)
    stream = yt.streams.filter(file_extension='mp4').first()
    stream.download(filename=save_path)
    print(f"Video downloaded to {save_path}")

# YOLO v3 모델 구성과 초기화
def construct_yolo_v3():
    # COCO 데이터셋 클래스 이름을 로드합니다.
    f = open('coco_names.txt', 'r')
    class_names = [line.strip() for line in f.readlines()]

    # YOLO v3 모델과 가중치를 로드합니다.
    model = cv.dnn.readNet('yolov3.weights', 'yolov3.cfg')
    
    # 모델의 레이어 이름을 가져옵니다.
    layer_names = model.getLayerNames()
    
    # 출력 레이어를 결정합니다. YOLO는 세 개의 출력 레이어를 가집니다.
    out_layers = [layer_names[i[0] - 1] for i in model.getUnconnectedOutLayers()]
    
    return model, out_layers, class_names

# 이미지에 대해 YOLO 객체 감지를 수행하는 함수
def yolo_detect(img, yolo_model, out_layers):
    height, width = img.shape[:2]
    
    # 이미지에서 네트워크에 입력할 blob을 생성합니다.
    test_img = cv.dnn.blobFromImage(img, 1.0 / 256, (448, 448), (0, 0, 0), swapRB=True)
    
    # 생성된 blob을 네트워크의 입력으로 설정합니다.
    yolo_model.setInput(test_img)
    
    # 네트워크를 실행하여 출력 레이어에서 결과를 얻습니다.
    output3 = yolo_model.forward(out_layers)
    
    box, conf, id = [], [], []  # 검출된 박스, 신뢰도, 클래스 ID를 저장할 리스트
    for output in output3:
        for detection in output:
            scores = detection[5:]
            class_id = np.argmax(scores)
            confidence = scores[class_id]
            if confidence > 0.5:  # 신뢰도가 50% 이상인 경우만 처리
                center_x, center_y = int(detection[0] * width), int(detection[1] * height)
                w, h = int(detection[2] * width), int(detection[3] * height)
                x, y = int(center_x - w / 2), int(center_y - h / 2)
                box.append([x, y, x + w, y + h])
                conf.append(float(confidence))
                id.append(class_id)
    
    # NMS를 사용하여 중복된 박스를 제거합니다.
    indices = cv.dnn.NMSBoxes(box, conf, 0.5, 0.4)
    objects = [box[i] + [conf[i]] + [id[i]] for i in range(len(box)) if i in indices]
    
    return objects

# 유튜브 동영상 URL
youtube_url = 'https://www.youtube.com/watch?v=ZUw5rpaS-wk'

# 동영상 다운로드
download_youtube_video(youtube_url, 'downloaded_video.mp4')

# 동영상 처리 및 객체 감지
cap = cv.VideoCapture('downloaded_video.mp4')

# 결과 영상을 저장하기 위한 VideoWriter 생성
frame_width = int(cap.get(3))
frame_height = int(cap.get(4))
out = cv.VideoWriter('detected_video.avi', cv.VideoWriter_fourcc(*'XVID'), 20.0, (frame_width, frame_height))

model, out_layers, class_names = construct_yolo_v3()
colors = np.random.uniform(0, 255, size=(len(class_names), 3))

while cap.isOpened():
    ret, frame = cap.read()
    if not ret:
        break

    res = yolo_detect(frame, model, out_layers)

    for i in range(len(res)):
        x1, y1, x2, y2, confidence, id = res[i]
        text = f"{class_names[id]}: {confidence:.3f}"
        cv.rectangle(frame, (x1, y1), (x2, y2), colors[id], 2)
        cv.putText(frame, text, (x1, y1 + 30), cv.FONT_HERSHEY_PLAIN, 1.5, colors[id], 2)
    
    # 결과 프레임을 VideoWriter에 쓴다
    out.write(frame)
    
    cv.imshow("Detection", frame)
    if cv.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
out.release()
cv.destroyAllWindows()

4-2. Yolo 웹캠 객체 탐지

import numpy as np
import cv2 as cv
import sys

def construct_yolo_v3():
    # COCO 데이터셋의 클래스 이름을 로드합니다.
    f = open('coco_names.txt', 'r')
    class_names = [line.strip() for line in f.readlines()]

    # YOLO v3 모델과 설정 파일을 로드하여 모델을 생성합니다.
    model = cv.dnn.readNet('yolov3.weights', 'yolov3.cfg')
    
    # 모델의 레이어 이름을 가져옵니다.
    layer_names = model.getLayerNames()
    
    # 출력 레이어를 결정합니다. YOLO는 세 개의 출력 레이어를 가집니다.
    out_layers = [layer_names[i[0] - 1] for i in model.getUnconnectedOutLayers()]
    
    return model, out_layers, class_names

def yolo_detect(img, yolo_model, out_layers):
    # 입력 이미지의 크기를 가져옵니다.
    height, width = img.shape[:2]
    
    # 네트워크에 넣기 위해 이미지의 크기를 변경하고 전처리합니다.
    test_img = cv.dnn.blobFromImage(img, 1.0 / 256, (448, 448), (0, 0, 0), swapRB=True)
    
    # 전처리된 이미지를 모델의 입력으로 설정합니다.
    yolo_model.setInput(test_img)
    
    # 정방향 패스를 실행하여 출력을 얻습니다.
    output3 = yolo_model.forward(out_layers)
    
    box, conf, id = [], [], []  # 박스, 신뢰도, 클래스 ID
    for output in output3:
        for vec85 in output:
            scores = vec85[5:]
            class_id = np.argmax(scores)
            confidence = scores[class_id]
            if confidence > 0.5:  # 신뢰도가 50% 이상인 경우만 처리
                center_x, center_y = int(vec85[0] * width), int(vec85[1] * height)
                w, h = int(vec85[2] * width), int(vec85[3] * height)
                x, y = int(center_x - w / 2), int(center_y - h / 2)
                box.append([x, y, x + w, y + h])
                conf.append(float(confidence))
                id.append(class_id)
    
    # Non-Maximum Suppression을 적용하여 중복된 박스를 제거합니다.
    ind = cv.dnn.NMSBoxes(box, conf, 0.5, 0.4)
    objects = [box[i] + [conf[i]] + [id[i]] for i in range(len(box)) if i in ind]
    
    return objects

# YOLO 모델을 구성합니다.
model, out_layers, class_names = construct_yolo_v3()
# 각 클래스별로 무작위 색상을 생성합니다.
colors = np.random.uniform(0, 255, size=(len(class_names), 3))

# 웹캠으로부터 영상을 캡처합니다.
cap = cv.VideoCapture(0, cv.CAP_DSHOW)
if not cap.isOpened():
    sys.exit('카메라 연결 실패')

while True:
    ret, frame = cap.read()
    if not ret:
        sys.exit('프레임 획득에 실패하여 루프를 나갑니다.')
    
    # 현재 프레임에서 객체 감지를 수행합니다.
    res = yolo_detect(frame, model, out_layers)
    
    # 감지된 객체를 프레임에 표시합니다.
    for i in range(len(res)):
        x1, y1, x2, y2, confidence, id = res[i]
        text = f"{class_names[id]}: {confidence:.3f}"
        cv.rectangle(frame, (x1, y1), (x2, y2), colors[id], 2)
        cv.putText(frame, text, (x1, y1 + 30), cv.FONT_HERSHEY_PLAIN, 1.5, colors[id], 2)
    
    # 결과를 화면에 표시합니다.
    cv.imshow("Object detection from video by YOLO v.3", frame)
    
    key = cv.waitKey(1)
    if key == ord('q'):
        break

# 자원을 해제하고 창을 닫습니다.
cap.release()
cv.destroyAllWindows()
728x90

'딥러닝 프레임워크 > 이미지 처리' 카테고리의 다른 글

CNN_고급활용(2)  (2) 2024.04.12
CNN_전이학습  (0) 2024.04.04
CNN(Convolution Neural Network)  (0) 2024.04.02

댓글