2_Opencv

미니미·2024년 8월 16일

Opencv

목록 보기
3/3

이미지 처리 기초와 OpenCV를 활용한 이진화 및 변환 기법

이미지 처리에서 중요한 개념인 이진화, 변환 기법에 대해 살펴보겠습니다. 특히 OpenCV를 이용해 직접 코드를 구현해 볼 수 있도록 실습 예제도 준비했습니다.

1. 관심 영역(ROI, Region of Interest)

ROI는 영상 내에서 특정 관심 영역을 설정하는 것을 의미합니다. 예를 들어, 이미지 내에서 태양의 영역을 설정해 그 부분만 다루고 싶을 때 ROI를 사용합니다.

import cv2
import numpy as np
#이미지 읽기
img = cv2.imread('./sun.jpg')
#태양 영역 선택 (임의로 선택한 좌표)
x, y, w, h = 182, 17, 120, 118
#태양 영역 복사
sun_region = img[y:y+h, x:x+w].copy()
#원형 마스크 생성
mask = np.zeros((h, w), dtype=np.uint8)
center = (w // 2, h // 2)
radius = min(w // 2, h // 2)
cv2.circle(mask, center, radius, 255, -1)
#마스크를 이용해 원형 부분만 남기기
sun_region_masked = cv2.bitwise_and(sun_region, sun_region, mask=mask)
#복사한 태양 영역을 새로운 위치에 붙여넣기
new_img = img.copy()
new_img[y:y+h, 300:300+w] = cv2.bitwise_and(new_img[y:y+h, 300:300+w], new_img[y:y+h, 300:300+w], mask=cv2.bitwise_not(mask))
new_img[y:y+h, 300:300+w] += sun_region_masked
#결과 이미지 표시
cv2.imshow('Sun Image', new_img)
cv2.imwrite('./sun_with_copy.jpg', new_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

결과

2. 영상의 이진화 (Binarization)

이진화는 픽셀 값을 흑백으로 나누는 작업입니다. 배경과 객체를 분리하거나 관심 영역을 강조하는 데 유용합니다.

OpenCV에서 사용하는 이진화 함수:

cv2.threshold()
cv2.adaptiveThreshold()

import cv2
import matplotlib.pyplot as plt
img = cv2.imread('./cells.png', cv2.IMREAD_GRAYSCALE)
hist = cv2.calcHist([img], [0], None, [256], [0, 255])
#임계값을 100으로 설정하여 이진화
_, dst1 = cv2.threshold(img, 100, 255, cv2.THRESH_BINARY)
# 임계값을 210으로 설정하여 이진화
_, dst2 = cv2.threshold(img, 210, 255, cv2.THRESH_BINARY)
cv2.imshow('Original Image', img)
cv2.imshow('Threshold 100', dst1)
cv2.imshow('Threshold 210', dst2)
plt.plot(hist)
plt.show()
cv2.waitKey(0)

결과

3. 오츠의 이진화 알고리즘

오츠 알고리즘은 자동으로 임계값을 찾아 이진화하는 기법입니다. 이미지의 히스토그램을 분석하여 최적의 임계값을 결정합니다.

import cv2
img = cv2.imread('./rice.png', cv2.IMREAD_GRAYSCALE)
#오츠 알고리즘을 사용한 이진화
th, dst = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
print('Calculated Threshold:', th)
cv2.imshow('Original Image', img)
cv2.imshow('Otsu Thresholding', dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

결과

4. 영상 변환 (Translation, Rotation, Scaling)

영상 변환은 이미지의 크기나 모양을 변환하는 작업입니다. 다음은 영상 이동(Translation), 크기 변환(Scaling), 회전(Rotation)에 대한 예제입니다.

import cv2
import numpy as np
#이미지 이동 (Translation)
img = cv2.imread('./dog.bmp')
aff = np.array([[1, 0, 200], [0, 1, 100]], dtype=np.float32)
dst = cv2.warpAffine(img, aff, (0, 0))
cv2.imshow('Original Image', img)
cv2.imshow('Translated Image', dst)
cv2.waitKey(0)

결과

5. 이미지 회전 (Rotation)

이미지를 회전시키기 위해 회전 변환 행렬을 사용합니다. 중심을 기준으로 이미지를 회전시킬 수 있습니다.

import cv2
import numpy as np
#이미지 읽기
img = cv2.imread('./dog.bmp')
#회전 중심 좌표 (이미지 중심)
center = (img.shape[1] // 2, img.shape[0] // 2)
#회전 각도와 스케일 설정
angle = 45  # 45도 회전
scale = 1.0  # 스케일 유지
#회전 변환 행렬 생성
rotation_matrix = cv2.getRotationMatrix2D(center, angle, scale)
#회전 적용
rotated_img = cv2.warpAffine(img, rotation_matrix, (img.shape[1], img.shape[0]))
#결과 이미지 출력
cv2.imshow('Original Image', img)
cv2.imshow('Rotated Image', rotated_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

결과

6. 영상의 가우시안 블러 (Gaussian Blur)

가우시안 블러는 이미지를 부드럽게 만들기 위해 사용되는 필터입니다. 이미지에서 노이즈를 제거하거나 흐림 효과를 적용할 때 사용됩니다.

import cv2
#이미지 읽기
img = cv2.imread('./dog.bmp')
#가우시안 블러 적용 (커널 크기 7x7)
blurred_img = cv2.GaussianBlur(img, (7, 7), 0)
# 결과 이미지 출력
cv2.imshow('Original Image', img)
cv2.imshow('Gaussian Blur', blurred_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

7 이미지 히스토그램 평활화 (Histogram Equalization)

히스토그램 평활화는 이미지의 밝기 분포를 조정하여 명암 대비를 개선하는 기법입니다. 특히 저조도 이미지에서 효과적입니다.

import cv2
#이미지 읽기 (그레이스케일)
img = cv2.imread('./dark_image.jpg', cv2.IMREAD_GRAYSCALE)
#히스토그램 평활화 적용
equalized_img = cv2.equalizeHist(img)
#결과 이미지 출력
cv2.imshow('Original Image', img)
cv2.imshow('Equalized Image', equalized_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

8 기본 원근 변환

원근 변환(Perspective Transformation)은 이미지에서 특정 영역을 다른 시점에서 촬영된 것처럼 변환하는 방법입니다. 이 변환은 주로 이미지를 왜곡시키거나 특정 각도에서 보이는 것처럼 만들 때 사용됩니다.

import cv2
import numpy as np
img = cv2.imread('./pic.jpg')
w, h = 600, 400
srcQuad = np.array([[369, 172], [1228, 156], [1424, 846], [207, 801]], 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()

결과

9 사용자 상호작용을 통한 원근 변환

사용자가 마우스를 사용해 직접 변환 영역의 좌표를 조정할 수 있는 프로그램을 만들 수도 있습니다. 이 방법은 보다 유연하게 원근 변환을 적용할 수 있게 해줍니다. 아래 코드는 사용자가 마우스로 드래그하여 4개의 포인트를 조정할 수 있도록 구현한 예제입니다

예제)

import cv2
import numpy as np
import sys
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
ptOld = None
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
img = cv2.imread('./namecard.jpg')
h, w = img.shape[:2]
#A4용지 크기: 210 * 297mm
dh = 500
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]
disp = drawROI(img, srcQuad)
cv2.imshow('img', disp)
cv2.setMouseCallback('img', onMouse)
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()

결과

profile
Mobile App Developer

0개의 댓글