영상처리 기초 - 2. OPENCV 이미지처리

김민수·2025년 3월 2일
post-thumbnail
# 본 자료는 이수안 교수님(https://suanlab.com/)의 자료를 기반으로 수정 및 보완하여 제작되었습니다.
# 제작자 : 김민수(rlaalstn1504@naver.com)

OPENCV 이미지처리

import cv2
import numpy as np
import matplotlib.pyplot as plt
from google.colab import files
from google.colab.patches import cv2_imshow

도형 그리기

  • 다양한 도형을 그릴 수 있음

  • 도형을 그리는 좌표가 해당 범위를 넘어가면 이미지에 표현되지 않음

img = np.zeros((512,512,3), np.uint8)
plt.imshow(img)
plt.show()

Line 그리기

  • cv.line()

    • Parameters

      • img : 그림을 그릴 이미지 파일

      • start : 시작 좌표

      • end : 종료 좌표

      • color : BGR형태의 Color (ex; (255, 0, 0) -> Blue)

      • thickness (int) : 선의 두께. pixel

img = cv2.line(img, (0,0), (511,511), (255,0,0), 5) # 시작, 끝, 컬러(BGR), 두께
plt.imshow(img) # 왜 붉은 색 선일까? -> B에 그렸으나 R로 인식
plt.show()

rectangle 그리기

  • cv2.rectangle()

    • Parameters

      • img : 그림을 그릴 이미지

      • start : 시작 좌표

      • end : 종료 좌표

      • color : BGR형태의 Color(ex; (255, 0, 0) -> Blue)

      • thickness (int) : 선의 두께. pixel

img = cv2.rectangle(img, (0,0), (250,350), (0,255,0), 3)
plt.imshow(img)
plt.show()

Circle 그리기

  • cv2.circle()

    • Parameters

      • img : 그림을 그릴 이미지

      • center : 원의 중심 좌표(x, y)

      • radian : 반지름

      • color : BGR형태의 Color

      • thickness : 선의 두께, -1 이면 원 안쪽을 채움

img = cv2.circle(img, (447, 63), 63, (0,0,255), -1)
plt.imshow(img)
plt.show()

img = cv2.circle(img, (63,447), 63,  (0,255,255), 2)
plt.imshow(img)
plt.show()

ellipse(타원) 그리기

  • cv2.ellipse()

    • Parameters

      • img : image

      • center : 타원의 중심

      • axes : 중심에서 가장 큰 거리와 작은 거리

      • angle : 타원의 기울기 각

      • startAngle : 타원의 시작 각도

      • endAngle : 타원이 끝나는 각도

      • color : 타원의 색

      • thickness : 선 두께. -1이면 안쪽을 채움

# 타원을 이미지에 그리기 (회색 타원)
# 중심 좌표: (255, 255), 축 길이: (100, 50), 회전 각도: 0, 호의 시작각도: 10도, 끝각도: 255도, 채우기: -1
img = cv2.ellipse(img,  (255,255), (100,50), 0,  10, 255,  -1)
plt.imshow(img)
plt.show()

# 타원을 이미지에 그리기 (흰색 타원)
# 중심 좌표: (255, 255), 축 길이: (150, 50), 회전 각도: 45, 호의 시작각도: 0도, 끝각도: 360도, 두께: 2
img = cv2.ellipse(img,  (255,255), (150,50), 45, 0, 360, (255,255,255), 2)
plt.imshow(img)
plt.show()

# 타원을 이미지에 그리기 (파란색 부분 타원)
# 중심 좌표: (255, 255), 축 길이: (150, 10), 회전 각도: 135, 호의 시작각도: 0도, 끝각도: 270도, 두께: 2
img  = cv2.ellipse(img,  (255,255), (150,10), 135, 0, 270, (0,0,255), 2)
plt.imshow(img)
plt.show()

Polygon 그리기

  • cv2.polylines()

    • Parameters

      • img : image

      • pts (array) : 연결할 꼭지점 좌표

      • isClosed : 닫힌 도형 여부

      • color : Color

      • thickness : 선 두께

  • 이미지에 표현하기 위해 점 좌표를 3차원 행렬로 변환.

    • 변환이전과 이후의 행렬 갯수는 동일해야함.
# 폴리라인(다각형)을 그리기
# 점들의 좌표 정의 (정수형 배열로 변환)
pts = np.array([[10,5], [20,30], [70,20], [50,10]], np.int32)
print(pts.shape)
(4, 2)
# 점들의 형태를 (n, 2, 1)에서 (n, 1, 2)로 변환
pts = pts.reshape((-1,2,1)) # 3차원 행렬로 변환하기 위해
print(pts.shape)
# 폴리라인 그리기, 닫힌 형태(True), 색상: 오렌지, 두께: 5
img = cv2.polylines(img, [pts], True, (0, 155, 255), 5)
(4, 2, 1)
plt.imshow(img)
plt.show()

