도형그리기
- 각 함수들은 원본 이미지에 도형을 그린다.
- cv2.line(img, pt1, pt2, color, tickness=None, lineType=None, shift):img**
- 선그리기
- 매개변수
- img: 그릴 대상 이미지
- pt1, pt2: 직선의 시작/끝점. 각각 튜플(x, y)
- color: 선색 또는 밝기 (B,G,R) 튜플 또는 정수
- thickness: 선 두께. 기본값=1 (픽셀)
- lineType: 선 타입. cv2.LINE_4, cv2.LINE_8(기본값), cv2.LINE_AA(부드러운 형태) 중 선택. 일직선이 아니 면 LINE_AA를 준다.
- 반환값
- 선을 그린 image (ndarray) 반환 (모든 도형함수 동일) - cv2.rectangle(img, pt1, pt2, color, thickness=None, lineType=None):img**
- cv2.rectangle(img, rec, color, thickness=None, lineType=None):img**
- 사각형 그리기
- 매개변수
- pt1, pt2: 좌측상단, 우측하단 좌표. 튜플 (x, y)
- rec: 사각형의 위치정보(x, y, w, h) 튜플지정.
- thickness: 도형에서는 -1을 주면 내부를 채운다. - cv2.circle(img, center, radius, color, thickness=None, lineStyle=None): img**
- 원 그리기. 원의 lineType은 LINE_AA (안티 알리애싱)을 주면 부드럽게 그려진다.
- 매개변수
- center: 원의 중심좌표. 튜플 (x,y)
- radius: 반지름 - cv2.polylines(img, pts, isClosed, color, thinkness=None, lineType=None): img**
- 다각형을 그린다.
- 매개변수
- pts: 다각형의 외곽점들의 좌표배열. ndarray 리스트 (ex: \[np.array[[10,10],[50,50], [10,10]])\] => 리스트로 감싸서 넣는다.
- isClosed: bool. 폐곡선 여부. 시작점과 끝점을 연결할지 여부. - cv2.putText(img, text, org, fontFace, fontScale, color, thickness=None, lineType=None): img**
- 문자열을 출력. 영문/숫자만 지원(한글 지원안함.)
- 매개변수
- text: 출력할 문자열
- org: 이미지에서 문자열을 출력할 위치. 좌측 하단의 좌표를 튜플로 지정 (x,y)
- fontFace: 폰트 종류. cv2.FONT_HERSHEY_ 로 시작하는 상수 중 선택
- fontScale: 폰트 크기 확대/축소 비율. 1이 기본. 1을 기준으로 정한다.
선행 : import
import numpy as np
import cv2
import matplotlib.pyplot as plt
다양한 도형 그리기
img = np.full((400, 400, 3), fill_value=255, dtype="uint8")
# (대상이미지, 도형을그리기위해필요한정보, 공통정보-색, 두께, type)
### 직선 -> 양단 끝점의 좌표(x,y)
cv2.line(img, (50, 50), (200, 50), color=(0, 0, 255), thickness=1) # color=(B, G, R)
cv2.line(img, (50, 50), (200, 200), color=(255, 0, 0), thickness=3, lineType=cv2.LINE_AA)
### 사각형 - 1. (좌상단 좌표), (우하단 좌표)
cv2.rectangle(img, (70, 200), (180, 280), color=(0, 255, 0), thickness=1)
### 사각형 - 2. (좌상단 좌표, width, height)
cv2.rectangle(img, (100, 210, 50, 60), (128, 128, 128), -1) # thickness=-1 : 색을 채운다.
### 원 - (중앙좌표), 반지름
cv2.circle(img, (300, 100), 30, (128, 0, 100), 1)
cv2.circle(img, (300, 200), 30, (128, 0, 100), 1, lineType=cv2.LINE_AA)
### 다각형 - 연결점의 좌표, 폐곡선여부(isClosed) - 시작/끝점을 연결할지 여부
pts = np.array([[250, 200], [300, 200], [350, 300], [250, 300]])
cv2.polylines(img, [pts], False, # isClosed
color=(200, 200, 50), thickness=1, lineType=cv2.LINE_AA)
# Text: 출력할 text, (글을쓰기시작할위치의좌표), font, 글씨크기
txt = "Hello World"
cv2.putText(img, txt, (50, 350), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 0, 0), 1, cv2.LINE_AA)
cv2.imshow("frame", img)
cv2.waitKey()
cv2.destroyAllWindows()
이미지에 한글 쓰기 -> opencv 는 지원안함.
- PIL를 이용해서 한글을 쓴다.
pillow 설치
!pip install pillow
# PIL (Python Image Lib)
# 폰트파일 경로 찾기
import matplotlib.font_manager as fm
font_list = fm.findSystemFonts(fontext='ttf')
print("폰트개수:", len(font_list))
print(font_list[:3])
malgun = [font_path for font_path in font_list if 'malgun' in font_path.lower()]
malgun
PIL을 이용한 한글 작성
### PILLOW 를 이용해서 이미지에 한글을 작성
import numpy as np
from PIL import Image, ImageFont, ImageDraw
import cv2
# 폰트설정(폰트객체 생성)
font_path = r'C:\\Windows\\Fonts\\malgun.ttf'
font = ImageFont.truetype(font_path, 20) # 폰트파일경로, 폰트크기
img = np.full((400,400,3), fill_value=200, dtype="uint8")
# ndarray -> PIL의 Image객체로 변환.
img_pil = Image.fromarray(img) # array로 부터 Image를 생성. (PIL: RGB)
# ImageDraw 객체 생성 -> ImageDraw: Image에 도형을 그리는 메소드들을 제공.
draw = ImageDraw.Draw(img_pil) # image_pil에 도형을 그릴수 있는 Draw객체 생성.
# Text를 쓰기
draw.text((50, 50), # 글을 쓰기 시작할 좌표(x,y)
"안녕하세요",
fill=(0, 0, 255), # 색: (R, G, B)
font=font
)
# type(img_pil)
### PIL 이미지를 ndarray로 변환
img = cv2.cvtColor(np.array(img_pil), cv2.COLOR_RGB2BGR)
cv2.imshow('frame', img)
cv2.waitKey()
cv2.destroyAllWindows()
TODO
- lenna 이미지를 읽은 뒤 적당한 위치에 txt(이름)를 쓴다.
- 얼굴에 Bounding Box(사각형)를 그리기.
import cv2
import matplotlib.pyplot as plt
txt='Lenna Forsen'
lenna = cv2.imread("images/Lenna.png")
## 이름 출력(text) - putText
cv2.putText(lenna, txt, (180, 430), cv2.FONT_HERSHEY_COMPLEX, 1, (255, 255, 250), 2, cv2.LINE_AA)
## 얼굴에 Box (Bounding Box) - rectangle
cv2.rectangle(lenna, (380, 200), (200, 380), (255, 255, 250), 2)
cv2.imshow("frame", lenna)
cv2.waitKey()
cv2.destroyAllWindows()
- 이미지 Crop
- open cv는 이미지를 numpy의 ndarray를 이용해 연산하기 때문에 image의 특정 영역의 좌표만 알면 그 영역을 잘라낼 수 있다.
### 이미지 crop: 특정 위치를 짤라내기.
lenna_face = lenna[200:381, 200:381].copy()
lenna_face.shape
cv2.imshow("frame", lenna_face)
cv2.waitKey()
cv2.destroyAllWindows()
영상의 기하학적 변환
- 영상을 구성하는 픽셀의 배치 구조를 변경함으로써 전체 영상의 모양을 바꾸는 작업
이동 변환 (Translation Transformation)
- 가로 또는 세로 방향으로 영상을 이동시키는 변환
- pixcel의 위치(좌표)를 이동시킨다. - X축과 Y축 방향으로 이동 변위를 지정


