1. 이미지 유사도
- 픽셀 값의 분표가 서로 비슷하다면 유사한 이미지일 확률이 높음
🔵 비교 알고리즘
|
cv2.compareHist(히스트그램1, 히스트그램2, 알고리즘) cv2.HISTCMP_CORREL: 상관관계(1: 완정 일치, -1: 완전 불일치, 0: 무관계) |
◼ 예제 : 여러 이미지 간의 히스토그램 유사도를 비교하기
|
import cv2 import matplotlib.pyplot as plt
import numpy as np
img1 = cv2.imread('./taekwonv1.jpg')
img2 = cv2.imread('./taekwonv2.jpg')
img3 = cv2.imread('./taekwonv3.jpg')
img4 = cv2.imread('./dr_ochanomizu.jpg')
imgs = [img1, img2, img3, img4]
hists = []
# 각 이미지에 대해 히스토그램 계산 및 비교를 수행
for i, img in enumerate(imgs):
plt.subplot(1, len(imgs), i+1)
plt.title('img%d' % (i+1))
plt.axis('off')
plt.imshow(img[:, :, ::-1])
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
hist = cv2.calcHist([hsv], [0, 1], None, [180,256], [0, 180, 0, 256])
cv2.normalize(hist, hist, 0, 1, cv2.NORM_MINMAX)
hists.append(hist)
query = hists[0]
methods = {'CORREL': cv2.HISTCMP_CORREL, 'CHISQR': cv2.HISTCMP_CHISQR, 'INTERSECT': cv2.HISTCMP_INTERSECT, 'BHATTACHARYYA': cv2.HISTCMP_BHATTACHARYYA}
# 각 메소드별로 히스토그램 유사도를 계산하고 출력
for j, (name, flag) in enumerate(methods.items()):
print('%-10s' % name, end = '\t')
for i, (hist, img) in enumerate(zip(hists, imgs)):
ret = cv2.compareHist(query, hist, flag)
# INTERSECT 메소드의 경우 정규화된 결과를 사용하여 출력
if flag == cv2.HISTCMP_INTERSECT:
ret = ret/np.sum(query)
print('img%d:%7.2f' % (i+1, ret), end = '\t')
print()
plt.show()
|
![]() |
- 주석
더보기
|
import cv2
import matplotlib.pyplot as plt
import numpy as np
img1 = cv2.imread('./taekwonv1.jpg')
img2 = cv2.imread('./taekwonv2.jpg')
img3 = cv2.imread('./taekwonv3.jpg')
img4 = cv2.imread('./dr_ochanomizu.jpg')
imgs = [img1, img2, img3, img4]
hists = []
# 각 이미지에 대해 히스토그램 계산 및 비교를 수행합니다.
for i, img in enumerate(imgs):
plt.subplot(1, len(imgs), i+1)
plt.title('img%d' % (i+1))
plt.axis('off')
plt.imshow(img[:, :, ::-1]) # OpenCV는 BGR 순서이므로 RGB 순서로 변환
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # HSV 색 공간으로 변환
# 2차원 히스토그램을 계산
hist = cv2.calcHist([hsv], [0, 1], None, [180,256], [0, 180, 0, 256])
# 히스토그램을 [0, 1] 범위로 정규화
cv2.normalize(hist, hist, 0, 1, cv2.NORM_MINMAX)
# 계산된 히스토그램을 리스트에 추가
hists.append(hist)
# 쿼리 이미지로 사용할 첫 번째 이미지의 히스토그램을 선택
query = hists[0]
# 비교할 메소드들과 그에 대한 설명
methods = {'CORREL': cv2.HISTCMP_CORREL, 'CHISQR': cv2.HISTCMP_CHISQR, 'INTERSECT': cv2.HISTCMP_INTERSECT, 'BHATTACHARYYA': cv2.HISTCMP_BHATTACHARYYA}
# 각 메소드별로 히스토그램 유사도를 계산하고 출력
for j, (name, flag) in enumerate(methods.items()):
print('%-10s' % name, end = '\t')
for i, (hist, img) in enumerate(zip(hists, imgs)):
ret = cv2.compareHist(query, hist, flag)
# INTERSECT 메소드의 경우 정규화된 결과를 사용하여 출력
if flag == cv2.HISTCMP_INTERSECT:
ret = ret/np.sum(query)
print('img%d:%7.2f' % (i+1, ret), end = '\t')
print()
plt.show()
|
|
2. 영상의 변환
- 영상을 구상하는 픽셀의 배치 구조를 변경함으로 전체 영상의 모양을 바꾸는 작업
🔵이미지 이동(translate)
|
M = [1 0 a] [0 1 b] x 방향으로 a 만큼, y 방향으로 b 만큼 이동하는 행렬 cv2.warpaffine(영상, 2 * 3 변환행렬, 결과, 보간법 알고리즘)
|
| 이미지 이동(translate) : (0,0)을 매게변수로 전달하면 입력 영상과 같은 행렬을 반환 원래 있던 좌표에 이동시키려는 거리 만큼 연산(shift) |
🔵보간법 일고리즘(interpolation)
|
cv2.INTER_LINEAR: 인접한 4개의 픽셀 값에 거리 가중치 사용 -> 속도는 빠르지만 퀄리티가 좀 떨어짐 cv2.INTRE_NEAREST: 가장 가까운 픽셀 값 사용 -> 속도가 가장 빨르지만 퀄리티가 떨어짐 cv2.INTER_AREA: 픽셀 영역 관계를 이용한 재샘플링 -> 영역적인 정보를 추출해서 결과 영상을 세팅하는 방법, 다운샘플링시 효과적 cv2.INTER_CUBIC: 인접한 16개의 픽셀 값에 사중치를 사용 -> 퀄리티는 가장 촣치만 속도가 떨어짐 |
◼ 예제: 이미지 이동 / cv2.warpaffine() 사용하기
|
import cv2
import numpy as np
img = cv2.imread('../Day1/dog.bmp')
# [1, 0, a], [0, 1, b]
aff = np.array([[1, 0, 150], [0, 1, 100]], dtype=np.float32)
dst = cv2.warpAffine(img, aff, (0, 0))
cv2.imshow('img', img)
cv2.imshow('dst', dst)
cv2.waitKey()
|
![]() |
🔵이미지 크기 변환 (resize)
|
cv2.resize(영상, 결과, x와 y방향 스케일 비율, 보간법)
|
| 영상의 크기를 원본 영상보다 크게 또는 작게 만드는 변환 |
◼ 예제: 이미지 확대하기 / cv2.INTER_NEAREST, cv2.INTER_CUBIC 사용하기
|
import cv2
img = cv2.imread('../Day1/dog.bmp')
dst1 = cv2.resize(img, (1280, 1024), interpolation=cv2.INTER_NEAREST)
dst2 = cv2.resize(img, (1280, 1024), interpolation=cv2.INTER_CUBIC)
cv2.imshow('img', img)
cv2.imshow('dst1', dst1[400:800, 200:600])
cv2.imshow('dst2', dst1[400:800, 200:600])
cv2.waitKey()
|
![]() |
🔵 회전(rotation)
|
cv2.getRotationMatrix2D(중심 좌표, 회전각도, 확대비율) -> affine 행렬 |
| 영상의 특정 각도 만큼 회전시키는 변환(반시계 방향) * 회전각도: 반시계방향(기본값), 음수는 시계방향 * 확대비율: 0~1 사이의 실수 |
◼ 예제: 이미지 회전시키기
|
import cv2
img = cv2.imread('../Day1/dog.bmp')
cp = (img.shape[1] / 2, img.shape[0] / 2)
rot = cv2.getRotationMatrix2D(cp, 30, 0.5)
dst = cv2.warpAffine(img, rot, (0, 0))
cv2.imshow('img', img)
cv2.imshow('dst', dst)
cv2.waitKey()
|
![]() |
🔵투시변환(perspective)
|
cv2.getPerspectiveTransforms(영상, 4개의 결과 좌표점) -> 투시 변환 행렬 cv2.wrapPerspective(영상, 투시 변환 행렬, 결과 영상 크기) |
| - 직사각형 형태의 영상을 임의의 입체감 있는 사각형 형태로 변경할 수 있는 변환 - 원본 영상에 있는 직선은 결과 영상에서 그대로 유지 되지 않고 평행 관계가 깨질 수 있음 - 투시 변환은 보통 3*3 크기의 실수 행렬로 표현 - 8개의 파라미터로 표현할 수 있지만, 좌표 계산 편의상 9개의 원소를 갖는 행렬로 표현 |
◼ 예제 : 이미지 투시변환하기
|
import cv2
import numpy as np
img = cv2.imread('./pic.jpg')
w, h = 600, 400
srcQuad = np.array([[370, 173], [1220, 155], [1420, 840], [210, 850]], np.float32)
dstQuad = np.array([[0, 0], [w, 0], [w, h], [0, h]], np.float32)
pers = cv2.getPerspectiveTransform(srcQuad, dstQuad)
dst = cv2.warpPerspective(img, pers, (w, h))
cv2.imshow('img', img)
cv2.imshow('dst', dst)
cv2.waitKey()
|
![]() |
◼ 방법1
|
import cv2
import numpy as np
# 전역 변수 선언
points = []
dragging_point_index = -1
image_path = './namecard.jpg'
# 마우스 이벤트 핸들러 함수
def mouse_handler(event, x, y, flags, param):
global points, image, dragging_point_index
if event == cv2.EVENT_LBUTTONDOWN:
for i, point in enumerate(points):
if abs(point[0] - x) < 10 and abs(point[1] - y) < 10:
dragging_point_index = i
break
elif event == cv2.EVENT_MOUSEMOVE:
if dragging_point_index != -1:
points[dragging_point_index] = (x, y)
redraw_image()
elif event == cv2.EVENT_LBUTTONUP:
dragging_point_index = -1
def redraw_image():
global image
image = orig_image.copy()
for i, point in enumerate(points):
cv2.circle(image, point, 10, (255, 0, 255), -1) # 큰 핑크색 점
if i > 0:
cv2.line(image, points[i-1], point, (255, 0, 255), 2) # 핑크색 선
if len(points) == 4:
cv2.line(image, points[3], points[0], (255, 0, 255), 2) # 마지막 점과 첫 점을 연결하는 선
cv2.imshow("Image", image)
# 이미지를 불러오고 초기화
image = cv2.imread(image_path)
orig_image = image.copy()
# 초기 네 점 설정 (이미지의 모서리 근처에 배치)
h, w, _ = orig_image.shape
points = [(50, 50), (w - 50, 50), (w - 50, h - 50), (50, h - 50)]
redraw_image()
cv2.setMouseCallback("Image", mouse_handler)
print("이미지에서 네 점을 선택하고 움직이세요. Enter 키를 누르면 완료됩니다.")
while True:
key = cv2.waitKey(1) & 0xFF
if key == 13: # Enter 키를 누르면 변환된 이미지를 새 창에 표시
if len(points) == 4:
# 원본 이미지의 크기를 얻음
h, w, _ = orig_image.shape
# 선택한 네 점
pts1 = np.float32(points)
# 대상 좌표 설정 (직사각형으로 변환)
pts2 = np.float32([[0, 0], [w, 0], [w, h], [0, h]])
# 변환 행렬 계산
matrix = cv2.getPerspectiveTransform(pts1, pts2)
# 원근 변환 적용
result = cv2.warpPerspective(orig_image, matrix, (w, h))
# 결과 이미지 표시
cv2.imshow("Transformed Image", result)
print("변환된 이미지가 새 창에 표시됩니다.")
else:
print("네 점이 선택되지 않았습니다.")
elif key == 27: # Esc 키를 누르면 종료
break
cv2.destroyAllWindows()
|
◼ 방법2
|
import cv2
import numpy as np
import sys
img = cv2.imread('./namecard.jpg')
h, w = img.shape[:2]
dh = 500
# A4용지 크기: 210*297mm
dw = round(dh * 297 / 210)
srcQuad = np.array([[30, 30], [30, h-30], [w-30, h-30], [w-30, 30]], np.float32)
dstQuad = np.array([[0, 0], [0, dh], [dw, dh], [dw, 0]], np.float32)
dragSrc = [False, False, False, False]
def drawROI(img, corners):
cpy = img.copy()
c1 = (192, 192, 255)
c2 = (128, 128, 255)
for pt in corners:
cv2.circle(cpy, tuple(pt.astype(int)), 25, c1, -1)
cv2.line(cpy, tuple(corners[0].astype(int)), tuple(corners[1].astype(int)), c2, 2)
cv2.line(cpy, tuple(corners[1].astype(int)), tuple(corners[2].astype(int)), c2, 2)
cv2.line(cpy, tuple(corners[2].astype(int)), tuple(corners[3].astype(int)), c2, 2)
cv2.line(cpy, tuple(corners[3].astype(int)), tuple(corners[0].astype(int)), c2, 2)
return cpy
def onMouse(event, x, y, flags, param):
global srcQuad, dragSrc, ptOld, img
if event == cv2.EVENT_LBUTTONDOWN:
for i in range(4):
if cv2.norm(srcQuad[i] - (x, y)) < 25:
dragSrc[i] = True
ptOld = (x, y)
break
if event == cv2.EVENT_LBUTTONUP:
for i in range(4):
dragSrc[i] = False
if event == cv2.EVENT_MOUSEMOVE:
for i in range(4):
if dragSrc[i]:
srcQuad[i] = (x, y)
cpy = drawROI(img, srcQuad)
cv2.imshow('img', cpy)
ptOld = (x, y)
break
disp = drawROI(img, srcQuad)
cv2.namedWindow('img')
cv2.setMouseCallback('img', onMouse)
cv2.imshow('img', disp)
while True:
key = cv2.waitKey()
if key == 13:
break
elif key == 27:
sys.exit()
pers = cv2.getPerspectiveTransform(srcQuad, dstQuad)
dst = cv2.warpPerspective(img, pers, (dw, dh), flags=cv2.INTER_CUBIC)
cv2.imshow('dst', dst)
cv2.waitKey()
|
![]() ![]() ![]() |
'AI > 컴퓨터 비전' 카테고리의 다른 글
| 09. 모폴로지 변환 (0) | 2024.07.23 |
|---|---|
| 08. 필터링, 블러링 (0) | 2024.07.22 |
| 06. 이진화 (0) | 2024.07.18 |
| 05. 마스크, 관심영역 (0) | 2024.07.18 |
| 04. 평활화, 색공간, CLAHE, 정규화 (1) | 2024.07.17 |







