Mode belajar: ketik kode secara manual. Pemilihan teks, copy/cut dan menu klik kanan dibatasi pada halaman ini; pembatasan antarmuka bukan jaminan anti-penyalinan mutlak.
1. Tujuan
Setelah mempelajari modul ini, mahasiswa mampu:
- Membaca citra dan menjelaskan hubungan antara tinggi, lebar, kanal, dan nilai piksel.
- Menerapkan resize, crop, rotate, flip, brightness, dan contrast.
- Menggunakan parameter transformasi secara tepat dan menjelaskan dampaknya terhadap informasi citra.
- Menyimpan minimal enam hasil transformasi dari satu citra menggunakan OpenCV.
Prasyarat: dasar Python, variabel, fungsi, instalasi paket, serta indexing array. Tidak diperlukan model machine learning untuk praktikum ini.
2. Materi Pembahasan — teori dan penerapan
Pelajari tujuan dan akibat setiap operasi terlebih dahulu. Contoh kasus berikut digunakan untuk memahami perubahan informasi sebelum menjalankan praktikum.
2.1 Citra digital, piksel dan koordinat
Citra digital adalah susunan piksel. Citra grayscale menyimpan intensitas pada satu kanal; citra warna yang digunakan dalam contoh memiliki tiga kanal. Nilai kanal citra uint8 berada pada 0–255. Operasi geometrik mengubah ukuran, area atau orientasi; operasi intensitas mengubah nilai piksel.
OpenCV memakai urutan warna BGR, sedangkan Matplotlib memakai RGB. img.shape berurutan (height, width, channels), indexing array [baris, kolom], dan ukuran output OpenCV (width, height). Koordinat crop harus berada di dalam citra.
Sebelum memilih operasi, tentukan masalahnya: objek terlalu besar → resize; area pengamatan terlalu luas → crop; orientasi miring → rotate; perlu pencerminan → flip; intensitas perlu disesuaikan → brightness/contrast. Satu operasi tidak menyelesaikan semua masalah.
| Operasi | Fungsi / teknik | Yang berubah |
|---|---|---|
| Resize | cv2.resize() | Ukuran citra dan sampling piksel. |
| Crop | img[y1:y2, x1:x2] | Area yang dipertahankan; informasi di luar ROI hilang. |
| Rotate | getRotationMatrix2D() + warpAffine() | Orientasi; area tepi bisa terpotong. |
| Flip | cv2.flip() | Pencerminan horizontal, vertikal, atau keduanya. |
| Brightness | Tambah offset β lalu clipping. | Intensitas tiap piksel bergeser. |
| Contrast | Kalikan intensitas dengan gain α. | Rentang intensitas berubah dan dapat mengalami saturasi. |
2.2 Resize — mengubah ukuran
Foto dokumentasi tanaman dibuat lebih kecil untuk galeri pengamatan agar dimensi seragam. Gunakan aspect ratio yang sama agar bentuk daun tidak tampak gepeng. Resize tidak sama dengan kompresi file dan tidak menciptakan kembali detail yang hilang.