# 또 다른 다각형 정의 및 폴리라인 그리기
pts2 = np.array([[150,5], [200,30], [100,70], [50,20]], np.int32)
print(pts2.shape)
(4, 2)
# (n, 2, 1) 형태에서 (n, 1, 2)로 변환
pts2 = pts2.reshape((-1,1,2))
print(pts2.shape)
# 폴리라인 그리기, 닫힌 형태(True), 색상: 연한 보라색, 두께: 4
img = cv2.polylines(img, [pts2], True, (172, 200, 255), 4)
(4, 1, 2)
plt.imshow(img)
plt.show()

Text 추가하기

  • cv2.putText()

    • Parameters

      • img : image

      • text : 표시할 문자열

      • org : 문자열이 표시될 위치. 문자열의 bottom-left corner 점

      • font : font type. CV2.FONT_XXX

      • fontSacle : Font Size

      • color : fond color

# 텍스트 추가
# 텍스트: 'OpenCV', 좌표: (10, 500), 폰트: SIMPLEX, 크기: 4, 색상: 흰색, 두께: 3
img = cv2.putText(img, 'OpenCV', (10, 500), cv2.FONT_HERSHEY_SIMPLEX, 4, (255,255,255), 3)
plt.imshow(img)
plt.show()

문제 : 별 그리기

img = np.zeros((540,540), np.uint8)
plt.imshow(img, cmap='gray')
plt.show()

정답 :

문제 정답: 별 그리기 (8개의 교차선으로 구성)

img = cv2.line(img, (0, 0), (270, 540), 255, 4) # 왼쪽 위 → 중앙 아래
img = cv2.line(img, (0, 0), (540, 270), 255, 4) # 왼쪽 위 → 중앙 오른쪽
img = cv2.line(img, (540, 0), (0, 270), 255, 4) # 오른쪽 위 → 중앙 왼쪽
img = cv2.line(img, (540, 0), (270, 540), 255, 4) # 오른쪽 위 → 중앙 아래
img = cv2.line(img, (0, 540), (270, 0), 255, 4) # 왼쪽 아래 → 중앙 위
img = cv2.line(img, (0, 540), (540, 270), 255, 4) # 왼쪽 아래 → 중앙 오른쪽
img = cv2.line(img, (540, 540), (0, 270), 255, 4) # 오른쪽 아래 → 중앙 왼쪽
img = cv2.line(img, (540, 540), (270, 0), 255, 4) # 오른쪽 아래 → 중앙 위

이미지 처리 (Image Processing)

# 이미지 다운로드 주소 : https://upload.wikimedia.org/wikipedia/ko/2/24/Lenna.png
files.upload()
image = cv2.imread('Lenna.png')
print(image.shape)
cv2_imshow(image)

Resize

  • cv2.resize()

    • 사이즈가 변하면 pixel사이의 값을 결정을 해야함

    • 보간법(Interpolation method)

      • 사이즈를 줄일 때 : cv2.INTER_AREA

      • 사이즈를 크게 할 때 : cv2.INTER_CUBIC , cv2.INTER_LINEAR

    • Parameters

      • img : Image

      • dsize : Manual Size. 가로, 세로 형태의 tuple(ex; (100,200))

      • fx : 가로 사이즈의 배수. 2배로 크게하려면 2. 반으로 줄이려면 0.5

      • fy : 세로 사이즈의 배수

      • interpolation : 보간법

cv2_imshow(image)

'''
cv2.resize(src, dsize[, dst[, fx[, fy[, interpolation]]]])
여기서 각 인자는 다음을 의미합니다:

src: 크기를 조절하려는 원본 이미지입니다.
dsize: 새로운 이미지의 크기입니다. (width, height) 형식의 튜플로 지정할 수 있습니다.
dst: 선택적으로, 크기를 조절한 이미지를 저장할 곳을 지정합니다. 이 인자를 생략하면 함수가 새로운 이미지를 반환합니다.
fx: 선택적으로 가로 방향 크기의 배율 요인입니다.
fy: 선택적으로 세로 방향 크기의 배율 요인입니다.
interpolation: 선택적으로 크기 조절에 사용할 보간법을 지정합니다. 기본값은 cv2.INTER_LINEAR로, 선형 보간법을 사용합니다.
다른 옵션으로는 cv2.INTER_NEAREST, cv2.INTER_AREA, cv2.INTER_CUBIC, cv2.INTER_LANCZOS4 등이 있습니다.
'''
height, width = image.shape[:2]
print(height, width)

