Developer's Development

3.3.20 [LLM] 자연어-이미지 멀티모달: etc 본문

LLM

3.3.20 [LLM] 자연어-이미지 멀티모달: etc

mylee 2025. 9. 15. 18:01
OpenCV

 

오픈소스 컴퓨터 비전 라이브러리

 

  • 주요 기능

1. 이미지 처리

2. 비디오 분석

3. 컴퓨터 비전 알고리즘

4. 딥러닝 통합

 

  • 가상환경 생성
conda create -n cv_env python=3.12
conda activate cv_env
pip install jupyter notebook ipykernel matplotlib
python -m ipykernel instal --user --name cv_env --display-name cv_env

 

  • Jupyter Notebook
!pip install opencv-python

 

1. 이미지 처리

import cv2

img = cv2.imread('maenggu.jpg')	# cv2.IMREAD_COLOR (기본값)
img = cv2.imread('maenggu.jpg', cv2.IMREAD_GRAYSCALE)   # 흑백이미지 (덮어씌워짐, 색상 좌표 변경)

cv2.imshow('My Maenggu', img)	# 창 이름 설정
cv2.waitKey(0)					# 키보드 입력을 기다림
cv2.destroyAllWindows()			# 창이 사라짐

 

2. 동영상 처리

cap = cv2.VideoCapture('video.mp4')

frame_count = cap.get(cv2.CAP_PROP_FRAME_COUNT) # 영상을 구성하고 있는 전체 frame의 수
fps = cap.get(cv2.CAP_PROP_FPS)                 # 1초당 몇 개의 frame으로 구성되어 있는지
width = cap.get(cv2.CAP_PROP_FRAME_WIDTH)       # 너비와 높이를 픽셀 수로 반환
height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
print(frame_count, fps, width, height)			# 350.0 25.0 640.0 360.0

while cap.isOpened():
    ret, frame = cap.read()		# 다음 frame을 읽어옴 (ret: 성공 여부, frame: 읽어온 이미지 frame)

    if not ret:		# 읽어올 게 없거나 오류면 멈춤
        break

    cv2.imshow('My Video', frame)

    if cv2.waitKey(int(1000/fps)) == ord('q'):	# q를 누르면 영상 중단
        break

cap.release()   # 자원 반납
cv2.destroyAllWindows()

 

3. 웹캠 영상 처리

cap = cv2.VideoCapture(0)   # 0을 넣으면 기본 내장 카메라(웹캠) 입력을 받음

if not cap.isOpened():
    print("Error: 웹캠을 열 수 없습니다.")
    exit()

while True:
    ret, frame = cap.read()

    if not ret:
        break

    cv2.imshow('My WebCam', frame)

    if cv2.waitKey(1) == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

 

 

OCR (Optical Character Recognition)

 

이미지 → 텍스트 추출

!pip install easyocr --user		# 현재 로그인한 사용자에 대해 전용으로 패키지 설치
import easyocr

reader = easyocr.Reader(['ko', 'en'])	# 이미지로부터 인식할 언어

result = reader.readtext('poem.jpg')

# result
for box, text, conf in result:
    print(text)

 

이미지의 텍스트 → 번역

!pip install paddlepaddle paddleocr scikit-learn translate
from paddleocr import PaddleOCR

ocr = PaddleOCR(lang='korean')
result = ocr.ocr('poem.jpg')

# result

result = result[0]

texts = result['rec_texts']
confs = result['rec_scores']
boxes = result['rec_boxes']

for text, conf, box in zip(texts, confs, boxes):
    print(f"텍스트: {text}, 신뢰도: {conf}, 텍스트 박스 위치: {box}")
    
# 아까보다 신뢰도 높게 잘 가져옴
"""
텍스트: 윤동주시인의‘서시', 신뢰도: 0.930273711681366, 텍스트 박스 위치: [177 ...  68]
텍스트: 죽는날까지하늘을 우러러, 신뢰도: 0.9459652304649353, 텍스트 박스 위치: [146 ... 117]
텍스트: 한점부끄럼이없기를, 신뢰도: 0.9719920754432678, 텍스트 박스 위치: [160 ... 139]
텍스트: 잎새에이는바람에도, 신뢰도: 0.989228367805481, 텍스트 박스 위치: [163 ... 164]
텍스트: 나는 괴로워했다, 신뢰도: 0.93855881690979, 텍스트 박스 위치: [180 ... 184]
텍스트: 별을노래하는마음으로, 신뢰도: 0.9662727117538452, 텍스트 박스 위치: [150 ... 208]
텍스트: 모든죽어가는것을사랑해야지, 신뢰도: 0.9785605072975159, 텍스트 박스 위치: [110 ... 230]
텍스트: 그리고나한테주어진길을, 신뢰도: 0.9853016138076782, 텍스트 박스 위치: [130 ... 252]
텍스트: 걸어가야겠다, 신뢰도: 0.9982728958129883, 텍스트 박스 위치: [181 ... 273]
텍스트: 오늘밤에도별이바람에스치운다., 신뢰도: 0.9415201544761658, 텍스트 박스 위치: [ 88 ... 322]
"""
import numpy as np

