μμ 곡κ°
μμ 곡갶
κ°μ¶
μ»΄ν¨ν° λΉμ μμ μμ 곡κ°(Color Space)μ μμμ νννλ λ°©λ²μ λλ€. OpenCVλ κΈ°λ³Έμ μΌλ‘ BGR μμ 곡κ°μ μ¬μ©νμ§λ§, νΉμ μμ μλ HSV, LAB λ± λ€λ₯Έ μμ 곡κ°μ΄ λ ν¨κ³Όμ μ λλ€. μ΄ λ¬Έμμμλ λ€μν μμ 곡κ°μ νΉμ±κ³Ό λ³ν λ°©λ², κ·Έλ¦¬κ³ μμ κΈ°λ° κ°μ²΄ μΆμ μ νμ΅ν©λλ€.
λμ΄λ: ββ (μ΄κΈ-μ€κΈ)
νμ΅ λͺ©ν:
- BGRκ³Ό RGBμ μ°¨μ΄ μ΄ν΄
- HSV μμ 곡κ°μ μ리μ νμ©
- cv2.cvtColor()λ₯Ό μ¬μ©ν μμ κ³΅κ° λ³ν
- μ±λ λΆλ¦¬/λ³ν©
- μμ κΈ°λ° κ°μ²΄ μΆμ ꡬν
λͺ©μ°¨¶
- BGR vs RGB
- cv2.cvtColor()μ μμ λ³ν μμ
- HSV μμ 곡κ°
- LAB μμ 곡κ°
- κ·Έλ μ΄μ€μΌμΌ λ³ν
- μ±λ λΆλ¦¬μ λ³ν©
- μμ κΈ°λ° κ°μ²΄ μΆμ
- μ°μ΅ λ¬Έμ
- λ€μ λ¨κ³
- μ°Έκ³ μλ£
1. BGR vs RGB¶
OpenCVμ κΈ°λ³Έ μμ μμ¶
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β BGR vs RGB λΉκ΅ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β OpenCV (BGR) λλΆλΆμ λΌμ΄λΈλ¬λ¦¬ (RGB) β
β βββββββββββββββ βββββββββββββββ β
β β B β G β R β β R β G β B β β
β β[0]β[1]β[2]β β[0]β[1]β[2]β β
β βββββββββββββββ βββββββββββββββ β
β β
β μμν λΉ¨κ°μ: μμν λΉ¨κ°μ: β
β [0, 0, 255] [255, 0, 0] β
β β
β μμν νλμ: μμν νλμ: β
β [255, 0, 0] [0, 0, 255] β
β β
β OpenCV μ¬μ© λΌμ΄λΈλ¬λ¦¬: RGB μ¬μ© λΌμ΄λΈλ¬λ¦¬: β
β - cv2.imread() - matplotlib β
β - cv2.imshow() - PIL/Pillow β
β - cv2.imwrite() - Tkinter β
β - μΉ λΈλΌμ°μ (CSS/HTML) β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
BGRμ μ¬μ©νλ μ΄μ ¶
μμ¬μ μΈ μ΄μ μ λλ€. μ΄κΈ° μΉ΄λ©λΌμ λμ€νλ μ΄ νλμ¨μ΄κ° BGR μμλ‘ λ°μ΄ν°λ₯Ό μ μ₯νκ³ , OpenCVλ μ΄ κ΄λ‘λ₯Ό λ°λμ΅λλ€.
BGR β RGB λ³ν¶
import cv2
import numpy as np
# μ΄λ―Έμ§ μ½κΈ° (BGR)
img_bgr = cv2.imread('image.jpg')
# BGR β RGB λ³ν
img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)
# RGB β BGR λ³ν
img_bgr_back = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2BGR)
# NumPyλ‘ μ§μ λ³ν (μ¬λΌμ΄μ±)
img_rgb_np = img_bgr[:, :, ::-1] # μ±λ μμ λ€μ§κΈ°
img_rgb_np = img_bgr[..., ::-1] # λμΌν κ²°κ³Ό
# μ±λλ³ μ€μ
b, g, r = cv2.split(img_bgr)
img_rgb_split = cv2.merge([r, g, b])
matplotlibκ³Ό ν¨κ» μ¬μ©νκΈ°¶
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('image.jpg')
# μλͺ»λ νμ (BGR κ·Έλλ‘ β μμμ΄ λ€λ°λ)
plt.figure(figsize=(12, 4))
plt.subplot(1, 3, 1)
plt.imshow(img) # BGR κ·Έλλ‘ β λΉ¨κ°κ³Ό νλμ΄ λ€λ°λ
plt.title('Wrong (BGR)')
plt.axis('off')
# μ¬λ°λ₯Έ νμ (RGBλ‘ λ³ν)
plt.subplot(1, 3, 2)
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.imshow(img_rgb)
plt.title('Correct (RGB)')
plt.axis('off')
# κ·Έλ μ΄μ€μΌμΌ
plt.subplot(1, 3, 3)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
plt.imshow(gray, cmap='gray')
plt.title('Grayscale')
plt.axis('off')
plt.tight_layout()
plt.show()
2. cv2.cvtColor()μ μμ λ³ν μμ¶
κΈ°λ³Έ μ¬μ©λ²¶
import cv2
img = cv2.imread('image.jpg')
# cv2.cvtColor(src, code) - μμ κ³΅κ° λ³ν
dst = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
μ£Όμ λ³ν μ½λ¶
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β μ£Όμ μμ λ³ν μ½λ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β BGR β κΈ°ν μμ κ³΅κ° β
β βββ COLOR_BGR2RGB / COLOR_RGB2BGR β
β βββ COLOR_BGR2GRAY / COLOR_GRAY2BGR β
β βββ COLOR_BGR2HSV / COLOR_HSV2BGR β
β βββ COLOR_BGR2LAB / COLOR_LAB2BGR β
β βββ COLOR_BGR2YCrCb / COLOR_YCrCb2BGR β
β βββ COLOR_BGR2HLS / COLOR_HLS2BGR β
β β
β RGB β κΈ°ν μμ κ³΅κ° β
β βββ COLOR_RGB2GRAY / COLOR_GRAY2RGB β
β βββ COLOR_RGB2HSV / COLOR_HSV2RGB β
β βββ COLOR_RGB2LAB / COLOR_LAB2RGB β
β βββ COLOR_RGB2HLS / COLOR_HLS2RGB β
β β
β νΉμ λ³ν β
β βββ COLOR_BGR2HSV_FULL (H: 0-255) β
β βββ COLOR_BGR2HSV (H: 0-179) β
β βββ COLOR_BayerBG2BGR (Bayer β BGR) β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
λ³ν μμ¶
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('image.jpg')
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# λ€μν μμ 곡κ°μΌλ‘ λ³ν
conversions = {
'Original (RGB)': img_rgb,
'Grayscale': cv2.cvtColor(img, cv2.COLOR_BGR2GRAY),
'HSV': cv2.cvtColor(img, cv2.COLOR_BGR2HSV),
'LAB': cv2.cvtColor(img, cv2.COLOR_BGR2LAB),
'YCrCb': cv2.cvtColor(img, cv2.COLOR_BGR2YCrCb),
'HLS': cv2.cvtColor(img, cv2.COLOR_BGR2HLS),
}
fig, axes = plt.subplots(2, 3, figsize=(12, 8))
axes = axes.flatten()
for ax, (name, converted) in zip(axes, conversions.items()):
if len(converted.shape) == 2:
ax.imshow(converted, cmap='gray')
else:
ax.imshow(converted)
ax.set_title(name)
ax.axis('off')
plt.tight_layout()
plt.show()
3. HSV μμ 곡갶
HSVλ?¶
HSVλ μμ(Hue), μ±λ(Saturation), λͺ λ(Value)λ‘ μμ ννν©λλ€.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β HSV μμ κ³΅κ° β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β H (Hue) - μμ β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β 0Β° 60Β° 120Β° 180Β° 240Β° 300Β° 360Β° β β
β β λΉ¨κ° λ
Έλ μ΄λ‘ μ²λ‘ νλ λ³΄λΌ λΉ¨κ° β β
β β ββββββββΌβββββββΌβββββββΌβββββββΌβββββββΌβββββββ€ β β
β β 0 30 60 90 120 150 179 β β
β β (OpenCVμμ H λ²μ: 0-179) β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β S (Saturation) - μ±λ (0-255) β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β 0 (무μ±μ/νμ) βββββββββββββββΆ 255 (μμν μ) β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β V (Value) - λͺ
λ (0-255) β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β 0 (κ²μμ) βββββββββββββββββββΆ 255 (λ°μ μ) β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β V (λ°κΈ°) β
β β² β
β β ν°μ β
β β / β
β β / β
β β / μμν μ β
β β/ββββββββ β
β β β² β
β β β² S (μ±λ) β
β β β² β
β βββββββββββββ²ββββΆ H (μμ, μν) β
β κ²μμ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
HSV λ³ν λ° μ±λ νμΈ¶
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('image.jpg')
# BGR β HSV λ³ν
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# μ±λ λΆλ¦¬
h, s, v = cv2.split(hsv)
# μκ°ν
fig, axes = plt.subplots(2, 2, figsize=(10, 10))
axes[0, 0].imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
axes[0, 0].set_title('Original')
axes[0, 1].imshow(h, cmap='hsv') # Hueλ hsv 컬λ¬λ§΅ μ¬μ©
axes[0, 1].set_title('H (Hue)')
axes[1, 0].imshow(s, cmap='gray')
axes[1, 0].set_title('S (Saturation)')
axes[1, 1].imshow(v, cmap='gray')
axes[1, 1].set_title('V (Value)')
for ax in axes.flatten():
ax.axis('off')
plt.tight_layout()
plt.show()
HSVμ μ₯μ ¶
import cv2
import numpy as np
# RGB/BGRμμλ μ‘°λͺ
λ³νμ λ―Όκ°
# HSVμμλ V μ±λλ§ μν₯λ°μ β μμ κ²μΆμ μ 리
# μ: λΉ¨κ°μ κ²μΆ
img = cv2.imread('red_objects.jpg')
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# λΉ¨κ°μ λ²μ μ μ (Hueκ° 0 λλ 180 κ·Όμ²)
# λΉ¨κ°μμ Hue λ²μμ μ λμ μμ
lower_red1 = np.array([0, 100, 100])
upper_red1 = np.array([10, 255, 255])
lower_red2 = np.array([160, 100, 100])
upper_red2 = np.array([179, 255, 255])
# λ§μ€ν¬ μμ±
mask1 = cv2.inRange(hsv, lower_red1, upper_red1)
mask2 = cv2.inRange(hsv, lower_red2, upper_red2)
mask = mask1 | mask2 # λ λ§μ€ν¬ ν©μΉκΈ°
# κ²°κ³Ό νμ
result = cv2.bitwise_and(img, img, mask=mask)
cv2.imshow('Original', img)
cv2.imshow('Mask', mask)
cv2.imshow('Result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
μ£Όμ μμμ HSV λ²μ¶
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β μ£Όμ μμ HSV λ²μ (OpenCV) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β μμ H (Hue) S (Saturation) V (Value) β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β λΉ¨κ° 0-10, 160-179 100-255 100-255 β
β μ£Όν© 10-25 100-255 100-255 β
β λ
Έλ 25-35 100-255 100-255 β
β μ΄λ‘ 35-85 100-255 100-255 β
β μ²λ‘ 85-95 100-255 100-255 β
β νλ 95-130 100-255 100-255 β
β λ³΄λΌ 130-160 100-255 100-255 β
β β
β ν°μ 0-179 0-30 200-255 β
β κ²μ 0-179 0-255 0-50 β
β νμ 0-179 0-30 50-200 β
β β
β μ£Όμ: μ‘°λͺ
쑰건μ λ°λΌ λ²μ μ‘°μ νμ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
4. LAB μμ 곡갶
LABμ΄λ?¶
LAB(λλ CIELAB)μ μΈκ°μ μμ μΈμ§μ κΈ°λ°ν μμ 곡κ°μ λλ€.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β LAB μμ κ³΅κ° β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β L (Lightness) - λ°κΈ° β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β 0 (κ²μ ) βββββββββββββββββββββββΆ 255 (ν°μ) β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β A - μ΄λ‘(-) β λΉ¨κ°(+) β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β 0 (μ΄λ‘) ββββββ 128 (μ€λ¦½) ββββββ 255 (λΉ¨κ°) β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β B - νλ(-) β λ
Έλ(+) β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β 0 (νλ) ββββββ 128 (μ€λ¦½) ββββββ 255 (λ
Έλ) β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β +B (λ
Έλ) β
β β² β
β β β
β -A ββββββββββΌβββββββββΆ +A β
β (μ΄λ‘) β (λΉ¨κ°) β
β β β
β βΌ β
β -B (νλ) β
β β
β μ₯μ : β
β - μΈκ° μκ°κ³Ό μ μ¬ν μμ 거리 κ³μ° β
β - λ°κΈ°μ μμμ΄ λΆλ¦¬λ¨ β
β - μμ 보μ , μμ μ μ΄μ μ μ© β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
LAB λ³ν λ° νμ©¶
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('image.jpg')
# BGR β LAB λ³ν
lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
# μ±λ λΆλ¦¬
l, a, b = cv2.split(lab)
# L μ±λ μ‘°μ μΌλ‘ λ°κΈ° 보μ
l_adjusted = cv2.add(l, 30) # λ°κΈ° μ¦κ°
l_adjusted = np.clip(l_adjusted, 0, 255).astype(np.uint8)
# λ€μ ν©μΉκΈ°
lab_adjusted = cv2.merge([l_adjusted, a, b])
result = cv2.cvtColor(lab_adjusted, cv2.COLOR_LAB2BGR)
# μκ°ν
fig, axes = plt.subplots(2, 3, figsize=(12, 8))
axes[0, 0].imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
axes[0, 0].set_title('Original')
axes[0, 1].imshow(l, cmap='gray')
axes[0, 1].set_title('L (Lightness)')
axes[0, 2].imshow(a, cmap='RdYlGn_r')
axes[0, 2].set_title('A (Green-Red)')
axes[1, 0].imshow(b, cmap='YlGnBu_r')
axes[1, 0].set_title('B (Blue-Yellow)')
axes[1, 1].imshow(cv2.cvtColor(result, cv2.COLOR_BGR2RGB))
axes[1, 1].set_title('Brightness Adjusted')
for ax in axes.flatten():
ax.axis('off')
axes[1, 2].axis('off')
plt.tight_layout()
plt.show()
CLAHEλ‘ LAB λ°κΈ° λ³΄μ ¶
import cv2
img = cv2.imread('dark_image.jpg')
# LAB λ³ν
lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
l, a, b = cv2.split(lab)
# CLAHE μ μ© (Contrast Limited Adaptive Histogram Equalization)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
l_clahe = clahe.apply(l)
# λ€μ ν©μΉκΈ°
lab_clahe = cv2.merge([l_clahe, a, b])
result = cv2.cvtColor(lab_clahe, cv2.COLOR_LAB2BGR)
cv2.imshow('Original', img)
cv2.imshow('CLAHE Result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
5. κ·Έλ μ΄μ€μΌμΌ λ³ν¶
λ³ν μ리¶
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β κ·Έλ μ΄μ€μΌμΌ λ³ν μ리 β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β BGR β Grayscale λ³ν 곡μ: β
β β
β Gray = 0.114 Γ B + 0.587 Γ G + 0.299 Γ R β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β μ λ¨μ νκ· μ΄ μλκΉ? β β
β β β β
β β μΈκ°μ λμ λ
Ήμμ κ°μ₯ λ―Όκ°νκ³ , νλμμ κ°μ₯ λκ°ν¨ β β
β β λ°λΌμ λ
Ήμ(G)μ κ°μ€μΉκ° κ°μ₯ λμ (0.587) β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β μ»¬λ¬ μ΄λ―Έμ§ κ·Έλ μ΄μ€μΌμΌ β
β βββββββββββββββββ βββββββββββββββββ β
β β B β G β R β β Gray β β
β β200β100β 50β ββββΆ β 121 β β
β βββββββββββββββββ βββββββββββββββββ β
β 0.114Γ200 + 0.587Γ100 + 0.299Γ50 = 121.45 β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
κ·Έλ μ΄μ€μΌμΌ λ³ν λ°©λ²¶
import cv2
import numpy as np
img = cv2.imread('image.jpg')
# λ°©λ² 1: cvtColor (κΆμ₯)
gray1 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# λ°©λ² 2: imreadλ‘ μ§μ μ½κΈ°
gray2 = cv2.imread('image.jpg', cv2.IMREAD_GRAYSCALE)
# λ°©λ² 3: NumPyλ‘ μ§μ κ³μ° (νμ΅μ©)
b, g, r = cv2.split(img)
gray3 = (0.114 * b + 0.587 * g + 0.299 * r).astype(np.uint8)
# λ°©λ² 4: λ¨μ νκ· (λΉμΆμ² - μκ°μ μΌλ‘ λΆμμ°μ€λ¬μ)
gray4 = np.mean(img, axis=2).astype(np.uint8)
# κ²°κ³Ό λΉκ΅
print(f"cvtColor κ²°κ³Ό: {gray1.shape}")
print(f"μ§μ κ³μ° κ²°κ³Ό: {gray3.shape}")
print(f"μ°¨μ΄ μ΅λκ°: {np.max(np.abs(gray1.astype(int) - gray3.astype(int)))}")
κ·Έλ μ΄μ€μΌμΌ β μ»¬λ¬ (μμ¬ μ»¬λ¬)¶
import cv2
gray = cv2.imread('image.jpg', cv2.IMREAD_GRAYSCALE)
# κ·Έλ μ΄μ€μΌμΌ β 3μ±λ (μ¬μ ν νλ°±)
gray_3ch = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)
# 컬λ¬λ§΅ μ μ© (ννΈλ§΅ λ±)
# COLORMAP_JET, COLORMAP_HOT, COLORMAP_RAINBOW λ±
colormap = cv2.applyColorMap(gray, cv2.COLORMAP_JET)
cv2.imshow('Grayscale', gray)
cv2.imshow('Colormap', colormap)
cv2.waitKey(0)
cv2.destroyAllWindows()
6. μ±λ λΆλ¦¬μ λ³ν©¶
cv2.split()κ³Ό cv2.merge()¶
import cv2
import numpy as np
img = cv2.imread('image.jpg')
# μ±λ λΆλ¦¬
b, g, r = cv2.split(img)
# λλ NumPy μΈλ±μ± μ¬μ© (λ λΉ λ¦)
b = img[:, :, 0]
g = img[:, :, 1]
r = img[:, :, 2]
# μ±λ λ³ν©
merged = cv2.merge([b, g, r]) # BGR μμ
# μ±λ μμ λ³κ²½νμ¬ λ³ν© (BGR β RGB)
rgb = cv2.merge([r, g, b])
# λΉ μ±λκ³Ό μ‘°ν© (λ¨μΌ μ±λλ§ νμ)
zeros = np.zeros_like(b)
only_blue = cv2.merge([b, zeros, zeros])
only_green = cv2.merge([zeros, g, zeros])
only_red = cv2.merge([zeros, zeros, r])
μ±λλ³ μκ°ν¶
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('image.jpg')
b, g, r = cv2.split(img)
fig, axes = plt.subplots(2, 3, figsize=(12, 8))
# μλ³Έ
axes[0, 0].imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
axes[0, 0].set_title('Original')
# κ° μ±λ (κ·Έλ μ΄μ€μΌμΌλ‘)
axes[0, 1].imshow(r, cmap='gray')
axes[0, 1].set_title('Red Channel')
axes[0, 2].imshow(g, cmap='gray')
axes[0, 2].set_title('Green Channel')
axes[1, 0].imshow(b, cmap='gray')
axes[1, 0].set_title('Blue Channel')
# κ° μ±λ (컬λ¬λ‘)
zeros = np.zeros_like(b)
axes[1, 1].imshow(cv2.merge([zeros, zeros, r])) # RGB μμ
axes[1, 1].set_title('Red Only')
axes[1, 2].imshow(cv2.merge([zeros, g, zeros]))
axes[1, 2].set_title('Green Only')
for ax in axes.flatten():
ax.axis('off')
plt.tight_layout()
plt.show()
μ±λ μ‘°μ μμ ¶
import cv2
import numpy as np
img = cv2.imread('image.jpg')
# 1. νΉμ μ±λ μ¦ν
b, g, r = cv2.split(img)
r_boost = np.clip(r.astype(np.int16) + 50, 0, 255).astype(np.uint8)
warm = cv2.merge([b, g, r_boost]) # λ°λ»ν μμ‘°
# 2. μ±λ μ€μ
b, g, r = cv2.split(img)
swapped = cv2.merge([r, g, b]) # Rκ³Ό B κ΅ν
# 3. μ±λ νκ· μΌλ‘ κ·Έλ μ΄μ€μΌμΌ
b, g, r = cv2.split(img)
gray_avg = ((b.astype(np.int16) + g + r) // 3).astype(np.uint8)
# 4. νΉμ μ±λλ§ μ μ§ (λλ¨Έμ§ 0μΌλ‘)
b, g, r = cv2.split(img)
only_r = cv2.merge([np.zeros_like(b), np.zeros_like(g), r])
7. μμ κΈ°λ° κ°μ²΄ μΆμ ¶
inRange()λ₯Ό μ¬μ©ν μμ νν°λ§¶
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β μμ κΈ°λ° κ°μ²΄ μΆμ νμ΄νλΌμΈ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β μ
λ ₯ μ΄λ―Έμ§ (BGR) β
β β β
β βΌ β
β HSV λ³ν β
β β β
β βΌ β
β cv2.inRange(hsv, lower, upper) βββΆ μ΄μ§ λ§μ€ν¬ β
β β β
β βΌ β
β λ
Έμ΄μ¦ μ κ±° (λͺ¨ν΄λ‘μ§ μ°μ°) β
β β β
β βΌ β
β μ€κ³½μ κ²μΆ β
β β β
β βΌ β
β κ°μ²΄ μμΉ/ν¬κΈ° μΆμΆ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
μμ μΆμ ꡬν¶
import cv2
import numpy as np
def track_color(img, lower_hsv, upper_hsv):
"""νΉμ μμ λ²μμ κ°μ²΄λ₯Ό μΆμ """
# HSV λ³ν
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# λ§μ€ν¬ μμ±
mask = cv2.inRange(hsv, lower_hsv, upper_hsv)
# λ
Έμ΄μ¦ μ κ±°
kernel = np.ones((5, 5), np.uint8)
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
# μ€κ³½μ κ²μΆ
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
# 결과 그리기
result = img.copy()
for contour in contours:
area = cv2.contourArea(contour)
if area > 500: # μ΅μ λ©΄μ νν°
x, y, w, h = cv2.boundingRect(contour)
cv2.rectangle(result, (x, y), (x+w, y+h), (0, 255, 0), 2)
# μ€μ¬μ
cx, cy = x + w//2, y + h//2
cv2.circle(result, (cx, cy), 5, (0, 0, 255), -1)
return result, mask
# μ¬μ© μ: νλμ μΆμ
img = cv2.imread('blue_objects.jpg')
lower_blue = np.array([100, 100, 100])
upper_blue = np.array([130, 255, 255])
result, mask = track_color(img, lower_blue, upper_blue)
cv2.imshow('Original', img)
cv2.imshow('Mask', mask)
cv2.imshow('Result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
μ€μκ° μμ μΆμ (μΉμΊ )¶
import cv2
import numpy as np
def nothing(x):
pass
# νΈλλ° μμ±
cv2.namedWindow('Trackbars')
cv2.createTrackbar('H_Low', 'Trackbars', 0, 179, nothing)
cv2.createTrackbar('H_High', 'Trackbars', 179, 179, nothing)
cv2.createTrackbar('S_Low', 'Trackbars', 100, 255, nothing)
cv2.createTrackbar('S_High', 'Trackbars', 255, 255, nothing)
cv2.createTrackbar('V_Low', 'Trackbars', 100, 255, nothing)
cv2.createTrackbar('V_High', 'Trackbars', 255, 255, nothing)
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
if not ret:
break
# νΈλλ° κ° μ½κΈ°
h_low = cv2.getTrackbarPos('H_Low', 'Trackbars')
h_high = cv2.getTrackbarPos('H_High', 'Trackbars')
s_low = cv2.getTrackbarPos('S_Low', 'Trackbars')
s_high = cv2.getTrackbarPos('S_High', 'Trackbars')
v_low = cv2.getTrackbarPos('V_Low', 'Trackbars')
v_high = cv2.getTrackbarPos('V_High', 'Trackbars')
lower = np.array([h_low, s_low, v_low])
upper = np.array([h_high, s_high, v_high])
# HSV λ³ν λ° λ§μ€ν¬
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, lower, upper)
result = cv2.bitwise_and(frame, frame, mask=mask)
cv2.imshow('Frame', frame)
cv2.imshow('Mask', mask)
cv2.imshow('Result', result)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
λ€μ€ μμ μΆμ ¶
import cv2
import numpy as np
# μ¬λ¬ μμ μ μ
colors = {
'red': {
'lower1': np.array([0, 100, 100]),
'upper1': np.array([10, 255, 255]),
'lower2': np.array([160, 100, 100]),
'upper2': np.array([179, 255, 255]),
'color': (0, 0, 255)
},
'green': {
'lower': np.array([35, 100, 100]),
'upper': np.array([85, 255, 255]),
'color': (0, 255, 0)
},
'blue': {
'lower': np.array([100, 100, 100]),
'upper': np.array([130, 255, 255]),
'color': (255, 0, 0)
}
}
def track_multiple_colors(img, colors):
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
result = img.copy()
for name, params in colors.items():
# λ§μ€ν¬ μμ±
if 'lower1' in params: # λΉ¨κ°μμ²λΌ λ²μκ° λ κ°μΈ κ²½μ°
mask1 = cv2.inRange(hsv, params['lower1'], params['upper1'])
mask2 = cv2.inRange(hsv, params['lower2'], params['upper2'])
mask = mask1 | mask2
else:
mask = cv2.inRange(hsv, params['lower'], params['upper'])
# μ€κ³½μ κ²μΆ
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
for contour in contours:
if cv2.contourArea(contour) > 500:
x, y, w, h = cv2.boundingRect(contour)
cv2.rectangle(result, (x, y), (x+w, y+h), params['color'], 2)
cv2.putText(result, name, (x, y-10),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, params['color'], 2)
return result
8. μ°μ΅ λ¬Έμ ¶
μ°μ΅ 1: μμ νλ νΈ μμ±¶
16κ°μ§ μ£Όμ μμ(λΉ¨κ°, μ£Όν©, λ Έλ, μ΄λ‘, μ²λ‘, νλ, 보λΌ, λΆν, ν°μ, κ²μ , νμ λ±)μ BGR κ°μΌλ‘ μ μνκ³ , 100x100 ν¬κΈ°μ μμ μΉ©μ 4x4 격μλ‘ λ°°μΉν νλ νΈ μ΄λ―Έμ§λ₯Ό μμ±νμΈμ.
μ°μ΅ 2: HSV μμ μ νκΈ°¶
λ§μ°μ€λ‘ μ΄λ―Έμ§λ₯Ό ν΄λ¦νλ©΄ ν΄λΉ ν½μ μ HSV κ°μ μΆλ ₯νκ³ , κ·Έ μμκ³Ό μ μ¬ν λͺ¨λ μμμ νμ΄λΌμ΄νΈνλ νλ‘κ·Έλ¨μ μμ±νμΈμ.
# ννΈ: cv2.setMouseCallback() μ¬μ©
def on_click(event, x, y, flags, param):
if event == cv2.EVENT_LBUTTONDOWN:
# ν΄λ¦ν μμΉμ HSV κ° μΆλ ₯
pass
μ°μ΅ 3: μ±λ μ€μ ν¨κ³Ό¶
μ΄λ―Έμ§μ μ±λμ λ€μνκ² μ‘°ν©νμ¬ 6κ°μ§ ν¨κ³Ό(BGR, BRG, GBR, GRB, RBG, RGB)λ₯Ό λ§λ€κ³ λΉκ΅νμΈμ.
μ°μ΅ 4: νΌλΆμ κ²μΆ¶
HSVμ YCrCb μμ 곡κ°μ μ¬μ©νμ¬ μ΄λ―Έμ§μμ νΌλΆμ μμμ κ²μΆνμΈμ. λ λ°©λ²μ κ²°κ³Όλ₯Ό λΉκ΅νμΈμ.
# νΌλΆμ HSV λ²μ μμ
# H: 0-50, S: 20-150, V: 70-255
# νΌλΆμ YCrCb λ²μ μμ
# Y: 0-255, Cr: 135-180, Cb: 85-135
μ°μ΅ 5: μμ μ μ΄ μ λλ©μ΄μ ¶
H μ±λμ μ μ§μ μΌλ‘ μ¦κ°μμΌ μ΄λ―Έμ§μ μμμ΄ λ¬΄μ§κ°μ²λΌ λ³νλ μ λλ©μ΄μ μ λ§λμΈμ.
# ννΈ
for h_shift in range(0, 180, 5):
h_channel = (original_h + h_shift) % 180
# ...
9. λ€μ λ¨κ³¶
04_Geometric_Transforms.mdμμ μ΄λ―Έμ§ ν¬κΈ° μ‘°μ , νμ , λ€μ§κΈ°, μ΄νμΈ/μκ·Ό λ³ν λ±μ νμ΅ν©λλ€!
λ€μμ λ°°μΈ λ΄μ©:
- cv2.resize()μ 보κ°λ²
- νμ , λ€μ§κΈ° ν¨μ
- μ΄νμΈ λ³ν (μ΄λ, νμ , μ€μΌμΌ)
- μκ·Ό λ³ν (λ¬Έμ μ€μΊ)
10. μ°Έκ³ μλ£¶
곡μ λ¬Έμ¶
κ΄λ ¨ νμ΅ μλ£¶
| ν΄λ | κ΄λ ¨ λ΄μ© |
|---|---|
| 02_Image_Basics.md | μ΄λ―Έμ§ μ½κΈ°, ν½μ μ κ·Ό |
| 07_Thresholding.md | HSV κΈ°λ° μκ³μ²λ¦¬ |