openCV_이미지 변환, 키보드 라벨링 - chloe73/openCV GitHub Wiki

✅키보드 라벨링

import cv2 as cv

source = "source/test.jpeg"
origin = cv.imread(source, cv.IMREAD_COLOR)
origin = cv.resize(origin, (720, 720))
#cv.imshow("origin", origin)
img = cv.cvtColor(origin, cv.COLOR_BGR2GRAY)
img = cv.GaussianBlur(img, (9, 9), 0)

ret, binar = cv.threshold(img, 100, 255, 1)
cv.imshow("binar", binar)
cnt, labels, stats, centroid = cv.connectedComponentsWithStats(binar)
count = 0
for i in range(1, cnt):
    (x, y, w, h, area) = stats[i]
    if area < 200:
        continue

    cv.rectangle(origin, (x, y, w, h), (0, 255, 255))
    count += 1
    string = str(count)
    cv.putText(origin, string, (x, y+15), cv.FONT_HERSHEY_PLAIN, 1.2, (255, 255, 255))

cv.imshow("Labeling", origin)
cv.waitKey(0)
cv.destroyAllWindows()

✅이미지 변환[python,c++]

  1. 이미지 변환 - Translation (상하, 좌우 이동)
  2. 이미지 변환 - Rotation
  3. 이미지 변환 - Scaling : Linear Interpolation(선형 보간법)
  4. 이미지 변환 - Flipping(이미지 뒤집기)
  5. 이미지 뒤틀기(어핀 변환, 원근 변환)

💡이미지 변환 - Translation (상하, 좌우 이동)

우선 Transition 이라 하면 이미지를 이동시키는 것입니다. 사진의 이동은 상하(y축), 좌우(x축)로 움직이는 것을 고려하지 앞,뒤(z축)은 고려를 하지 않습니다.

image

이것을 행렬(Matrix)로 표현하면 위와 같습니다. x축, y축 이동 값을 행렬로 표현해서 cv2.warpAffine 함수를 호출해야 합니다. 아래와 같이...

image = cv2.imread('images/beach.png')
# X 방향으로 25, Y 방향으로 50 이동할때
M = np.float32([1, 0, 25], [0, 1, 50](/chloe73/openCV/wiki/1,-0,-25],-[0,-1,-50))
shifted = cv2.warpAffine(image, M, (image.shape[1], image.shape[0]))
cv2.imshow("Shifted Down and Right", shifted)

그런데 warpAffine 이 무슨 말인지도 모르겠고, 늘 Matrix 를 정의 해야 하기 때문에 복잡합니다. 그래서 OpenCV 대가인 Dr. Adrian Rosebrock 는 imutils 패키지를 추천합니다.  (설치는 pip install imutils)

imutils 패키지를 사용하면 다음과 같이 변경이 됩니다.

# computer vision study : 이미지 변환 - Translation (상하, 좌우 이동)
import cv2
import imutils

image = cv2.imread('resource/111.jpg')
# X 방향으로 25, Y 방향으로 50 이동할때
shifted = imutils.translate(image, 25, 50)   # translate는 이해하기 쉬운 용어

cv2.imshow("Shifted Down and Right", shifted)
cv2.waitKey()
cv2.destroyAllWindows()

translate 라는 이해하기 쉬운 함수 이름을 쓰기 때문에 명확해 지는 것 같습니다.

image

💡이미지 변환 - Rotation

Rotation에서 신경을 써야 하는 부분은 두가지 입니다.

우선 회전을 하는 중심 축을 어디에 둘 것이냐 입니다. Top Left가 될수도 있고, 그림의 중심이 될수도 있습니다.

두번째는 회전 각도입니다. 회전 각도는 시간 반대 방향이 + 이동 각도이고, 시계 방향이 - 이동 각도라는 것을 이해하고 있으면 됩니다.

OpenCV를 기준으로 그림의 중심을 시계 반대 방향으로 45도 회전을 시킨다고 하면 다음과 같은 소스코드가 나옵니다.

#  computer vision study : 이미지 변환 - Rotation
import cv2

# load the image and show it
image = cv2.imread("resource/111.jpg")
cv2.imshow("Original", image)

# grab the dimensions of the image and calculate the center of the image
(h, w) = image.shape[:2]
(cX, cY) = (w / 2, h / 2)

# rotate our image by 45 degrees
M = cv2.getRotationMatrix2D((cX, cY), 45, 1.0)
rotated = cv2.warpAffine(image, M, (w, h))
cv2.imshow("Rotated by 45 Degrees", rotated)
cv2.waitKey()

image

