πŸ“Œμ΄λ―Έμ§€μ²˜λ¦¬ 기초

μ΄μ‚¬λ¬΄μ—˜Β·2023λ…„ 9μ›” 29일

μ΄λ―Έμ§€μ²˜λ¦¬

λͺ©λ‘ 보기
2/6
post-thumbnail

색 곡간 (Color Space)

μƒ‰κ³΅κ°„μ΄λž€?

색을 ν‘œν˜„ν•˜κΈ° μœ„ν•œ λ‹€μ–‘ν•œ 방법을 의미, μ—¬λŸ¬ 방법이 있으며 각각 λͺ©μ μ— 따라 μ„€κ³„λ˜μ–΄ κ³ μœ ν•œ νŠΉμ„±μ„ κ°€μ§„λ‹€.

  • RGB: 일반적으둜 λ””μ§€ν„Έ μ΄λ―Έμ§€μ—μ„œ μ‚¬μš©λ˜λŠ” 색 곡간.
  • HSV: 색상(Hue), 채도(Saturation), λͺ…도(Value)둜 κ΅¬μ„±λœ 색 곡간.
  • LAB: μΈκ°„μ˜ μ‹œκ° 체계와 μœ μ‚¬ν•œ λ°©μ‹μœΌλ‘œ 색 차이λ₯Ό ν‘œν˜„ν•˜λŠ” 색 곡간.
  • Grayscale: 흑백 이미지λ₯Ό μœ„ν•œ 색 곡간.

RGB (Red, Green, Blue)

RGBλŠ” λ””μ§€ν„Έ μ΄λ―Έμ§€μ—μ„œ κ°€μž₯ 널리 μ‚¬μš©λ˜λŠ” 색 κ³΅κ°„μž…λ‹ˆλ‹€.

  • ꡬ성: λΉ¨κ°•(Red), 초둝(Green), νŒŒλž‘(Blue)의 μ„Έ κ°€μ§€ 색상 μ±„λ„λ‘œ κ΅¬μ„±λ©λ‹ˆλ‹€.
  • νŠΉμ§•:
    • 직관적이며, λŒ€λΆ€λΆ„μ˜ λ””μŠ€ν”Œλ ˆμ΄μ™€ μΉ΄λ©”λΌμ—μ„œ 기본적으둜 μ‚¬μš©λ©λ‹ˆλ‹€.
    • 각 채널은 0~255 μ‚¬μ΄μ˜ κ°’μœΌλ‘œ ν‘œν˜„λ˜λ©°, 이λ₯Ό μ‘°ν•©ν•˜μ—¬ 1677만 κ°€μ§€ 색상을 ν‘œν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
      RGB_BOX

HSV (Hue, Saturation, Value)

HSVλŠ” μƒ‰μƒμ˜ μ’…λ₯˜, 강도, 밝기λ₯Ό λΆ„λ¦¬ν•˜μ—¬ ν‘œν˜„ν•˜λŠ” 색 κ³΅κ°„μž…λ‹ˆλ‹€.

  • ꡬ성: 색상(Hue), 채도(Saturation), λͺ…도(Value)둜 κ΅¬μ„±λ©λ‹ˆλ‹€.
  • νŠΉμ§•:
    • Hue: μƒ‰μƒμ˜ μ’…λ₯˜λ₯Ό λ‚˜νƒ€λ‚΄λ©°, 0~360λ„μ˜ κ°λ„λ‘œ ν‘œν˜„λ©λ‹ˆλ‹€ (λΉ¨κ°•, μ£Όν™©, λ…Έλž‘ λ“±).
    • Saturation: μƒ‰μƒμ˜ 강도λ₯Ό λ‚˜νƒ€λ‚΄λ©°, 0~100%의 λ²”μœ„λ‘œ ν‘œν˜„λ©λ‹ˆλ‹€ (100%λŠ” κ°€μž₯ μ§„ν•œ 색).
    • Value: μƒ‰μƒμ˜ 밝기λ₯Ό λ‚˜νƒ€λ‚΄λ©°, 0~100%의 λ²”μœ„λ‘œ ν‘œν˜„λ©λ‹ˆλ‹€.

