BASCORRO
LearningComputer Vision

Image Processing Basics

Fundamental image processing techniques - color spaces, filtering, morphological operations

Computer Vision Fundamentals
0 dari 11 halaman selesai
In Progress
Scroll sampai 80% untuk menandai halaman selesai.

Image Processing Basics

Sebelum melakukan deteksi objek, image perlu diproses terlebih dahulu. Bab ini membahas teknik-teknik dasar image processing menggunakan OpenCV.


Color Spaces

Color space menentukan bagaimana warna direpresentasikan. Pilihan color space akan mempengaruhi stabilitas deteksi objek, terutama saat pencahayaan berubah.

RGB (Red, Green, Blue)

Format default dari kebanyakan kamera. Setiap pixel terdiri dari 3 channel. Kekurangannya: perubahan cahaya langsung mempengaruhi nilai semua channel.

import cv2
import numpy as np

# Read image (OpenCV uses BGR by default)
image = cv2.imread('robot_field.jpg')

# Split channels
b, g, r = cv2.split(image)

# Access single pixel
pixel = image[100, 200]  # [B, G, R] values
print(f"Blue: {pixel[0]}, Green: {pixel[1]}, Red: {pixel[2]}")

HSV (Hue, Saturation, Value)

HSV memisahkan warna murni (Hue) dari kecerahan (Value), sehingga lebih stabil saat lighting berubah. Biasanya kita mencari range Hue yang sempit, lalu menyesuaikan Saturation dan Value agar objek tetap terdeteksi tanpa terlalu banyak noise.

Lebih baik untuk color-based detection karena memisahkan warna (Hue) dari intensitas (Value).

┌─────────────────────────────────────────────┐
│  H (Hue)        : 0-179 (warna)             │
│  S (Saturation) : 0-255 (kepekatan warna)   │
│  V (Value)      : 0-255 (kecerahan)         │
└─────────────────────────────────────────────┘
# Convert BGR to HSV
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)

# Common color ranges in HSV
colors = {
    'red_low':    ([0, 100, 100], [10, 255, 255]),
    'red_high':   ([170, 100, 100], [180, 255, 255]),
    'orange':     ([5, 100, 100], [15, 255, 255]),
    'yellow':     ([20, 100, 100], [35, 255, 255]),
    'green':      ([35, 50, 50], [85, 255, 255]),
    'blue':       ([100, 100, 100], [130, 255, 255]),
    'white':      ([0, 0, 200], [180, 30, 255]),
}

# Create mask for orange (ball)
lower = np.array([5, 100, 100])
upper = np.array([15, 255, 255])
mask = cv2.inRange(hsv, lower, upper)

Interactive HSV Tuner

Eksperimen dengan berbagai nilai HSV untuk menemukan range optimal:

🎨 Interactive HSV Tuner

Presets:
5-15
100-255
100-255
Low
High
Sample Pixels (matched: 2/200)1.0% matched
# Python/OpenCV code:
lower_hsv = np.array([5, 100, 100])
upper_hsv = np.array([15, 255, 255])
mask = cv2.inRange(hsv_image, lower_hsv, upper_hsv)

LAB Color Space

Perceptually uniform, bagus untuk color difference calculation.

# Convert to LAB
lab = cv2.cvtColor(image, cv2.COLOR_BGR2LAB)

# L: Lightness (0-255)
# A: Green-Red (-128 to 127, stored as 0-255)
# B: Blue-Yellow (-128 to 127, stored as 0-255)

YCrCb

Sering digunakan untuk skin detection dan video compression.

ycrcb = cv2.cvtColor(image, cv2.COLOR_BGR2YCrCb)

# Y: Luminance
# Cr: Red difference
# Cb: Blue difference

Color Space Comparison

Color SpaceBest ForProsCons
RGB/BGRDisplay, generalStandard formatLighting sensitive
HSVColor detectionSeparates color from intensityHue wraps around at red
LABColor matchingPerceptually uniformComplex conversion
YCrCbSkin detectionGood luminance separationLess intuitive