여기서도 중심점과 각도를 변형하는 행렬(Matrix)를 선언하고, 이것은 warpAffine이라는 어려운 함수를 사용해야 합니다.

그래서 여기서도 imutils 함수를 사용하는 것을 권장합니다. imutils 를 사용하면 다음과 같이 깔끔해 집니다.

# computer vision study : 이미지 변환 - Rotation(2)
import cv2
import imutils

# load the image and show it
image = cv2.imread("resource/111.jpg")
cv2.imshow("Original", image)

# 회전의 중심축을 정의하지 않으면 그림의 중심이 됨
rotated = imutils.rotate(image, 45)
cv2.imshow("Rotated by 180 Degrees", rotated)
cv2.waitKey()

# 회전의 중심 축을 정의하면 해당 중심축으로 회전을 함.
rotated = imutils.rotate(image, 45, center=(0, 0))  # 회전 중심축 TOP LEFT
cv2.imshow("Rotated by 180 Degrees", rotated)
cv2.waitKey()

image

image

💡이미지 변환 - Scaling : Linear Interpolation(선형 보간법)

스케일링이란 Computer Vision에서 가장 흔하게 사용되는 처리 방법 중 하나로, 이미지의 크기를 조절할 수 있다.

스케일링 방법으로는 선형(Linear) 보간법, 삼차(Cubic) 보간법, 특정 화소로 지정하는 조정이 대표적이다.

OpenCV에서 스케일링하는 함수로 resize를 사용한다.

변환 행렬을 쓰지 않고도 확대 및 축소를 할 수 있습니다. cv2.resize() 함수를 사용하면 됩니다.

  • **cv2.resize(src, dsize, dst, fx, fy, interpolation)**src: 입력 원본 이미지dsize: 출력 영상 크기(확대/축소 목표 크기, (width, height)형식), 생략하면 fx, fy 배율을 적용fx, fy: 크기 배율, dsize가 주어지면 dsize를 적용함interpolation: 보간법 알고리즘 선택 플래그 (cv2.warpAffine()과 동일)dst: 결과 이미지

cv2.resize() 함수를 사용하면 확대/축소를 몇 픽셀로 할지 혹은 어떤 배율로 할지 선택할 수 있습니다. dsize는 확대/축소를 원하는 목표 이미지의 크기이며, fx, fy는 변경할 배율입니다. 예를 들어 fx = 2, fy = 0.5이면 x축으로 2배, y축으로 0.5배로 스케일링한다는 뜻입니다. 아래는 cv2.resize()를 적용하여 이미지를 확대 및 축소하는 코드입니다.

# computer vision stduy : 이미지 변환 - Scaling - Linear Interpolation(선형 보간법)
import cv2

image = cv2.imread("resource/111.jpg")
img_scale = cv2.resize(image, None, fx=0.8, fy=1, interpolation = cv2.INTER_LINEAR)
cv2.imshow('Linear Interpolation', img_scale)
cv2.waitKey()
cv2.destroyAllWindows()
# computer vision stduy : 이미지 변환 - Scaling - Cubic Interpolation
import cv2

image = cv2.imread("resource/111.jpg")
img_scale = cv2.resize(image, None, fx=0.8, fy=1, interpolation = cv2.INTER_CUBIC)
cv2.imshow('CUBIC Interpolation', img_scale)
cv2.waitKey()
cv2.destroyAllWindows()
# computer vision stduy : 이미지 변환 - Scaling - Resize
import cv2

image = cv2.imread("resource/111.jpg")
img_scale = cv2.resize(image, (300, 200), interpolation = cv2.INTER_AREA)
cv2.imshow('Scaling Size', img_scale)
cv2.waitKey()
cv2.destroyAllWindows()

3가지 모두 출력형태는 맨 위에 기본 이미지와 동일하지만 경우에 따라 화질을 유지하기 위해 적절하게 조절할 필요가 있다.

영상 확대를 위해서는 Cubic interpolation이 적합하며, 축소를 위해서는 영역을 직접 지정하는 것이 적합하다.

Linear, Cubic 방식 모두 1.3배 확대하는 것은 동일하지만, Cubic 방식은 Linear 방식보다 속도가 늦지만 질적인 측면에서는 우수한 점에서 차이를 보인다.

💡이미지 변환 - Flipping(이미지 뒤집기)

이미지 뒤집기(Flipping)은 매우 간단합니다. X축으로 뒤집기를 할 것인지, Y축으로 할지, 동시에 X, Y축으로 할지만 결정하면 됩니다.

flipCode로 나누는데,

  • 0 : X축으로 뒤집기
  • 1 (Positive) : Y 축으로 뒤집기 : 양수이면 모두 가능
  • 1 (Negative) : 동시에 뒤집기 : 음수이면 모두 가능