LAB

LAB 색 곡간은 μΈκ°„μ˜ μ‹œκ° 체계λ₯Ό λ°˜μ˜ν•˜μ—¬ μ„€κ³„λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

  • ꡬ성: L은 밝기, A와 BλŠ” 색상을 ν‘œν˜„ν•©λ‹ˆλ‹€.
  • νŠΉμ§•:
    • L 채널은 밝기λ₯Ό λ‚˜νƒ€λ‚΄λ©°, A와 B 채널은 색상을 λ‚˜νƒ€λƒ…λ‹ˆλ‹€.
    • LAB 색 곡간은 색 차이λ₯Ό μΌκ΄€λ˜κ²Œ ν‘œν˜„ν•  수 μžˆμ–΄ 색상 μ²˜λ¦¬μ— μ ν•©ν•©λ‹ˆλ‹€.

Grayscale

Grayscale은 흑백 이미지λ₯Ό ν‘œν˜„ν•˜κΈ° μœ„ν•œ 색 κ³΅κ°„μž…λ‹ˆλ‹€.

  • νŠΉμ§•:
    • 색상 정보 없이 밝기 μ •λ³΄λ§ŒμœΌλ‘œ 이미지λ₯Ό ν‘œν˜„ν•©λ‹ˆλ‹€.
    • 각 픽셀은 0(검은색)μ—μ„œ 255(흰색) μ‚¬μ΄μ˜ κ°’μœΌλ‘œ ν‘œν˜„λ©λ‹ˆλ‹€.
      GrayscaleBOX

이미지 νžˆμŠ€ν† κ·Έλž¨ (Image Histogram)

νžˆμŠ€ν† κ·Έλž¨μ΄λž€?

λ°μ΄ν„°μ˜ 뢄포λ₯Ό κ·Έλž˜ν”„ ν˜•νƒœλ‘œ ν‘œν˜„ν—Œ κ²ƒμœΌλ‘œ, 이미지 μ²˜λ¦¬μ—μ„œμ˜ νžˆμŠ€ν† κ·Έλž¨μ€ 주둜 μ΄λ―Έμ§€μ˜ 밝기 값을 λ‚˜νƒ€λ‚΄λ©°, 각 밝기 값에 ν•΄λ‹Ήν•˜λŠ” ν”½μ…€μ˜ 수λ₯Ό μ„Έλ‘œμΆ•μœΌλ‘œ ν‘œμ‹œν•œλ‹€.

  • μ΄λ―Έμ§€μ˜ λͺ…μ•” 뢄포λ₯Ό μ‰½κ²Œ νŒŒμ•…ν•  수 있음

  • μ΄λ―Έμ§€μ˜ μ „λ°˜μ μΈ λŒ€λΉ„μ™€ 밝기 μˆ˜μ€€μ„ ν‰κ°€ν•˜κ±°λ‚˜ μ‘°μ •ν•˜λŠ”λ° 도움을 쀌
    histogram

  • xxμΆ• : μ΄λ―Έμ§€μ˜ 밝기(0~255)

  • yyμΆ• : λ“±μž₯ λΉˆλ„

    μ‘μš©

    νžˆμŠ€ν† κ·Έλž¨ ν‰ν™œν™” (Histogram Equalization)

    ν”½μ…€μ˜ 값을 0λΆ€ν„° 255κΉŒμ§€μ˜ λˆ„μ μΉ˜κ°€ 전체 μ˜μ—­μ—μ„œ κ³ λ₯΄κ²Œ λΆ„ν¬λ˜λ„λ‘ λ§Œλ“œλŠ” κΈ°λ²•μœΌλ‘œ 이미지가 μ „μ²΄μ μœΌλ‘œ μ–΄λ‘‘κ±°λ‚˜ 고루 밝아 νŠΉμ§•μ΄ λˆˆμ— 띄지 μ•Šκ±°λ‚˜ 뢄리가 μ–΄λ €μšΈ λ•Œ 자주 μ“°μž…λ‹ˆλ‹€.

    μœ„ 이미지λ₯Ό λ³΄μ‹œλ©΄ λͺ¨μžμ˜ κ·Έλ¦Όμžμ™€ μ—¬μ„± ν”ΌλΆ€μ™€μ˜ λŒ€λΉ„κ°€ 컀진 것을 확인 ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 즉, μ–΄λ‘μš΄ 것은 λ”μš± μ–΄λ‘‘κ²Œ, 밝은 것은 λ”μš± λ°μ•„μ‘ŒμŠ΅λ‹ˆλ‹€. μ΄λŠ” 원본 μ΄λ―Έμ§€μ˜ 뢄포가 쀑간밝기에 λ°€μ§‘λ˜μ—ˆκΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€.

    νžˆμŠ€ν† κ·Έλž¨ λ§€μΉ­ (Histogram Matching)

    νžˆμŠ€ν† κ·Έλž¨ 맀칭은 ν•œ μ΄λ―Έμ§€μ˜ νžˆμŠ€ν† κ·Έλž¨μ„ λ‹€λ₯Έ μ΄λ―Έμ§€μ˜ νžˆμŠ€ν† κ·Έλž¨κ³Ό μœ μ‚¬ν•˜κ²Œ μ‘°μ •ν•˜λŠ” κ³Όμ •μž…λ‹ˆλ‹€. λ‹€μ–‘ν•œ ν™˜κ²½μ—μ„œ 촬영된 μ΄λ―Έμ§€μ˜ 밝기 및 λŒ€λΉ„λ₯Ό μΌκ΄€λ˜κ²Œ λ§Œλ“œλŠ”λ° μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.