- affine(아핀) 변환: 영상을 구성하는 픽셀의 배치 구조를 변경함으로써 평행 이동, 확대 및 축소, 회전 등 전체 영상의 모양을 바꾸는 기하학적 변환
a = np.array([[1, 0, 5], [0, 1, 3]])
b = np.array([[0, 0, 0, 1, 1, 1], [0, 1, 2, 0, 1, 2], [1, 1, 1, 1, 1, 1]]) # 픽셀값들
a @ b
- cv2.warpAffine(src, M, dsize, dst=None, flags=None, borderMode=None, borderValue=None)
- 매개변수
- src: 원본 영상
- M: $2\times3$ 어파인 변환 행렬. 실수형
- dsize: 결과 영상의 크기를 (w, h) 튜플로 지정. (0,0) 이면 같은 크기
- flags: 보간법
- borderMode: 영상이 이동해서 생기는 빈공간을 채우는 방식 설정. default: cv2.BORDER_CONSTANT (검 정색으로 채운다.)
- borderValue: cv2.BORDER_CONSTANT 일때 채울 색. (B, G, R) 로 지정
이미지 픽셀 이동
import numpy as np
import cv2
lenna = cv2.imread('images/Lenna.png')
a, b = 200, 0 #a: 좌(음수)우(양수), b: 상(음수)하(양수) 이동 픽셀크기.
a, b = 0, -100
a, b = 100, 200
# 아핀변환행렬 (2, 3)
aff_matrix = np.array([[1, 0, a], [0, 1, b]], dtype="float32")
# 대상이미지, affine변환행렬, dsize(w, h) => 변환후 이미지 크기를 변환.
# result_img = cv2.warpAffine(lenna, aff_matrix, (0, 0))
# result_img = cv2.warpAffine(lenna, aff_matrix, (lenna.shape[1]+a, lenna.shape[0]+b))# (1000, 1000))
result_img = cv2.warpAffine(lenna, aff_matrix, (0, 0),
borderMode=cv2.BORDER_REFLECT # 생기는 빈공간을 어떦값을 채울지
)
cv2.imshow("src", lenna)
cv2.imshow(f"Move - ({a}, {b})", result_img)
cv2.waitKey()
cv2.destroyAllWindows()
전단 변환(Shear transformation)
- 직사각형 형태의 영상을 한쪽 방향으로 밀어서 평행사변형 모양으로 변형되는 변환으로 층밀림 변환이라고도 한다.
- 한축 방향으로 이동하는데 기준축에 비례해서 다르게 이동한다. - X축과 Y축에 대해 따로 정의 한다.