shrink = cv2.resize(image, (0,0), fx=0.5, fy=0.5, interpolation=cv2.INTER_AREA) # 새 이미지의 크기를 직접 지정하지 않은 것
print(shrink.shape)
expand1 = cv2.resize(image, (width*2, height*2), interpolation=cv2.INTER_CUBIC)  # 크기 2배 확대
print(expand1.shape)
expand2 = cv2.resize(image, None, fx=2, fy=2, interpolation=cv2.INTER_CUBIC)  # 크기 2배 확대 (명시적 크기 미지정)
print(expand2.shape)
220 220
(110, 110, 3)
(440, 440, 3)
(440, 440, 3)
cv2_imshow(shrink)  # 축소된 이미지 표시
cv2_imshow(expand1)  # 확대된 이미지 표시 (방식 1)
cv2_imshow(expand2)  # 확대된 이미지 표시 (방식 2)

Translation

  • 이미지의 위치를 변경

  • cv2.warpAffine()

    • Parameters

      • src : Image

      • M : 변환 행렬

      • dsize (tuple) : output image size(ex; (width=columns, height=rows)

'''
[1, 0, 10], [0, 1, 20]

1: 축 방향의 스케일링 비율을 나타내며, 이 경우 1이므로 x축 방향의 크기 변화가 없음을 의미합니다.
0: y축으로부터 x축으로의 기울기(회전)를 나타냅니다. 0이므로 이 방향으로의 회전이 없음을 의미합니다.
10: x축 방향으로의 이동(변환)을 나타내며, 이 값은 이미지를 오른쪽으로 10 픽셀 이동시킵니다.

0: x축으로부터 y축으로의 기울기(회전)를 나타냅니다. 0이므로 이 방향으로의 회전이 없음을 의미합니다.
1: y축 방향의 스케일링 비율을 나타내며, 이 경우 1이므로 y축 방향의 크기 변화가 없음을 의미합니다.
20: y축 방향으로의 이동(변환)을 나타내며, 이 값은 이미지를 아래로 20 픽셀 이동시킵니다.
'''
# 이미지 이동 (Translation)
rows, cols = image.shape[:2]
M = np.float32([[1, 0, 10], [0, 1, 20]])  # 이동 행렬: x축 10 픽셀, y축 20 픽셀 이동
dst = cv2.warpAffine(image, M, (cols, rows))  # 이동 적용
cv2_imshow(dst)  # 이동된 이미지 표시

Rotate

  • 물체를 평면상의 한 점을 중심으로 𝜃 만큼 회전하는 변환

  • 양의 각도는 시계반대방향으로 회전

  • cv2.getRotationMatrix2D()

    • Parameters

      • center : 이미지의 중심 좌표

      • angle : 회전 각도

      • scale : scale factor

# 이미지 회전
rows, cols, _ = image.shape
M = cv2.getRotationMatrix2D((cols / 2, rows / 2), 45, 1)  # 중심에서 45도 회전
rotated_img = cv2.warpAffine(image, M, (cols, rows))  # 회전 적용
cv2_imshow(rotated_img) # 회전된 이미지 표시

Flip

  • 대칭 변환

    • 좌우 대칭 (좌우 반전)

    • 상하 대칭 (상하 반전)

  • 입력 영상과 출력 영상의 픽셀이 1:1 매칭이므로 보간법이 필요 없음

  • cv2.flip()

    • Parameters

      • src : 입력 영상

      • flipCode : 대칭 방법을 결정하는 flag 인자

        • 양수이면 좌우 대칭

        • 0이면 상하 대칭

        • 음수이면 상하, 좌우 대칭을 모두 실행

result2 = cv2.flip(image, 0)  # 수직 뒤집기
result3 = cv2.flip(image, 1)  # 수평 뒤집기
cv2_imshow(result2)  # 수직 뒤집힌 이미지 표시
cv2_imshow(result3)  # 수평 뒤집힌 이미지 표시

Affine Transformation

  • 기하학적 도형의 크기와 각도를 변경할 수 있지만, 원점 간의 상대적인 위치(선의 평행성과 점들 간의 비율)는 보존

  • 이동, 확대, Scale, 반전까지 포함된 변환

  • cv2.getAffineTransform()

    • Affine 변환을 위해서는 3개의 Match가 되는 점이 있으면 변환행렬을 구할 수 있음

# 원본 이미지의 크기와 채널 정보 가져오기
# rows: 이미지의 높이(픽셀 수), cols: 너비(픽셀 수), ch: 채널 수 (컬러 이미지라서 3)
rows, cols, ch = image.shape

# Affine 변환을 위한 원본 좌표와 이동 좌표 설정
# 원본 좌표: pts1 (Affine 변환 전의 3개 점)
pts1 = np.float32([[100, 50], [200, 50], [100, 100]])
# 이동 좌표: pts2 (Affine 변환 후의 3개 점)
pts2 = np.float32([[100, 150], [200, 100], [100, 200]])

# Affine 변환에서 사용하는 3개의 점 시각화를 위해 원본 이미지에 원 그리기
# 첫 번째 점 (200, 100) 빨간색 점
cv2.circle(image, (200, 100), 10, (255, 0, 0), -1)  # 색상: 빨강 (BGR 형식), 두께: -1 (채우기)
# 두 번째 점 (400, 100) 초록색 점
cv2.circle(image, (400, 100), 10, (0, 255, 0), -1)  # 색상: 초록 (BGR 형식), 두께: -1 (채우기)
# 세 번째 점 (200, 200) 파란색 점
cv2.circle(image, (200, 200), 10, (0, 0, 255), -1)  # 색상: 파랑 (BGR 형식), 두께: -1 (채우기)

# 원본 좌표(pts1)와 이동 좌표(pts2)를 기반으로 Affine 변환 행렬 계산
# M: 2x3 변환 행렬, 이 행렬은 점들의 위치를 기반으로 전체 이미지를 변환하는 데 사용됨
M = cv2.getAffineTransform(pts1, pts2)

# Affine 변환 적용
# cv2.warpAffine(): 이미지를 변환 행렬(M)을 기반으로 변환
# cols, rows: 결과 이미지의 크기 (원본 이미지와 동일하게 설정)
dst = cv2.warpAffine(image, M, (cols, rows))

# 변환된 이미지(dst) 출력
cv2_imshow(dst)  # Google Colab에서 이미지를 표시하는 함수
# 변환된 이미지의 크기 확인
print(dst.shape)  # 변환 후에도 원본 이미지 크기(높이, 너비, 채널)가 유지됨

(220, 220, 3)
# 문제 1: 이미지 크기 조절
# 목표: 주어진 이미지의 크기를 사용자가 지정한 크기로 조절하는 기능을 구현합니다.
# 설명: 이미지를 200x200 크기로 조절해보세요. 다양한 보간법을 적용하며 결과를 비교합니다.

# 이미지 불러오기
img = cv2.imread('Lenna.png')
# 크기 조절

# 이미지 표시
plt.imshow(cv2.cvtColor(resized_img, cv2.COLOR_BGR2RGB))
plt.show()

# 문제 2: 이미지 뒤집기
# 목표: 주어진 이미지를 수평, 수직으로 뒤집는 기능을 구현합니다.
# 설명: 이미지를 수평, 수직으로 뒤집고 결과를 표시합니다.
# # 수평 뒤집기

# 수직 뒤집기

# 결과 표시
plt.imshow(cv2.cvtColor(flipped_img_hor, cv2.COLOR_BGR2RGB))
plt.show()
plt.imshow(cv2.cvtColor(flipped_img_ver, cv2.COLOR_BGR2RGB))
plt.show()

# 문제 3: 이미지 회전
# 목표: 주어진 이미지를 특정 각도로 회전시키는 기능을 구현합니다.
# 설명: 이미지를 45도 회전시키고 결과를 표시합니다.
# 회전을 위한 변환 행렬 생성
rows, cols, _ = img.shape
# 이미지 회전

# 결과 표시
plt.imshow(cv2.cvtColor(rotated_img, cv2.COLOR_BGR2RGB))
plt.show()

# 정답
# 문제 1
resized_img = cv2.resize(img, (200, 200), interpolation=cv2.INTER_LINEAR)
# 이미지 표시
plt.imshow(cv2.cvtColor(resized_img, cv2.COLOR_BGR2RGB))
plt.show()
# 문제 2
# # 수평 뒤집기
flipped_img_hor = cv2.flip(img, 1)
# 수직 뒤집기
flipped_img_ver = cv2.flip(img, 0)
# 결과 표시
plt.imshow(cv2.cvtColor(flipped_img_hor, cv2.COLOR_BGR2RGB))
plt.show()
plt.imshow(cv2.cvtColor(flipped_img_ver, cv2.COLOR_BGR2RGB))
plt.show()

# 문제 3
rows, cols, _ = img.shape
M = cv2.getRotationMatrix2D((cols/2, rows/2), 45, 1)
# 이미지 회전
rotated_img = cv2.warpAffine(img, M, (cols, rows))
# 결과 표시
plt.imshow(cv2.cvtColor(rotated_img, cv2.COLOR_BGR2RGB))
plt.show()
profile
인공지능을 공부하고 가르치는 김민수 강사입니다. 공부한 내용 및 수업 자료가 업로드 됩니다.

0개의 댓글