Image Filtering

Filtering membantu menekan noise dan membuat bentuk objek lebih jelas sebelum proses deteksi. Di RoboCup, filter sering dipakai untuk menstabilkan kontur bola dan garis lapangan.

Gaussian Blur

Menghaluskan image untuk mengurangi noise. Cocok untuk menghilangkan noise acak ringan.

# Gaussian blur
blurred = cv2.GaussianBlur(image, (5, 5), 0)

# Parameters:
# - ksize: Kernel size (must be odd, e.g., 3, 5, 7)
# - sigmaX: Standard deviation in X direction

Median Filter

Bagus untuk menghilangkan salt-and-pepper noise.

# Median blur
median = cv2.medianBlur(image, 5)

Bilateral Filter

Menghaluskan sambil mempertahankan edges.

# Bilateral filter
bilateral = cv2.bilateralFilter(image, 9, 75, 75)

# Parameters:
# - d: Diameter of pixel neighborhood
# - sigmaColor: Filter sigma in color space
# - sigmaSpace: Filter sigma in coordinate space

Interactive Filter Demo

Coba berbagai filter dan lihat efeknya secara real-time:

🖼️ Image Filter Demo

Filter:
Original
Original
# OpenCV equivalent:
result = image.copy()

Filter Comparison

Purpose: Membandingkan efek filter pada image noisy. Inputs: image noisy. Outputs: visual perbandingan hasil filter. Steps:

  1. Baca image noisy.
  2. Terapkan Gaussian, Median, dan Bilateral.
  3. Tampilkan hasil secara berdampingan. Pitfalls: ukuran kernel tidak konsisten membuat perbandingan bias. Validation: terlihat tradeoff antara smoothing dan edge preservation.
import matplotlib.pyplot as plt

# Load noisy image
noisy = cv2.imread('noisy_field.jpg')

# Apply filters
gaussian = cv2.GaussianBlur(noisy, (5, 5), 0)
median = cv2.medianBlur(noisy, 5)
bilateral = cv2.bilateralFilter(noisy, 9, 75, 75)

# Display comparison
fig, axes = plt.subplots(2, 2, figsize=(12, 12))
axes[0, 0].imshow(cv2.cvtColor(noisy, cv2.COLOR_BGR2RGB))
axes[0, 0].set_title('Original (Noisy)')
axes[0, 1].imshow(cv2.cvtColor(gaussian, cv2.COLOR_BGR2RGB))
axes[0, 1].set_title('Gaussian Blur')
axes[1, 0].imshow(cv2.cvtColor(median, cv2.COLOR_BGR2RGB))
axes[1, 0].set_title('Median Filter')
axes[1, 1].imshow(cv2.cvtColor(bilateral, cv2.COLOR_BGR2RGB))
axes[1, 1].set_title('Bilateral Filter')
plt.show()

Edge Detection

Edge detection menonjolkan batas objek. Ini penting untuk garis lapangan atau kontur bola, terutama saat warna tidak cukup kuat untuk segmentasi.

Canny Edge Detector

Algoritma paling populer untuk edge detection.

# Convert to grayscale
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# Apply Gaussian blur first
blurred = cv2.GaussianBlur(gray, (5, 5), 0)

# Canny edge detection
edges = cv2.Canny(blurred, threshold1=50, threshold2=150)

# Parameters:
# - threshold1: Lower threshold for hysteresis
# - threshold2: Upper threshold for hysteresis

Sobel Operator

Menghitung gradient dalam arah X atau Y.

# Sobel in X direction
sobelx = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=3)

# Sobel in Y direction
sobely = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=3)

# Magnitude
magnitude = np.sqrt(sobelx**2 + sobely**2)

Laplacian

Mendeteksi edges berdasarkan second derivative.

laplacian = cv2.Laplacian(gray, cv2.CV_64F)

Morphological Operations

Operasi berbasis shape untuk membersihkan binary masks. Ini sering dipakai setelah threshold/HSV mask supaya noise kecil hilang dan bentuk objek lebih solid.