def point_center(box):
    x_center = box[0] + box[2] / 2
    y_center = box[1] + box[3] / 2
    return np.array([x_center, y_center])
from sklearn.cluster import DBSCAN

def cluster_boxes(boxes, eps=100):
    center = np.array([point_center(box) for box in boxes])
    clustering = DBSCAN(eps=eps, min_samples=1).fit(center)
    labels = clustering.labels_

    clusters = {}
    for i, label in enumerate(labels):
        clusters.setdefault(label, []).append(i)
    return list(clusters.values())
    
boxes = result['rec_boxes']

box_point_data = [
    [int(x1), int(y1), int(x2-x1), int(y2-y1)] for (x1, y1, x2, y2) in boxes
]

cluster_result = cluster_boxes(box_point_data)
from translate import Translator

translator = Translator(from_lang='ko', to_lang='en')

doc_result = [" ".join([texts[word_idx] for word_idx in cluster])
              for cluster in cluster_result]
eng_doc = [translator.translate(text) for text in doc_result]

print(doc_result)
print(eng_doc)
"""
["윤동주시인의‘서시' 죽는날까지하늘을 우러러 한점부끄럼이없기를 잎새에이는바람에도 나는 괴로워했다 별을노래하는마음으로 모든죽어가는것을사랑해야지 그리고나한테주어진길을 걸어가야겠다 오늘밤에도별이바람에스치운다."]
["Yoon Dong-ju's ‘Searcy‘ looked up to the sky until the day he died, so that there would be no shame in the wind on the leaves, but I was distressed. With the mindset of singing the stars, I should love all things dying, and walk the path that was given to me. Even tonight, the stars are clearing the wind."]
"""

 

 

YOLO를 사용한 객체 탐지

 

👉🏻 객체 탐지의 응용 분야

자율 주행 자동차, 영상 감시 시스템, 의료 영상 분석, 스마트 팩토리(생산 라인에서 제품의 결함이나 이상을 자동으로 탐지) 등

 

👉🏻 객체 탐지 모델 구분

1. 1-Stage Detector

- 구조: 이미지를 입력 받아 한 번에 객체의 위치와 클래스를 예측한다.

- 주요 모델: YOLO (You Only Look Once)

2. 2-Stage Detector

- 구조: 먼저 객체가 있을 가능성이 높은 영역을 추출한 후, 해당 여역에서 클래스와 위치를 예측하는 두 단계로 이루어진다.

 

  • YOLO

객체 탐지를 위한 실시간 알고리즘

 

👉🏻 주요 특징

- 속도: 실시간 처리가 가능할 정도로 빠르다.

- 단일 신경망 구조: 이미지를 여러 영역으로 나누고 각 영역에서 바운딩 박스와 확률을 예측한다.

- 전역 정보 활용: 전체 이미지를 기반으로 예측하기 때문에 문맥 정보를 잘 활용한다.

 

👉🏻 대표적인 데이터셋

Pascal VOC (사람, 차량, 가구 등을 구분 가능)

MS COCO

Google OpenImages

 

 

실습 (객체 탐지 학슴용 Datasets, vscode)

 

👇🏻 Download Dataset as zip

https://www.kaggle.com/datasets/gopalbhattrai/pascal-voc-2012-dataset?resource=download

 

PASCAL VOC 2012 DATASET

PASCAL VOC 2012 DATASET

www.kaggle.com

import cv2
import matplotlib.pyplot as plt

image_path = '.\\archive\\VOC2012_train_val\\VOC2012_train_val\\JPEGImages\\2007_000032.jpg'

image = cv2.cvtColor(cv2.imread(image_path), cv2.COLOR_BGR2RGB)
plt.imshow(image)

!pip install lxml
import os
import xml.etree.ElementTree as ET

base_dir = os.path.join('archive', 'VOC2012_train_val', 'VOC2012_train_val')
xml_path = os.path.join(base_dir, 'Annotations', '2007_000032.xml')

tree = ET.parse(xml_path)
root = tree.getroot()

filename = root.find('filename').text
size = root.find('size')
width = size.find('width').text
height = size.find('height').text
depth = size.find('depth').text