이미지 λ³€ν™˜ (Image Transformations)

이미지 λ³€ν™˜μ΄λž€?

이미지 λ³€ν™˜μ€ μ΄λ―Έμ§€μ˜ ν”½μ…€ μœ„μΉ˜λ‚˜ 값을 λ³€κ²½ν•˜μ—¬ 원본 이미지λ₯Ό λ‹€λ₯Έ ν˜•νƒœλ‚˜ λͺ¨μ–‘μœΌλ‘œ λ³€ν™˜ν•˜λŠ” 것을 μ˜λ―Έν•©λ‹ˆλ‹€. κΈ°ν•˜ν•™μ  ꡬ쑰λ₯Ό λ³€κ²½ν•˜κ±°λ‚˜ μ΄λ―Έμ§€μ˜ 밝기, 색상을 μ‘°μ ˆν•  수 있으며 이미지 νŽΈμ§‘, κ°œμ„ , 뢄석 λ“± λ‹€μ–‘ν•œ 처리 μž‘μ—…μ— μ‚¬μš©λ©λ‹ˆλ‹€.

κΈ°ν•˜ν•™μ  λ³€ν™˜ (Geometric Transformations)

κΈ°ν•˜ν•™μ  λ³€ν™˜μ€ μ΄λ―Έμ§€μ˜ λͺ¨μ–‘μ΄λ‚˜ μœ„μΉ˜λ₯Ό λ³€ν™˜ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

- μŠ€μΌ€μΌλ§ (Scaling)

  • μ΄λ―Έμ§€μ˜ 크기λ₯Ό ν™•λŒ€ λ˜λŠ” μΆ•μ†Œν•˜λŠ” λ³€ν™˜μž…λ‹ˆλ‹€.
  • 보간법(Interpolation)을 μ‚¬μš©ν•˜μ—¬ μƒˆλ‘œμš΄ ν”½μ…€ 값을 κ²°μ •ν•©λ‹ˆλ‹€.

- νšŒμ „ 및 이동

  • νšŒμ „μ€ 이미지λ₯Ό 쀑심점을 κΈ°μ€€μœΌλ‘œ νŠΉμ • κ°λ„λ‘œ νšŒμ „μ‹œν‚€λŠ” λ³€ν™˜μž…λ‹ˆλ‹€.
  • 이동은 이미지λ₯Ό x, y λ°©ν–₯으둜 νŠΉμ • 거리만큼 μ΄λ™μ‹œν‚€λŠ” λ³€ν™˜μž…λ‹ˆλ‹€.