전단변환
m_x, m_y = 0.1, 0.1
shear_matrix = np.array([[1, m_x, 0], [m_y, 1, 0]], dtype="float32")
result2 = cv2.warpAffine(lenna, shear_matrix, (0, 0))
cv2.imshow("src", lenna)
cv2.imshow(f"({m_x}, {m_y})", result2)
cv2.waitKey()
cv2.destroyAllWindows()
대칭변환(Flip)
- cv2.flip(src, flipCode)
- 매개변수
- src: 원본 영상
- flipCode: 대칭방향지정
- 양수: 좌우대칭
- 0: 상하대칭
- 음수: 좌우/상하 대칭
대칭변환
result1 = cv2.flip(lenna, 1) # 좌우
result2 = cv2.flip(lenna, 0) # 상하
result3 = cv2.flip(lenna, -1) # 상하/좌우
cv2.imshow("src", lenna)
cv2.imshow("1", result1)
cv2.imshow("0", result2)
cv2.imshow("-1", result3)
cv2.waitKey()
cv2.destroyAllWindows()
회전(Rotate)
- rotate(src, rotateCode): img
- 매개변수
- src: 회전시킬 원본이미지
- rotateCode: 회전각도 상수
- ROTATE_90_CLOCKWISE: 시계방향 90도
- ROTATE_180: 180도 회전
- ROTATE_90_COUNTERCLOCKWISE: 반시계방향 90도(시계방향 270도) - 원하는 각도만큼 회전.
- 얼마나 회전할지 getRotationMatrix2D()를 이용해 어파인 변환 행렬을 생성.
- warpAffine()을 이용해 회전 처리
- getRotationMatrix2D(center, angle, scale)
- 2x3의 회전을 위한 어파인 변환 행렬 생성
- center: 회전의 중심점 좌표, 튜플형태로 지정
- angle: 중심점을 기준으로 회전할 각도(양수: 반시계방향, 음수: 시계방향)
- scale: 이미지 확대 및 축소 비율
- warpAffine(src, M, dsize)
- 회전 처리
- src: 회전시킬 대상 이미지 배열.
- M: getRotationMatrix2D()가 반환한 어파인 변환 행렬을 사용
- dsize: 출력이미지 크기
- (0,0): 변환된 크기 유지
rotate(회전)
import cv2
import matplotlib.pyplot as plt
# rotate() : 가운데를 기준으로 90도 단위로 회전.
lenna = cv2.imread('images/Lenna.png')
lenna_90 = cv2.rotate(lenna, cv2.ROTATE_90_CLOCKWISE)
lenna_180 = cv2.rotate(lenna, cv2.ROTATE_180)
lenna_270 = cv2.rotate(lenna, cv2.ROTATE_90_COUNTERCLOCKWISE)
images = [lenna, lenna_90, lenna_180, lenna_270]
titles = ["원본", "시계방향 90도", "180도", "반시계방향 90도"]
plt.figure(figsize=(10, 10))
for idx, (image, title) in enumerate(zip(images, titles)):
plt.subplot(2, 2, idx+1)
plt.imshow(image[:, :, ::-1])
plt.title(title)
plt.tight_layout()
plt.show()
원하는 각도만큼 회전
### 원하는 각도만큼 회전
angle = -37 # 회전시킬 각도 - 양수: 반시계방향, 음수: 시계방향
# center x, y좌표
x, y = int(lenna.shape[1]/2), int(lenna.shape[0]/2)
center = (x, y) # 돌릴 기준 좌표
# center = (10, 10)
# affine 변환행렬을 생성
rotate_matrix = cv2.getRotationMatrix2D(center, # 회전축의 기준좌표
angle, #회전각도
0.5 # 회전후 이미지 크기. 비율 (1-원본과 동일)
)
print(rotate_matrix)
rotate_result = cv2.warpAffine(lenna, rotate_matrix, (0, 0))
images = [lenna, rotate_result]
titles = ["원본", f"({x},{y})축 기준 {angle}도 회전"]
plt.figure(figsize=(10, 5))
for idx, (image, title) in enumerate(zip(images, titles)):
plt.subplot(1, 2, idx+1)
plt.imshow(image[:,:,::-1])
plt.title(title)
plt.tight_layout()
plt.show()
크기 조절(확대/축소 - Resize)
- cv2.resize(src, dsize\[, fx, fy, interpolation\])
- 매개변수
- src: 원본 이미지
- dsize: 조절할 이미지 크기 (width, height)
- fx, fy: 상대적 크기로 지정한다. (dsize는 0,0 으로 설정한다. dsize를 설정하면 dsize가 우선한다.)
- interpolation: 보간 방법
- 크기를 조절할 때 본래는 없는 값을 메우는 작업이 필요한데, 이를 interpolation(보간법)이라고 한다.
- 반환값
- ndarray: resize된 이미지반환
Interpolation 상수
- cv2.INTER_NEAREST: 이웃보간법. nearest neighbor interpolation이라고도 하며, 주변 이웃 pixel값을 가져와 빈공간을 채운다. 가장 빠르지만 화질이 좋지 않다.
- cv2.INTER_LINEAR: 쌍 선형보간법.(2x2 이웃픽셀을 계산해서 만든다.) resize의 default 방식. 연산속도가 빠르고 화질도 좋아서 많이 사용된다.
- cv2.INTER_CUBIC - 바이큐빅 보간법.(4x4 이웃픽셀을 계산해서 만든다.) INTER_LINEAR보다 화질이 좋고 lancozs보다 계산량이 적어 많이 사용된다.
- cv2.LANCZOS4 - Lanczos보간법.(8x8 이웃픽셀을 계산해서 만든다.) 가장 부드럽게 값을 메우지만 연산이 많이 필요하다.
- cv2.INTER_AREA: 영역보간법. 크기를 **축소**할 때 많이 사용한다. 확대할 때는 nearest neighbor와 유사하다.
- 일반적으로 쌍 선형보간법(INTER_LINEAR)을 많이 쓴다.
- 이미지 확대: 바이큐빅, 쌍 선형 보간법을 가장 많이 사용
- 이미지 축소: 영역 보간법을 많이 사용.
Interpolation 비교
- upsampling
- nearest와 area는 계단현상이 발생
- linear는 edge가 smooth된 효과가 발생
- cubic과 lancozs는 edge가 shapen되는 효과 - downsampling
- area는 pixel 관계에 따라 resampling하기 때문에 상대적으로 부드럽게 변환된다.
- 나머지는 계단현상이 많이 발생한다. - upsampling: cv2.INTER_CUBIC 또는 cv2.INTER_LINEAR
- downsampling: cv2.INTER_AREA
크기 확인
rose = cv2.imread('images/rose.bmp')
rose.shape
resize
# 크기를 지정해서 resize (240:width, 160:height)
result1 = cv2.resize(rose, (240, 160),
interpolation=cv2.INTER_AREA
) #(160, 240)
cv2.imshow("src", rose)
cv2.imshow("160 x 240", result1)
cv2.waitKey()
cv2.destroyAllWindows()
배율로 resize
# 비율로 크기를 지정 resize
result2 = cv2.resize(rose, (0, 0),
fx=4, # 가로 -> 4배
fy=4 # 높이 -> 4배
, interpolation=cv2.INTER_NEAREST)
result3 = cv2.resize(rose, (0, 0),
fx=4,
fy=4
, interpolation=cv2.INTER_LINEAR # default: LINEAR
)
result4 = cv2.resize(rose, (0, 0),
fx=4,
fy=4
, interpolation=cv2.INTER_CUBIC
)
result5 = cv2.resize(rose, (0, 0),
fx=4,
fy=4
, interpolation=cv2.INTER_LANCZOS4
)
cv2.imshow("src", rose)
cv2.imshow("2배", result2)
cv2.waitKey()
cv2.destroyAllWindows()
크기 확인
result3.shape
여러방법 사용 후 결과 확
cv2.imshow("src", rose)
cv2.imshow("Nearest", result2[500:900, 400:800])
cv2.imshow("LINEAR", result3[500:900, 400:800])
cv2.imshow("CUBIC", result4[500:900, 400:800])
cv2.imshow("LANCZOS4", result5[500:900, 400:800])
cv2.waitKey()
cv2.destroyAllWindows()'Data_Analysis_Track_33 > Python' 카테고리의 다른 글
| Python_Deeplearning_pytorch_01-2(tensor 다루기) (1) | 2023.10.16 |
|---|---|
| Python_Deeplearning_pytorch_01(tensor 다루기) (0) | 2023.10.15 |
| Python_opencv_02(기본 영상 처리) (1) | 2023.10.06 |
| Python_opencv_01(opencv 개요) (1) | 2023.10.05 |
| Python_numpy_02(인덱싱과 슬라이싱을 이용한 배열의 원소 조회 및 변경) (2) | 2023.10.04 |