print(filename, size, width, height, depth, sep=" / ")
print(image.shape)
"""
2007_000032.jpg / <Element 'size' at 0x000001D28A27FB50> / 500 / 281 / 3
(281, 500, 3)
"""
objs = root.findall('object')

base_image = image.copy()

for obj in objs:
    bnd_box = obj.find('bndbox')
    name = obj.find('name').text
    xmin = int(bnd_box.find('xmin').text)
    ymin = int(bnd_box.find('ymin').text)
    xmax = int(bnd_box.find('xmax').text)
    ymax = int(bnd_box.find('ymax').text)
    print(f"{name} : ({xmin}, {ymin}), ({xmax}, {ymax})")

    cv2.rectangle(base_image, (xmin, ymin), (xmax, ymax), color=(0, 255, 0), thickness=2)
    cv2.putText(base_image, name, (xmin, ymin-5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), thickness=2)
    
plt.imshow(base_image)
"""
aeroplane : (104, 78), (375, 183)
aeroplane : (133, 88), (197, 123)
person : (195, 180), (213, 229)
person : (26, 189), (44, 238)
"""

 

 

영역 추정 (Region Proposal, vscode)

 

cv_env 환경

!pip install selectivesearch
import cv2
import matplotlib.pyplot as plt

image = cv2.cvtColor(cv2.imread("lucky.jpg"), cv2.COLOR_BGR2RGB)
plt.imshow(image)
import selectivesearch as ss

img, regions = ss.selective_search(image, scale=100, min_size=2000)
regions
candidate_bnd_boxes = [region['rect'] for region in regions]

base_image = image.copy()

for candidate in candidate_bnd_boxes:
    x1, y1, width, height = candidate
    x2, y2 = x1 + width, y1 + height

    cv2.rectangle(base_image, (x1, y1), (x2, y2), color=(0, 255, 0), thickness=1)

cv2.rectangle(base_image, (150, 150), (600, 700), color=(255, 0),thickness=2)

plt.imshow(base_image)

import numpy as np

def iou(candidate, ground_truth):
    x1 = np.maximum(candidate[0], ground_truth[0])
    y1 = np.maximum(candidate[1], ground_truth[1])
    x2 = np.maximum(candidate[2], ground_truth[3])
    y2 = np.maximum(candidate[3], ground_truth[3])

    candidate_area = (candidate[2] - candidate[0]) * (candidate[3] - candidate[1])
    ground_truth_area = (ground_truth[2] - ground_truth[0]) * (ground_truth[3] - ground_truth[1])

    intersection = np.maximum(0, x2 - x1) * np.maximum(0, y2 - y1)
    union = candidate_area + ground_truth_area - intersection

    return intersection / union
candidate_bnd_boxes = [region['rect'] for region in regions if region['size'] > 20000]
base_image = image.copy()

ground_truth_box = (150, 150, 600, 700)
cv2.rectangle(base_image, (150, 150), (600, 700), color=(255, 0),thickness=2)

for candidate in candidate_bnd_boxes:
    x1, y1, width, height = candidate
    x2, y2 = x1 + width, y1 + height

    iou_score = iou((x1, y1, x2, y2), ground_truth_box)

    if iou_score > 0.7:
        cv2.rectangle(base_image, (x1, y1), (x2, y2), color=(0, 0, 255), thickness=1)
        cv2.putText(base_image, f"{iou_score:.2f}", (x1, y1+20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), thickness=2)

plt.imshow(base_image)

 

 

YOLO (You Only Look Once, vscode)

 

https://docs.ultralytics.com/ko/#how-can-i-get-started-with-yolo-installation-and-setup

 

Ultralytics YOLO를 만나보세요 - 실시간 객체 감지 및 이미지 분할의 최신 기술입니다. 그 기능에 대해 배우고 프로젝트에서 잠재력을 극대화하십시오.

docs.ultralytics.com

!pip install ultralytics
from ultralytics import YOLO

model = YOLO("yolo11n.pt")

 

  • 이미지 객체 탐지
results = model('./resources/bus.jpg')
"""
image 1/1 c:\skn_17\LLM\09_multi_modal\09_vision\resources\bus.jpg: 640x480 4 persons, 1 bus, 357.6ms
Speed: 12.1ms preprocess, 357.6ms inference, 26.4ms postprocess per image at shape (1, 3, 640, 480)
"""

results[0].show()

 

  • 비디오 객체 탐지
results = model('./resources/Night_Day_Chase.mp4', show=False, save=True)

 

  • 웹캠 실시간 객체 탐지
import cv2

cap = cv2.VideoCapture(0)

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

    results = model(frame, verbose=False)
    frame = results[0].plot()

    cv2.imshow('YOLO WebCam', frame)
    if cv2.waitKey(1) == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()