Structuring Elements

Purpose: Membuat kernel dasar untuk operasi morphology. Inputs: ukuran kernel dan bentuk elemen. Outputs: kernel rect, ellipse, dan cross. Steps:

  1. Pilih ukuran kernel sesuai skala objek.
  2. Buat kernel dengan bentuk berbeda.
  3. Uji di mask untuk memilih yang paling stabil. Pitfalls: kernel terlalu besar menghapus detail objek kecil. Validation: mask tetap mempertahankan bentuk bola/garis.
# Create kernels
kernel_rect = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
kernel_ellipse = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
kernel_cross = cv2.getStructuringElement(cv2.MORPH_CROSS, (5, 5))

Erosion

Mengecilkan foreground, menghilangkan noise kecil.

eroded = cv2.erode(mask, kernel, iterations=1)

Dilation

Memperbesar foreground, mengisi lubang kecil.

dilated = cv2.dilate(mask, kernel, iterations=1)

Opening

Erosion diikuti dilation. Menghilangkan noise tanpa memperbesar.

opened = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)

Closing

Dilation diikuti erosion. Mengisi lubang kecil.

closed = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)

Combined Pipeline

Purpose: Menyatukan operasi morphology untuk membersihkan mask. Inputs: mask biner dan ukuran kernel. Outputs: mask bersih tanpa noise kecil dan lubang. Steps:

  1. Buat kernel ellipse.
  2. Jalankan opening untuk noise.
  3. Jalankan closing untuk menutup lubang. Pitfalls: kernel terlalu kecil membuat noise masih muncul. Validation: mask terlihat halus saat ditampilkan.
def clean_mask(mask, kernel_size=5):
    """Clean binary mask using morphological operations."""
    kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,
                                        (kernel_size, kernel_size))

    # Remove noise
    cleaned = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)

    # Fill holes
    cleaned = cv2.morphologyEx(cleaned, cv2.MORPH_CLOSE, kernel)

    return cleaned

Histogram Analysis

Histogram Calculation

Purpose: Melihat distribusi intensitas untuk menentukan threshold. Inputs: image grayscale. Outputs: histogram intensitas. Steps:

  1. Hitung histogram 256 bin.
  2. Plot untuk melihat puncak dominan. Pitfalls: histogram tanpa normalisasi bisa menyesatkan saat bandingkan image berbeda. Validation: puncak histogram sesuai dengan area dominan image.
# Calculate histogram
hist = cv2.calcHist([gray], [0], None, [256], [0, 256])

# Plot histogram
plt.plot(hist)
plt.xlabel('Pixel Value')
plt.ylabel('Frequency')
plt.title('Grayscale Histogram')
plt.show()

Histogram Equalization

Meningkatkan contrast dengan mendistribusikan pixel values secara merata.

# Standard histogram equalization
equalized = cv2.equalizeHist(gray)

# CLAHE (Contrast Limited Adaptive Histogram Equalization)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
clahe_result = clahe.apply(gray)

CLAHE lebih baik dari equalization standar karena menghindari over-amplification noise.


Thresholding

Simple Thresholding

Purpose: Membuat mask biner sederhana dari grayscale. Inputs: image grayscale dan nilai threshold. Outputs: mask biner atau variasinya. Steps:

  1. Pilih threshold awal.
  2. Terapkan threshold binary dan variasi lain.
  3. Evaluasi mask hasilnya. Pitfalls: threshold statis gagal saat lighting berubah. Validation: objek utama muncul jelas di mask.
# Binary threshold
_, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)

# Inverse binary
_, binary_inv = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV)

# Truncate
_, trunc = cv2.threshold(gray, 127, 255, cv2.THRESH_TRUNC)

Adaptive Thresholding

Lebih robust terhadap perubahan pencahayaan.

# Adaptive mean threshold
adaptive_mean = cv2.adaptiveThreshold(gray, 255,
                                       cv2.ADAPTIVE_THRESH_MEAN_C,
                                       cv2.THRESH_BINARY, 11, 2)