- μ•„ν•€ λ³€ν™˜

  • μŠ€μΌ€μΌλ§, νšŒμ „, 이동 λ“±μ˜ κΈ°λ³Έ λ³€ν™˜μ„ μ‘°ν•©ν•˜μ—¬ μˆ˜ν–‰ν•˜λŠ” λ³€ν™˜μž…λ‹ˆλ‹€.
  • 3개의 점을 원본 이미지와 λŒ€μƒ 이미지 간에 λ§€ν•‘ν•˜μ—¬ λ³€ν™˜ 맀트릭슀λ₯Ό μƒμ„±ν•˜κ³ , 이λ₯Ό μ‚¬μš©ν•˜μ—¬ 이미지λ₯Ό λ³€ν™˜ν•©λ‹ˆλ‹€.

Python Example

πŸ’» 예제

import cv2
import numpy as np
import matplotlib.pyplot as plt
# ν¬μΈνŠΈμ— 원을 κ·Έλ €μ£ΌλŠ” ν•¨μˆ˜
def draw_points(image, points, color, border_color, size=3):
    for point in points:
        center = (int(point[0]), int(point[1]))
        cv2.circle(image, center, size, border_color, -1)
        cv2.circle(image, center, size-1, color, -1)
# 이미지 뢈러였기
img = cv2.imread('lenna.jpg')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

# μ•„ν•€ λ³€ν™˜
rows, cols, ch = img.shape
src_points = np.float32([[0, 0], [cols - 1, 0], [0, rows - 1]])
dst_points = np.float32([[cols * 0.1, rows * 0.1], [cols * 0.9, rows * 0.2], [cols * 0.1, rows * 0.9]])
affine_matrix = cv2.getAffineTransform(src_points, dst_points)
affine_transformed = cv2.warpAffine(img, affine_matrix, (cols, rows))

# 원본 이미지와 μ•„ν•€ λ³€ν™˜λœ 이미지에 포인트 그리기
draw_points(img, src_points, (255, 255, 255), (0, 0, 0))
draw_points(affine_transformed, dst_points, (255, 255, 255), (0, 0, 0))

# κ²°κ³Ό 이미지 ν‘œμ‹œ
fig, axes = plt.subplots(1, 2, figsize=(10, 5))
axes[0].imshow(img)
axes[0].set_title("Original Image")
axes[1].imshow(affine_transformed)
axes[1].set_title("Affine Transformed")
plt.tight_layout()
plt.show()


원근 λ³€ν™˜

  • 3D κ³΅κ°„μ˜ 점듀을 2D 이미지 평면에 νˆ¬μ˜ν•  λ•Œ λ°œμƒν•˜λŠ” λ³€ν™˜μž…λ‹ˆλ‹€.
  • 원근 λ³€ν™˜μ€ 4개의 점을 원본 이미지와 λŒ€μƒ 이미지 간에 λ§€ν•‘ν•˜μ—¬ λ³€ν™˜ 맀트릭슀λ₯Ό μƒμ„±ν•©λ‹ˆλ‹€. 이 λ³€ν™˜μ€ 특히 3D κ³΅κ°„μ˜ 객체λ₯Ό 2D μ΄λ―Έμ§€λ‘œ νˆ¬μ˜ν•˜κ±°λ‚˜, λ°˜λŒ€λ‘œ 2D μ΄λ―Έμ§€μ—μ„œ 3D κ³΅κ°„μœΌλ‘œ λ³€ν™˜ν•  λ•Œ μ‚¬μš©λ©λ‹ˆλ‹€.

Python Example

πŸ’» 예제

# 이미지 뢈러였기
img = cv2.imread('lenna.jpg')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
rows, cols, _ = img.shape

# 원근 λ³€ν™˜
src_points = np.float32([[0, 0], [cols - 1, 0], [0, rows - 1], [cols - 1, rows - 1]])
dst_points = np.float32([[cols * 0.3, rows * 0.1], [cols * 0.7, rows * 0.1], [cols * 0.1, rows * 0.9], [cols * 0.9, rows * 0.9]])
perspective_matrix = cv2.getPerspectiveTransform(src_points, dst_points)
perspective_transformed = cv2.warpPerspective(img, perspective_matrix, (cols, rows))

