Files
UTS-Pengolahan-Citra-Digita…/Problem 3/buat_gambar_koin.py
T
MelvynFaith 003b2c544c Jawaban UTS Pengolahan Citra Digital Kelompok I
Soal 1: selisih Laplacian of Gaussian (sigma 0,1 dan 0,2).
Soal 2: memecah teks menjadi karakter individual dengan regionprops.
Soal 3: menghitung jumlah koin per ukuran dengan regionprops.
2026-10-22 23:43:56 +07:00

86 lines
3.3 KiB
Python

"""Membuat gambar uji koin_100.png dari koin.png.
Soal mengandaikan gambar berisi 100 koin berbagai ukuran yang tidak saling
bersentuhan di atas latar belakang seragam. koin.png hanya berisi satu koin,
jadi koin tersebut diperkecil ke beberapa ukuran lalu ditempel 100 kali pada
posisi acak di atas latar seragam. Setiap koin diputar acak dan seluruh gambar
diberi sedikit noise agar koin sejenis tidak identik piksel per piksel, seperti
pada foto asli. Jumlah koin per ukuran diketahui, sehingga hasil
pengolahan_citra.py dapat diperiksa.
Cara menjalankan:
python buat_gambar_koin.py
"""
import os
import cv2
import numpy as np
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
SOURCE_PATH = os.path.join(BASE_DIR, "koin.png")
OUTPUT_PATH = os.path.join(BASE_DIR, "koin_100.png")
CANVAS_SIZE = 3000
BACKGROUND_BGR = (40, 40, 40) # latar abu-abu gelap yang seragam
MIN_GAP = 10 # jarak minimum antar-tepi koin (piksel), agar tidak bersentuhan
# (diameter koin dalam piksel, jumlah koin); total 100 koin
COIN_SIZES = [(140, 30), (170, 27), (205, 25), (245, 18)]
NOISE_STD = 3.0 # simpangan baku noise Gaussian (tingkat keabuan)
SEED = 0
def load_coin() -> np.ndarray:
coin = cv2.imread(SOURCE_PATH, cv2.IMREAD_UNCHANGED)
if coin is None or coin.shape[2] != 4:
raise FileNotFoundError(f"{SOURCE_PATH} harus berupa PNG dengan kanal alpha.")
# Potong ke area koin saja (alpha > 0)
rows, cols = np.nonzero(coin[:, :, 3])
return coin[rows.min():rows.max() + 1, cols.min():cols.max() + 1]
def main() -> None:
rng = np.random.default_rng(SEED)
coin = load_coin()
canvas = np.full((CANVAS_SIZE, CANVAS_SIZE, 3), BACKGROUND_BGR, np.float64)
diameters = [d for d, n in COIN_SIZES for _ in range(n)]
rng.shuffle(diameters)
# Tempatkan koin besar lebih dulu agar mudah mendapat tempat
placed = [] # (baris pusat, kolom pusat, jari-jari)
for d in sorted(diameters, reverse=True):
r = d / 2
for _ in range(100000):
y, x = rng.uniform(r + MIN_GAP, CANVAS_SIZE - r - MIN_GAP, size=2)
if all(np.hypot(y - py, x - px) >= r + pr + MIN_GAP for py, px, pr in placed):
placed.append((y, x, r))
break
else:
raise RuntimeError("Tidak cukup ruang untuk menempatkan semua koin.")
for y, x, r in placed:
d = round(2 * r)
small = cv2.resize(coin, (d, d), interpolation=cv2.INTER_AREA)
# Putar koin dengan sudut acak; area di luar koin tetap transparan
rotation = cv2.getRotationMatrix2D(((d - 1) / 2, (d - 1) / 2), rng.uniform(0, 360), 1.0)
small = cv2.warpAffine(small, rotation, (d, d), flags=cv2.INTER_LINEAR,
borderMode=cv2.BORDER_CONSTANT, borderValue=(0, 0, 0, 0))
small = small.astype(np.float64)
top, left = round(y - r), round(x - r)
region = canvas[top:top + d, left:left + d]
# Alpha blending: tepi koin menyatu halus dengan latar
alpha = small[:, :, 3:4] / 255
region[:] = alpha * small[:, :, :3] + (1 - alpha) * region
canvas += rng.normal(0, NOISE_STD, canvas.shape)
cv2.imwrite(OUTPUT_PATH, np.clip(np.round(canvas), 0, 255).astype(np.uint8))
print(f"Gambar uji disimpan di: {OUTPUT_PATH}")
for d, n in COIN_SIZES:
print(f"Diameter {d} piksel: {n} koin")
if __name__ == "__main__":
main()