# Adaptive Gaussian threshold
adaptive_gauss = cv2.adaptiveThreshold(gray, 255,
                                        cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
                                        cv2.THRESH_BINARY, 11, 2)

Otsu's Method

Automatically finds optimal threshold.

# Otsu's thresholding
_, otsu = cv2.threshold(gray, 0, 255,
                         cv2.THRESH_BINARY + cv2.THRESH_OTSU)

Complete Processing Pipeline

Purpose: Contoh class pipeline lengkap untuk preprocessing hingga mask warna. Inputs: image BGR dan parameter HSV. Outputs: image preprocess, mask warna, dan edges jika dipakai. Steps:

  1. Resize dan blur untuk stabilitas.
  2. CLAHE untuk kontras.
  3. Buat mask HSV dan bersihkan.
  4. Deteksi edges jika dibutuhkan. Pitfalls: resize mengubah skala; sesuaikan parameter radius dan threshold. Validation: mask bola stabil dan edges konsisten di lapangan.
import cv2
import numpy as np

class ImageProcessor:
    """Complete image processing pipeline for RoboCup."""

    def __init__(self):
        self.clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
        self.kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))

    def preprocess(self, image):
        """Standard preprocessing pipeline."""
        # Resize for consistent processing
        resized = cv2.resize(image, (640, 480))

        # Denoise
        denoised = cv2.GaussianBlur(resized, (3, 3), 0)

        return denoised

    def enhance_contrast(self, image):
        """Enhance contrast using CLAHE."""
        lab = cv2.cvtColor(image, cv2.COLOR_BGR2LAB)
        l, a, b = cv2.split(lab)
        l = self.clahe.apply(l)
        enhanced = cv2.merge([l, a, b])
        return cv2.cvtColor(enhanced, cv2.COLOR_LAB2BGR)

    def create_color_mask(self, image, lower_hsv, upper_hsv):
        """Create binary mask for color range."""
        hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
        mask = cv2.inRange(hsv, lower_hsv, upper_hsv)

        # Clean mask
        mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, self.kernel)
        mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, self.kernel)

        return mask

    def detect_edges(self, image, low_thresh=50, high_thresh=150):
        """Detect edges using Canny."""
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
        blurred = cv2.GaussianBlur(gray, (5, 5), 0)
        edges = cv2.Canny(blurred, low_thresh, high_thresh)
        return edges

# Usage
processor = ImageProcessor()

cap = cv2.VideoCapture(0)
while True:
    ret, frame = cap.read()
    if not ret:
        break

    # Preprocess
    processed = processor.preprocess(frame)
    enhanced = processor.enhance_contrast(processed)

    # Create ball mask (orange)
    ball_mask = processor.create_color_mask(
        enhanced,
        np.array([5, 100, 100]),
        np.array([15, 255, 255])
    )

    # Detect edges (for line detection)
    edges = processor.detect_edges(enhanced)

    cv2.imshow('Enhanced', enhanced)
    cv2.imshow('Ball Mask', ball_mask)
    cv2.imshow('Edges', edges)

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

Performance Tips

OptimizationBenefitTrade-off
Resize before processing4-16x fasterLower resolution
Use ROI (Region of Interest)Process only relevant areaMay miss objects
Convert to grayscale early3x less dataLose color info
Use integer operationsFaster than floatLess precision

Resources

Documentation

Tutorials

Interactive Tools


Practice Exercises

  1. Color Space: Konversi image ke berbagai color space dan bandingkan
  2. Filtering: Bandingkan efek Gaussian, Median, dan Bilateral filter pada noisy image
  3. Morphology: Bersihkan binary mask menggunakan kombinasi opening dan closing
  4. HSV Tuning: Temukan HSV range optimal untuk deteksi bola oranye di berbagai kondisi cahaya

Next Steps

Setelah memahami image processing basics, lanjut ke:

On this page