# computer vision study : 이미지 변환 - Flipping(이미지 뒤집기)
import cv2

image = cv2.imread("resource/111.jpg")
cv2.imshow("Original", image)

# X축 뒤집기
flipped = cv2.flip(image, 0)
cv2.imshow("X axis", flipped)

# Y축 뒤집기
flipped = cv2.flip(image, 1)
cv2.imshow("Y axis", flipped)

# X, Y축 동시
flipped = cv2.flip(image, -1)
cv2.imshow("Both Flipped", flipped)

cv2.waitKey(0)
cv2.destroyAllWindows()

image

이미지 뒤틀기(어핀 변환, 원근 변환)

💡어핀 변환(Affine Transform)

어핀 변환은 뒤틀기 방법 중 하나입니다. 말이 어려워 보이지만 아래 예제를 보면 어떤 변환인지 쉽게 이해가 될 겁니다.

이 함수는 3개의 좌표인 pts1이 pts2로 위치가 변한 만큼 이미지를 뒤트는 기능을 제공합니다.

# computer vision stduy : 이미지 뒤틀기(어핀 변환 (getAffine.py))
import cv2
import numpy as np
from matplotlib import pyplot as plt

file_name = 'resource/111.jpg'
img = cv2.imread(file_name)
rows, cols = img.shape[:2]

# ---① 변환 전, 후 각 3개의 좌표 생성
pts1 = np.float32([200, 100], [400, 100], [200, 400](/chloe73/openCV/wiki/200,-100],-[400,-100],-[200,-400))
pts2 = np.float32([160, 140], [420, 120], [500, 240](/chloe73/openCV/wiki/160,-140],-[420,-120],-[500,-240))

# ---② 변환 전 좌표를 이미지에 표시
cv2.circle(img, (200,100), 5, (255,0), -1)
cv2.circle(img, (400,100), 5, (0,255,0), -1)
cv2.circle(img, (200,400), 5, (0,0,255), -1)

#---③ 짝지은 3개의 좌표로 변환 행렬 계산
mtrx = cv2.getAffineTransform(pts1, pts2)
#---④ 어핀 변환 적용
dst = cv2.warpAffine(img, mtrx, (int(cols*1.5), rows))

#---⑤ 결과 출력
cv2.imshow('origin',img)
cv2.imshow('affin', dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

image

💡원근 변환(Perspective Transform)

어핀 변환은 이미지를 2차원으로 뒤트는 변환이었습니다. 반면 원근 변환은 이미지를 3차원으로 변환한다고 보시면 됩니다. 멀리 있는 것은 작게 보이고, 가까이 있는 것은 크게 보이는 게 원근법의 원리입니다. 이 원근법의 원리를 적용해 변환하는 방식이 원근 변환입니다. 원근 변환에 필요한 변환 행렬을 반환해주는 함수는 아래와 같습니다.

지금까지는 이 변환행렬을 cv2.warpAffine() 함수에 전달해주었는데, 원근 변환은 별도의 함수 cv2.warpPerspective() 함수를 써야 합니다. 이 함수의 모든 파라미터는 cv2.warpAffine()과 동일합니다.

# computer vision stduy : 이미지 뒤틀기(원근 변환 (perspective.py))
import cv2
import numpy as np

file_name = "resource/111.jpg"
img = cv2.imread(file_name)
rows, cols = img.shape[:2]

#---① 원근 변환 전 후 4개 좌표
pts1 = np.float32([0,0], [0,rows], [cols, 0], [cols,rows](/chloe73/openCV/wiki/0,0],-[0,rows],-[cols,-0],-[cols,rows))
pts2 = np.float32([100,50], [10,rows-50], [cols-100, 50], [cols-10,rows-50](/chloe73/openCV/wiki/100,50],-[10,rows-50],-[cols-100,-50],-[cols-10,rows-50))

#---② 변환 전 좌표를 원본 이미지에 표시
cv2.circle(img, (0,0), 10, (255,0,0), -1)
cv2.circle(img, (0,rows), 10, (0,255,0), -1)
cv2.circle(img, (cols,0), 10, (0,0,255), -1)
cv2.circle(img, (cols,rows), 10, (0,255,255), -1)

#---③ 원근 변환 행렬 계산
mtrx = cv2.getPerspectiveTransform(pts1, pts2)
#---④ 원근 변환 적용
dst = cv2.warpPerspective(img, mtrx, (cols, rows))

cv2.imshow("origin", img)
cv2.imshow('perspective', dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

image