# 원본 이미지와 μ•„ν•€ λ³€ν™˜λœ 이미지에 포인트 그리기
draw_points(img, src_points, (255, 255, 255), (0, 0, 0))
draw_points(perspective_transformed, dst_points, (255, 255, 255), (0, 0, 0))

# κ²°κ³Ό 이미지 ν‘œμ‹œ
fig, axes = plt.subplots(1, 2, figsize=(10, 5))
axes[0].imshow(img)
axes[0].set_title("Original Image")
axes[1].imshow(perspective_transformed)
axes[1].set_title("Perspective Transformed")
plt.tight_layout()
plt.show()

강도 λ³€ν™˜ (Intensity Transformations)

강도 λ³€ν™˜μ€ μ΄λ―Έμ§€μ˜ ν”½μ…€ κ°’ 자체λ₯Ό λ³€ν™˜ ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

  • νžˆμŠ€ν† κ·Έλž¨ ν‰ν™œν™”, λ§€μΉ­
  • 감마 보정 λ“±..

πŸ’» 라이브러리 및 이미지 호좜

import cv2
import numpy as np
import matplotlib.pyplot as plt

# 이미지 뢈러였기
image = cv2.imread('lenna.jpg', cv2.IMREAD_GRAYSCALE)

πŸ’» νžˆμŠ€ν† κ·Έλž¨ Plot

# νžˆμŠ€ν† κ·Έλž¨ 계산
hist = cv2.calcHist([image], [0], None, [256], [0,256])

plt.figure()
plt.title("Lenna Image Histogram")
plt.xlabel("Bins")
plt.ylabel("# of Pixels")
plt.plot(hist)
plt.xlim([0, 256])
plt.show()

πŸ’» νžˆμŠ€ν† κ·Έλž¨ ν‰ν™œν™”

# 이미지 뢈러였기
image = cv2.imread('lenna.jpg', cv2.IMREAD_GRAYSCALE)

# νžˆμŠ€ν† κ·Έλž¨ ν‰ν™œν™”
equalized_image = cv2.equalizeHist(image)


fig, axes = plt.subplots(1, 2, figsize=(5, 10))
axes[0].imshow(image, cmap='gray')
axes[1].imshow(equalized_image, cmap='gray')
plt.show()

πŸ’» νžˆμŠ€ν† κ·Έλž¨ λ§€μΉ­

def histogram_matching(source, reference):
    s_values, bin_idx, s_counts = np.unique(source, return_inverse=True, return_counts=True)
    r_values, r_counts = np.unique(reference, return_counts=True)

    s_quantiles = np.cumsum(s_counts).astype(np.float64)
    s_quantiles /= s_quantiles[-1]
    r_quantiles = np.cumsum(r_counts).astype(np.float64)
    r_quantiles /= r_quantiles[-1]

    interp_r_values = np.interp(s_quantiles, r_quantiles, r_values)
    matched = interp_r_values[bin_idx].reshape(source.shape)
    return matched

# 원본 이미지와 μ°Έμ‘° 이미지 뢈러였기
source = cv2.imread('lenna.jpg', cv2.IMREAD_GRAYSCALE)
reference = cv2.imread('ref.jpg', cv2.IMREAD_GRAYSCALE)

matched_image = histogram_matching(source, reference)

fig, axes = plt.subplots(2, 3, figsize=(15, 10))
# Images
axes[0, 0].imshow(source, cmap='gray')
axes[0, 0].set_title("Source Image")
axes[0, 1].imshow(reference, cmap='gray')
axes[0, 1].set_title("Reference Image")
axes[0, 2].imshow(matched_image, cmap='gray')
axes[0, 2].set_title("Matched Image")

# Histograms
axes[1, 0].hist(source.ravel(), 256, [0,256], color='black')
axes[1, 0].set_title("Source Histogram")
axes[1, 1].hist(reference.ravel(), 256, [0,256], color='black')
axes[1, 1].set_title("Reference Histogram")
axes[1, 2].hist(matched_image.ravel(), 256, [0,256], color='black')
axes[1, 2].set_title("Matched Histogram")

plt.tight_layout()
plt.show()


0개의 λŒ“κΈ€