Gunakan faktor skala yang sama pada kedua sumbu untuk mempertahankan aspect ratio. Dokumentasi OpenCV merekomendasikan INTER_AREA untuk memperkecil; INTER_LINEAR atau INTER_CUBIC dapat digunakan untuk memperbesar.
resized = cv2.resize(img, (max(1, w // 2), max(1, h // 2)),
interpolation=cv2.INTER_AREA)Menaikkan resolusi tidak otomatis memulihkan detail yang tidak ada pada citra asal. Selisih kecil aspect ratio dapat timbul karena pembulatan ukuran ke integer.
2.3 Crop — memilih region of interest
Dari foto satu tanaman, pilih area daun sebagai region of interest untuk pengamatan. Pastikan bagian daun yang relevan tidak terbuang. Crop membuang area di luar batas, bukan sekadar mengecilkan seluruh foto.


Crop bukan resize. Tentukan koordinat yang valid dengan 0 ≤ x1 < x2 ≤ w dan 0 ≤ y1 < y2 ≤ h; batas akhir slicing tidak disertakan.
x1, x2 = w // 4, max(w // 4 + 1, 3 * w // 4)
y1, y2 = h // 4, max(h // 4 + 1, 3 * h // 4)
cropped = img[y1:y2, x1:x2].copy().copy() menghasilkan array terpisah agar perubahan hasil crop tidak mengubah array asal melalui view.
2.4 Rotate — memutar citra
Foto tanaman yang orientasinya miring diputar agar arah pengamatan lebih sesuai. Pada dokumen, prinsip serupa dipakai untuk memperbaiki kemiringan baris tulisan; rotasi saja tidak memperbaiki distorsi perspektif.


center = ((w - 1) / 2.0, (h - 1) / 2.0)
M = cv2.getRotationMatrix2D(center, 30, 1.0)
rotated = cv2.warpAffine(img, M, (w, h),
borderMode=cv2.BORDER_CONSTANT,
borderValue=(0, 0, 0))Sudut positif pada contoh OpenCV berarti berlawanan arah jarum jam. Output di atas mempertahankan ukuran awal: sudut tepi bisa terpotong, dan area kosong diisi hitam. Menjaga seluruh objek membutuhkan perluasan kanvas serta penyesuaian translasi matriks.
2.5 Flip — mencerminkan citra
Membandingkan posisi objek dengan versi cerminnya atau membuat variasi orientasi foto objek. Jangan flip dokumen untuk pembacaan teks karena huruf akan tercermin; makna objek/label harus tetap valid.


horizontal = cv2.flip(img, 1)
vertical = cv2.flip(img, 0)
both = cv2.flip(img, -1)Kode 1 mencerminkan kiri–kanan, 0 atas–bawah, dan -1 keduanya. Pertimbangkan apakah transformasi masih masuk akal, misalnya tulisan akan menjadi terbalik.
2.6 Brightness dan 2.7 Contrast
Contoh brightness: foto daun kurang terang diberi offset positif agar intensitas meningkat. Contoh contrast: foto objek dengan intensitas yang berdekatan diuji dengan gain agar perbedaan intensitas berubah. Keduanya harus dievaluasi: area yang sudah tersaturasi tidak dapat dipulihkan hanya dengan menaikkan parameter.




Transformasi linear per kanal dinyatakan sebagai output = clip(α × input + β, 0, 255). α adalah gain, sedangkan β adalah offset. Untuk contoh terpisah, brightness memakai α = 1; contrast memakai β = 0.
bright = np.clip(img.astype(np.float32) + 35, 0, 255).astype(np.uint8)
contrast = np.clip(img.astype(np.float32) * 1.4, 0, 255).astype(np.uint8)β positif membuat citra lebih terang, β negatif lebih gelap. α > 1 memperbesar intensitas relatif terhadap nol; α antara 0 dan 1 mengecilkannya. Gain berbasis nol juga memengaruhi tingkat terang. Contrast berpusat pada nilai tertentu adalah formulasi berbeda.
Clipping dapat menghilangkan detail di area sangat terang atau gelap. convertScaleAbs() mengambil nilai absolut; untuk brightness negatif dengan clipping murni, kode NumPy di atas menghindari perubahan tanda menjadi positif.
Menyimpan hasil
ok = cv2.imwrite("hasil.png", bright)
if not ok:
raise OSError("Gagal menyimpan hasil.png")Pastikan direktori output tersedia. PNG dipilih untuk menghindari artefak kompresi lossy saat membandingkan transformasi.
2.8 Ilustrasi interaktif untuk memahami teori
Bandingkan satu operasi dengan citra asal. Demo pendamping ini menggunakan Canvas browser, bukan praktikum utama di Colab atau runtime OpenCV; interpolasi dapat berbeda dari Python. Gambar diproses lokal pada browser, tidak diunggah oleh halaman ini.
2.10 Video pendamping — transformasi geometrik OpenCV
OpenCV - Crop, Resize, Flip, Rotate, Translate (Affine Transformations) — DIY Engineers. Video berbahasa Inggris; fokuskan pengamatan pada crop, resize, flip dan rotate. Bagian translate merupakan pengayaan. Jika video membahas setup lokal, tetap ikuti praktikum Google Colab pada halaman ini.
Buka video di YouTube jika pemutar tidak tersedia
Pertanyaan setelah menonton
- Operasi mana yang membuang area citra dan mana yang hanya mengubah ukuran?
- Mengapa rotasi dengan kanvas tetap menghasilkan area kosong?
- Bagaimana menentukan apakah flip masih sesuai dengan makna objek?
2.9 Cek pemahaman dan referensi
Mengapa ukuran OpenCV memakai (width, height), tetapi shape memakai (height, width)?
Array disusun sebagai baris lalu kolom. Ukuran citra pada fungsi resize/warp dinyatakan sebagai lebar lalu tinggi. Kedua urutan harus dibedakan saat menulis kode.
Apa perbedaan crop dan resize?
Crop mempertahankan bagian tertentu dan menghilangkan area lain. Resize mengubah sampling dan ukuran citra; seluruh area dapat tetap direpresentasikan.
Apakah brightness dan contrast dapat menghilangkan detail?
Ya. Nilai di luar rentang disaturasi ke 0 atau 255. Banyak piksel dapat menjadi identik sehingga detail tidak dapat dipulihkan hanya dengan transformasi kebalikan.
Apakah enam transformasi selalu cocok untuk augmentasi dataset?
Tidak otomatis. Transformasi harus mempertahankan arti label untuk tugas yang diteliti; crop dapat membuang objek, dan flip dapat mengubah tulisan atau orientasi penting.
Referensi
3. Praktikum Google Colab — ketik manual
3.1 Persiapan Google Colab
Seluruh praktikum dan tugas dijalankan di Google Colab, bukan Python lokal. Cukup siapkan browser, akun Google, internet, dan satu gambar berizin. Pemrosesan terjadi pada runtime Colab; GPU tidak diperlukan untuk operasi dasar ini.
Langkah memulai
- Buka Google Colab, masuk ke akun Google sendiri, lalu buat notebook baru.
- Buat lima sel kode di Colab dan ketik ulang blok Sel 1–5 ke sel yang sesuai. Perhatikan indentasi, tanda kutip dan nama variabel. Tidak perlu mengunduh atau mengunggah notebook contoh.
- Beri nama notebook
NPM_Nama_Materi02dan simpan ke Google Drive milik sendiri. - Hubungkan runtime melalui tombol Connect/Hubungkan. Gunakan Python dengan CPU; nama menu dapat berbeda mengikuti bahasa antarmuka.
- Jalankan sel dari atas ke bawah dengan tombol ▶ atau
Shift + Enter. - Unggah tepat satu gambar melalui dialog pada sel upload. Gunakan foto sendiri atau gambar yang memiliki izin.
File upload dan variabel berada pada runtime sementara. Notebook yang disimpan tidak otomatis menyimpan seluruh file runtime. Unduh ZIP hasil sebelum sesi berakhir; jika runtime terputus, jalankan ulang sel dan upload gambar kembali. Jangan gunakan data sensitif tanpa izin karena gambar dikirim ke runtime Google Colab.
Library dan citra sebagai array
Sel pertama mengimpor OpenCV, NumPy dan Matplotlib serta mencetak versi. Jika import gagal karena library belum tersedia, jalankan sel perbaikan berikut, lalu ulangi import. Jangan menjalankan instalasi jika import sudah berhasil.
%pip install opencv-python-headless numpy matplotlibimg.shape memakai urutan (height, width, channels); indexing NumPy adalah [baris, kolom]. Ukuran output resize dan warpAffine memakai (width, height). OpenCV menggunakan BGR; tampilan Matplotlib dikonversi ke RGB.
Untuk citra uint8, nilai per kanal berada pada 0–255. Gunakan tipe lebih luas sebelum brightness/contrast, lalu np.clip(). Pada Colab, gunakan Matplotlib atau cv2_imshow dari patch Colab, bukan cv2.imshow().
3.2 Identitas dan langkah praktikum
# Tugas — Operasi Dasar Citra
Nama: [Nama lengkap mahasiswa]
NPM: [NPM mahasiswa]
Kelas: [Kelas, jika diperlukan]Semua kode tersedia langsung di halaman ini sebagai teks, bukan file notebook unduhan. Ketik kode secara manual di Colab agar memahami setiap langkah. Buat notebook baru di Colab, tambahkan lima sel kode, lalu ketik manual dan jalankan blok berikut berurutan: import → upload → parameter/transformasi → visualisasi → penyimpanan dan download.
- Ketik kode Sel 1 secara manual pada sel pertama Colab, lalu jalankan dengan
Shift + Enter. - Tambahkan sel kode berikutnya dengan tombol + Code atau pilihan setara. Ulangi untuk Sel 2–5.
- Sel 2 meminta upload satu gambar. Sel 3 mengatur parameter; Sel 4 menampilkan hasil; Sel 5 mengunduh ZIP.
- Untuk eksperimen baru, ubah parameter pada Sel 3 lalu jalankan ulang Sel 3, 4 dan 5. Sel 1–2 tidak perlu diulang selama runtime dan gambar masih tersedia.
Sel 1 — Import library
Jalankan sekali saat memulai runtime.
import cv2
import numpy as np
import matplotlib.pyplot as plt
from google.colab import files
from pathlib import Path
import json
import zipfile
print("OpenCV:", cv2.__version__)
print("NumPy:", np.__version__)Sel 2 — Upload satu gambar
Pilih tepat satu gambar melalui dialog upload.
# Upload satu gambar. Penggunaan data pribadi/sensitif mengikuti izin yang berlaku.
uploaded = files.upload()
if len(uploaded) != 1:
raise ValueError("Pilih tepat satu gambar, lalu jalankan ulang sel upload.")
filename, raw_bytes = next(iter(uploaded.items()))
img = cv2.imdecode(np.frombuffer(raw_bytes, dtype=np.uint8), cv2.IMREAD_COLOR)
if img is None:
raise ValueError("File tidak dapat dibaca sebagai gambar.")
h, w = img.shape[:2]
if min(h, w) < 2:
raise ValueError("Gunakan gambar minimal 2 x 2 piksel.")
print("Nama:", filename, "shape:", img.shape, "dtype:", img.dtype)Sel 3 — Parameter dan enam transformasi
Ubah parameter di awal blok ini, lalu jalankan kembali untuk eksperimen baru.
# Parameter: ubah nilainya dan jalankan sel ini kembali.
skala = 0.5
sudut = 30.0
crop_fraction = 0.5
flip_code = 1
beta = 35.0
alpha = 1.4
def enam_transformasi(img, skala, sudut, crop_fraction, flip_code, beta, alpha):
values = [skala, sudut, crop_fraction, beta, alpha]
if not all(np.isfinite(value) for value in values):
raise ValueError("Semua parameter harus berupa angka finite.")
if not 0.1 <= skala <= 2:
raise ValueError("Skala harus 0.1 sampai 2.")
if not -180 <= sudut <= 180:
raise ValueError("Sudut harus -180 sampai 180.")
if not 0 < crop_fraction <= 1:
raise ValueError("Crop fraction harus > 0 dan <= 1.")
if flip_code not in (-1, 0, 1):
raise ValueError("Flip harus -1, 0 atau 1.")
if not -255 <= beta <= 255 or not 0 < alpha <= 3:
raise ValueError("Beta: -255..255; alpha: >0 sampai 3.")
h, w = img.shape[:2]
cw, ch = max(1, int(w * crop_fraction)), max(1, int(h * crop_fraction))
x1, y1 = (w - cw) // 2, (h - ch) // 2
M = cv2.getRotationMatrix2D(((w - 1) / 2.0, (h - 1) / 2.0), sudut, 1.0)
pixels = img.astype(np.float32)
return {
"01_resize": cv2.resize(img, (max(1, round(w * skala)), max(1, round(h * skala))),
interpolation=cv2.INTER_AREA if skala < 1 else cv2.INTER_LINEAR),
"02_crop": img[y1:y1 + ch, x1:x1 + cw].copy(),
"03_rotate": cv2.warpAffine(img, M, (w, h), borderMode=cv2.BORDER_CONSTANT,
borderValue=(0, 0, 0)),
"04_flip": cv2.flip(img, flip_code),
"05_brightness": np.clip(pixels + beta, 0, 255).astype(np.uint8),
"06_contrast": np.clip(pixels * alpha, 0, 255).astype(np.uint8),
}
hasil = enam_transformasi(img, skala, sudut, crop_fraction, flip_code, beta, alpha)
print("Jumlah transformasi:", len(hasil))Sel 4 — Tampilkan perbandingan hasil
Jalankan setelah Sel 3 untuk melihat citra asal dan enam hasil.
# Tampilkan citra asal dan seluruh hasil; Matplotlib menggunakan RGB.
fig, axes = plt.subplots(2, 4, figsize=(16, 8))
panels = {"00_asli": img, **hasil}
for ax, (name, image) in zip(axes.flat, panels.items()):
ax.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
ax.set_title(f"{name}\n{image.shape[1]} x {image.shape[0]}")
ax.axis("off")
for ax in axes.flat[len(panels):]:
ax.axis("off")
plt.tight_layout()
plt.show()Sel 5 — Simpan dan unduh ZIP
Jalankan setelah Sel 4. ZIP berisi gambar asal, enam hasil dan parameter.
# Gunakan direktori baru setiap run; hasil eksperimen lain tidak tertimpa.
import tempfile
output_dir = Path(tempfile.mkdtemp(prefix="materi02_", dir="/content"))
for name, image in panels.items():
if not cv2.imwrite(str(output_dir / (name + ".png")), image):
raise OSError("Gagal menyimpan " + name)
params = {"skala": skala, "sudut": sudut, "crop_fraction": crop_fraction,
"flip_code": flip_code, "beta": beta, "alpha": alpha,
"input_filename": filename, "input_shape": list(img.shape),
"opencv_version": cv2.__version__, "numpy_version": np.__version__}
(output_dir / "parameter.json").write_text(json.dumps(params, indent=2), encoding="utf-8")
zip_path = output_dir.with_suffix(".zip")
with zipfile.ZipFile(zip_path, "w", compression=zipfile.ZIP_DEFLATED) as archive:
for path in sorted(output_dir.iterdir()):
archive.write(path, arcname=path.name)
print("ZIP siap:", zip_path.name)
files.download(str(zip_path))Setiap transformasi memakai citra asli, bukan hasil operasi sebelumnya. File 00_asli.png, enam hasil dan parameter.json dikemas dalam ZIP. Direktori baru dibuat untuk setiap run agar hasil tidak tertimpa.
Jika terjadi error
- NameError: jalankan sel sebelumnya; variabel hilang setelah reset runtime.
- Upload kosong atau lebih dari satu gambar: ulangi sel upload dan pilih tepat satu file.
- Gambar tidak terbaca: pilih file gambar valid, bukan dokumen yang hanya berganti ekstensi.
- Warna salah: pastikan BGR dikonversi ke RGB sebelum
plt.imshow(). - ZIP tidak terunduh: cek izin download browser dan ulangi sel akhir; alternatif klik kanan ZIP pada panel Files Colab lalu Download.
- Parameter ditolak: sesuaikan batas dalam fungsi; pertahankan pesan error sebagai bukti pengujian negatif.
4. Tugas — penerapan mandiri di Google Colab
Kumpulkan satu link Google Colab saja. Notebook harus memuat Nama dan NPM di bagian paling atas, kode, hasil yang terlihat dan analisis. Tidak perlu mengumpulkan file .ipynb, ZIP, PDF atau screenshot terpisah.
# Tugas — Operasi Dasar Citra
Nama: [Nama lengkap mahasiswa]
NPM: [NPM mahasiswa]
Kelas: [Kelas, jika diperlukan]Ketentuan pengerjaan
- Buat notebook sendiri di Google Colab. Tulis kode secara manual dari pemahaman contoh; jangan hanya mengganti nama pada pekerjaan orang lain.
- Gunakan satu gambar milik sendiri/berizin. Catat sumbernya di sel Markdown dan upload dengan
files.upload(). - Implementasikan enam operasi: resize, crop, rotate, flip, brightness dan contrast.
- Buat dua skenario dengan minimal tiga parameter berbeda. Tampilkan citra asal dan keenam hasil untuk setiap skenario di notebook; output skenario pertama harus tetap terlihat, tidak hilang karena selnya ditimpa.
- Tulis tabel parameter dan dimensi output pada sel Markdown. Bandingkan perubahan bentuk/area/orientasi, clipping dan informasi yang hilang.
- Uji minimal satu parameter tidak valid; dokumentasikan penanganannya. Pastikan kode akhir dapat dijalankan berurutan dengan konfigurasi valid.
- Penyimpanan/download ZIP boleh digunakan sebagai latihan atau cadangan pribadi, tetapi bukan berkas pengumpulan.
Cara mengumpulkan link
- Pastikan sel identitas Nama dan NPM berada di paling atas, sebelum kode atau gambar.
- Jalankan sel, pastikan seluruh hasil dan analisis tampil, lalu simpan perubahan notebook. Jika pengaturan notebook menghilangkan output saat disimpan, nonaktifkan pengaturan tersebut untuk versi pengumpulan.
- Klik Share/Bagikan. Berikan akses Viewer/Pelihat kepada dosen; jika diizinkan institusi, gunakan “Siapa saja yang memiliki link”. Tidak perlu memberi izin edit publik.
- Periksa link dari akun penerima atau jendela privat sesuai pengaturan akses. Jika kebijakan akun kampus membatasi berbagi publik, tambahkan akun dosen secara khusus.
- Kumpulkan satu URL notebook Google Colab pada media yang ditentukan dosen. Pastikan bukan link folder Drive dan bukan link runtime sementara.
Checklist sebelum dikumpulkan
- Nama lengkap dan NPM ada di bagian paling atas.
- Dua skenario, enam hasil per skenario dan citra asal terlihat di notebook.
- Parameter, analisis dan sumber gambar tercantum.
- Link dapat dibuka dosen dengan izin melihat, tanpa meminta izin edit.
| Aspek | Bobot | Indikator |
|---|---|---|
| Kebenaran transformasi | 40% | Enam operasi dan visualisasi sesuai. |
| Parameter dan validasi | 20% | Dua skenario, perubahan parameter dan pengujian negatif. |
| Kelengkapan notebook dan akses link | 15% | Sel berurutan, output tersimpan, satu link dapat dibuka dosen. |
| Analisis | 20% | Perbandingan serta penjelasan informasi yang hilang tepat. |
| Identitas dan dokumentasi | 5% | Nama dan NPM paling atas, sumber gambar dan Markdown jelas. |