- Perbedaan antara cara standar membagi dengan 255 dan cara alternatif membagi dengan 256 setelah bias 0,5 saat mengonversi warna bilangan bulat 8-bit ke floating-point
- Cara 255 memetakan bilangan bulat 0 ke 0.0 dan 255 ke 1.0, sehingga hitam dan putih mudah ditangani secara langsung, serta sesuai dengan cara GPU melakukan konversi UNORM-to-float
- Cara 256 menggunakan
(img + 0.5) / 256.0untuk menempatkan tiap nilai di tengah interval, sehingga penanganan batas lebih sederhana untuk pekerjaan seperti dithering, tetapi 0 tidak lagi menjadi 0.0 sehingga logika pemrosesan terikat pada input 8-bit - Pada cara 255, interval di kedua ujung hanya selebar setengah, sehingga jika bilangan acak seragam
[0, 1]dibulatkan kembali ke 8-bit, 0 dan 255 muncul setengah lebih sering dibanding nilai lain, tetapi konversi bolak-balik gambar nyata tetap bekerja tanpa kehilangan - Jika memproses gambar dari orang lain, jawaban yang benar adalah normalisasi dengan 255; cara 256 hanya layak dipertimbangkan jika Anda mengendalikan penyimpanan dan pemuatan sepenuhnya
Pengaturan masalah
- Dalam program yang menerima gambar, mengubahnya ke floating-point, memprosesnya, lalu menyimpannya kembali sebagai warna 8-bit, yang menjadi pokok bahasan adalah cara konversi integer ke floating-point
- Ada dua pendekatan
- Cara standar (dibagi 255):
pixels = img / 255.0→ proses →output = np.trunc(result * 255 + 0.5) - Cara alternatif (dibagi 256):
pixels = (img + 0.5) / 256.0→ proses →output = np.trunc(result * 256) - Pada kedua kasus, nilai dibatasi ke 0–255 sebelum konversi tipe akhir:
output.clip(0, 255).astype(np.uint8)
- Cara standar (dibagi 255):
- Cara standar memetakan integer 0 ke 0.0 dan 255 ke 1.0, sama seperti cara GPU mengonversi UNORM ke float
- Cara alternatif menambahkan bias 0,5 sehingga integer 0 dipetakan ke
0.5/256 = 0.001953125- Akibatnya, tanpa mengetahui konstanta ini, piksel hitam tidak bisa dideteksi
- Walaupun memakai perhitungan floating-point, logikanya tetap terikat pada input 8-bit
- Pada cara standar, hitam selalu bisa diasumsikan sebagai 0.0
Sanggahan terhadap 255.0
- Jika cara standar digambarkan pada garis bilangan, hasilnya terlihat agak aneh
-
Ada bin yang lebih kecil di kedua ujung
- Bin ujung pada rumus standar menonjol keluar dari rentang [0,1], sehingga bentuk rentangnya tampak “direnggangkan”
- Saat floating-point dikembalikan ke integer, lebar bin di kedua ujung hanya setengah dari bin lain
- Ini membuat algoritme menjadi “lebih sulit” menghasilkan nilai ekstrem
- Jika menghasilkan noise seragam [0,1] lalu membulatkannya dengan rumus standar, nilai 0 dan 255 hanya muncul setengah sesering integer lain
- Pada histogram satu juta bilangan acak seragam, bisa dilihat bahwa bin 0 dan 255 hanya setengah setinggi bin lain
- Namun sulit membayangkan situasi nyata di mana bias penghindaran nilai ekstrem ini benar-benar menjadi masalah
- Gambar asli tetap bisa dikonversi bolak-balik tanpa kehilangan (
uint8 → float → uint8) - Hasil yang sedikit melewati 0.0 atau 1.0 tetap dibulatkan ke bin yang benar sehingga distribusi output kembali seragam
- Contoh: jika selama pemrosesan warna dikurangi 0.005, pada cara standar hitam turun di bawah 0, sedangkan pada cara alternatif tetap positif, tetapi keduanya tetap menghasilkan integer 0 pada output akhir
- Gambar asli tetap bisa dikonversi bolak-balik tanpa kehilangan (
-
Ketidakakuratan
- Nilai floating-point pada cara standar tidak eksak, misalnya
128/255.0 ≈ 0.501961, sedangkan128/256.0 = 0.5 - Jarak antarnilai floating-point sedikit berubah karena galat pembulatan, tetapi galatnya sangat kecil sehingga bukan masalah praktis
- Floating-point 32-bit memiliki mantissa 23-bit, dan galatnya berada pada tingkat bit paling rendah, kurang dari
2⁻²³ - Galat relatif 0.00001% tidak berarti bahkan untuk pemrosesan gambar presisi tinggi; ketidakakuratan ini adalah masalah estetika, bukan teknis
- Floating-point 32-bit memiliki mantissa 23-bit, dan galatnya berada pada tingkat bit paling rendah, kurang dari
- Nilai floating-point pada cara standar tidak eksak, misalnya
-
Nilai yang tidak berada pada rentang integer
- Cara alternatif menempatkan tiap nilai floating-point tepat di tengah antara dua integer
- Karena nilai kuantisasi aslinya tidak diketahui, titik tengah dua integer berurutan menjadi kompromi yang baik sebagai estimasi
- Ada klaim bahwa ini memudahkan dithering (posting blog Andrew Kesler tahun 2015, "Converting Color Depth")
- Noise bisa ditambahkan tanpa mengkhawatirkan edge case
- Sebaliknya, nilai ekstrem yang canggung pada rumus standar memerlukan penanganan hati-hati agar distribusi noise tetap konsisten
- Cara alternatif menempatkan tiap nilai floating-point tepat di tengah antara dua integer
Dua jenis kuantisator
- Kedua pendekatan ini bisa dipandang sebagai dua jenis uniform scalar quantizer
- Menurut artikel Wikipedia tentang kuantisasi, kuantisator seragam untuk data input bertanda diklasifikasikan menjadi dua jenis
- mid-tread: memetakan 0 ke level rekonstruksi bernilai 0 (bagian pijakan tangga)
- mid-riser: memetakan 0 ke ambang klasifikasi bernilai 0 (bagian tegak tangga)
- Wikipedia mengutip makalah tahun 1977 sebagai sumber (Allen Gresho, "Quantization")
- Rumus kuantisator (L adalah jumlah level output, misalnya 256)
- Kuantisator tangga mid-tread: encoding
k = trunc(xL + 0.5), decodingyₖ = k/L - Kuantisator tangga mid-riser: encoding
k = trunc(xL), decodingyₖ = (k+0.5)/L
- Kuantisator tangga mid-tread: encoding
- Jika diterapkan di sini
- Rumus standar = mid-tread (L=255)
- Rumus alternatif = mid-riser (L=256)
- Cara standar adalah kombinasi penggunaan mid-tread untuk input tak bertanda dengan kode L=255, yang bukan pilihan optimal untuk input 8-bit
- Ini dipilih demi kemudahan pemrograman karena memetakan kedua ujung ke 0.0 dan 1.0
-
Galat kuantisasi lebih tinggi, tetapi sebenarnya tidak
- Jika sistemnya adalah mengenkode bilangan riil berdistribusi seragam x∈[0,1] ke integer 8-bit lalu merekonstruksinya kembali menjadi bilangan riil, maka rumus standar memang membuang bandwidth
- Rentang yang dapat direpresentasikan oleh cara standar adalah
[-0.5/255, 255.5/255], lebih lebar dari yang diperlukan untuk input [0,1], sehingga galat rekonstruksi meningkat - Menurut perhitungan pengguna StackOverflow Peter Mudrievskij, galat absolut rata-ratanya adalah
1/1020untuk pembagi 255 dan1/1024untuk pembagi 256, sehingga membagi dengan 256 secara teori sedikit lebih presisi
- Rentang yang dapat direpresentasikan oleh cara standar adalah
- Namun pada praktiknya, bukan itu yang sedang dilakukan
- Asumsinya adalah memuat gambar RGB 8-bit, memprosesnya, lalu menyimpannya kembali; saat penyimpanan, cara kuantisasi tidak bisa dikendalikan, dan informasi yang hilang akan lenyap permanen
- Jika gambar disimpan dengan dikalikan dan dibulatkan memakai rumus standar, memuatnya kembali dengan membagi 256 tidak bisa memulihkan presisi
- Klaim galat rekonstruksi yang lebih kecil hanya bermakna jika Anda mengendalikan baik penyimpanan maupun pemuatan
- Jika memuat gambar milik orang lain dengan rumus alternatif, justru akan menimbulkan lebih banyak galat
- Kemungkinan besar gambar tersebut dikuantisasi dengan rumus standar, sehingga mendekode dengan skala yang salah secara teori menjadi tidak akurat
- Dalam praktiknya, karena warna bukan besaran absolut, yang terjadi hanya pemrosesan dalam rentang yang sedikit lebih kecil dengan offset kecil
- Langkah encoding dan decoding dari kedua kuantisator ini tidak boleh dicampur; ini adalah bentuk kode rusak yang mudah sekali dibuat
- Jika sistemnya adalah mengenkode bilangan riil berdistribusi seragam x∈[0,1] ke integer 8-bit lalu merekonstruksinya kembali menjadi bilangan riil, maka rumus standar memang membuang bandwidth
Kesimpulan
- Jika Anda memproses gambar yang diberikan orang lain, maka nilai RGB harus dinormalisasi dengan 255
- Kekhawatiran tentang nilai floating-point yang tidak eksak atau galat rekonstruksi abstrak bukan alasan yang baik untuk memilih cara alternatif
- Jika Anda mengendalikan sepenuhnya penyimpanan dan pemuatan gambar, tidak perlu memetakan 0 ke 0, dan tidak masalah jika kode pemrosesan terikat pada rentang dinamis 8-bit, maka membagi dengan 256 bisa memberi sedikit tambahan presisi
- Namun perhatikan bahwa rekan kerja Anda mungkin memuat gambar dengan rumus standar dan merusak rencananya
Pandangan lain
- Tulisan Jonathan Blow tahun 2002 membahas kuantisator mid-riser dan mid-tread tanpa menyebut nama, dan menjadi sumber ide diagram
- Posting blog Andrew Kesler tahun 2015 membela rumus alternatif
- Namun objek pembandingnya adalah rumus standar tanpa pembulatan, sehingga sebagian besar analisisnya menjadi tidak berlaku
2 komentar
Opini Hacker News
Apa tepatnya arti nilai warna biasanya tidak terlalu penting pada 8 bit per komponen. Galat akibat perbedaan penyebut 255 atau 256 sangat kecil, dan untuk melihat bedanya orang harus punya kepekaan warna yang baik serta melihat layar dari jarak sangat dekat, sementara monitor atau layar ponsel pun biasanya tidak terkalibrasi dengan baik
Tetapi jika kita membuat sinyal VGA dengan mikrokontroler dan hanya punya 8 pin keluaran warna (merah 3, hijau 3, biru 2), ini bisa jadi cukup merepotkan. Dalam kasus ini, nilai warna adalah level tegangan 0V~0.7V yang harus dikirim ke monitor VGA itu sendiri
Kanal biru dipetakan sebagai 0→0V, 1→0.23V, 2→0.47V, 3→0.7V, sedangkan merah/hijau dipetakan sebagai 0→0V, 1→0.1V, …, 7→0.7V. Jika titik ujung dikecualikan, tegangan biru sama sekali tidak sejajar dengan tegangan merah/hijau, sehingga kita tidak bisa melihat abu-abu murni, dan warna terdekat pun akan sedikit bercampur nuansa biru atau kuning tergantung arah perbedaannya
Selain itu, hampir semua gradasi yang mencampurkan biru dengan kanal lain juga akan tampak meleset. Misalnya, warna-warna terdekat pada garis dari merah murni ke putih murni akan tampak sedikit oranye atau ungu
Kode untuk keluaran VGA warna 8 bit dengan framebuffer ganda 320x240 di Raspberry Pi Pico 2 ada di sini: https://github.com/moefh/pico-vga-8bit-demo
Dengan begitu, perbedaan antara nilai kecil dan besar menjadi jauh lebih menonjol: 2^2.2 = 4.595, 255^2.2 = 196,964.699
Jika berubah pada 30Hz, manusia tampaknya akan sulit membedakan antara sedikit kebiruan dan sedikit kekuningan
Argumen yang mendukung 255 bisa dilihat dari kasus ekstrem berupa gambar hitam-putih. Pada satu bit, 0 adalah hitam dan 1 adalah putih
Cukup jelas bahwa 0 harus dipetakan ke 0.0 dan 1 ke 1.0. Itu hitam-putih, bukan abu-abu terang (0.25) dan abu-abu gelap (0.75). Artinya, gambar hitam-putih dinormalisasi dengan 1, bukan 2
Untuk 2 bit, biasanya 0=hitam, 1=abu-abu terang, 2=abu-abu gelap, 3=putih, sehingga wajar dipetakan ke 0.0, 0.33, 0.66, 1.0. Hitam harus tetap hitam, putih harus tetap putih, dan jaraknya juga harus sama, jadi dinormalisasi dengan 3
Jika logika ini diteruskan sampai 8 bit, hasilnya adalah normalisasi dengan 255. Pada 8 bit pun, meskipun perbedaannya jadi sangat kecil, hitam tetap harus 0.0 dan putih tetap harus 1.0
Pendekatan lain, yaitu normalisasi 256 pada 8 bit, membuat rentang keluaran berubah sesuai jumlah bit. Pada 1 bit hasilnya jadi [0.25, 0.75], pada 2 bit jadi [0.125, 0.875], dan seterusnya. Biasanya yang diinginkan adalah jumlah nuansa bertambah seiring jumlah bit bertambah, bukan kontrasnya yang berubah
Ini benar-benar tulisan yang memancing pemikiran, dan secara pribadi membuat saya meninjau ulang asumsi yang saya pegang
Dari sudut pandang teknik elektro, saya sulit setuju dengan pemaparan tentang “dua jenis quantizer” dalam tulisan itu. Secara matematis mungkin ketat, tetapi itu bukan penjelasan yang berbasis pada sistem nyata
ADC pada dasarnya selalu memiliki ketidakpastian kuantisasi ±1/2 LSB. Karakteristik transfernya selalu berupa sampling mid-tread, setidaknya saya belum pernah melihat contoh tandingannya. Ini berlaku baik untuk ADC bipolar maupun unipolar
Kode terendah merepresentasikan tegangan negatif acuan dan kode tertinggi merepresentasikan tegangan positif acuan. Grafik karakteristik transfer menunjukkan bahwa, seperti yang diperlihatkan dalam tulisan, rentang tertinggi/terendah pada dasarnya memiliki lebar 1/2 LSB
Dalam sistem unipolar, tegangan tengah tidak bisa direpresentasikan secara tepat; dengan kata lain, masalah abu-abu memang muncul. Dalam sistem bipolar, 0V adalah nilai N/2 pada mid-tread, tetapi itu tidak berarti ada “256 interval”
Jadi saya akan tetap memakai (VREF+ - VREF-) * k / (2^N - 1). Artinya saya setuju dengan normalisasi 255. Pada akhirnya ini sama seperti kesalahan tiang pagar: nilainya ada N, tetapi intervalnya hanya N-1. Jika jumlah interval lebih sedikit daripada jumlah nilai, satu interval harus dibagi di antara dua nilai, sehingga titik ujung mendapat interval 1/2 LSB
Transisi dari 126 ke 127 terjadi pada titik yang berjarak 1.5 LSB dari ujung penuh skala positif. Selisih 1 LSB berarti perbedaan 1/128=0.00781V, bukan 2/255=0.00784V
Namun dalam praktiknya, jika yang penting adalah tegangan dan ketidakpastian, perbedaan seperti ini hampir selalu tidak berarti. Tegangan referensi punya bias dan ada juga galat linearitas. 1 LSB tidak persis cocok baik dengan 1/128 maupun 2/255, sehingga parameter kalibrasi tetap diperlukan
Ini mirip dengan perbedaan antara sampel berpusat pada node dan sampel berpusat pada sel dalam komputasi ilmiah, dilihat dalam satu dimensi. Kita harus memutuskan apakah nilainya berada di tengah interval (atau di tengah segitiga/tetrahedron) atau di batas interval (atau di titik sudut segitiga/tetrahedron)
Dalam komputasi ilmiah, memulai pemrosesan data tanpa tahu bagaimana nilai itu harus diinterpretasikan tidak masuk akal. Dalam pemrosesan sinyal audio juga begitu: jika kita hanya menerima stream bilangan bulat, kita harus tahu maksud representasi bilangan itu, misalnya apakah itu encoding mu-law atau linear, agar bisa menghitung kembali sinyal aslinya. Kita berharap metadata yang melekat pada nilainya memberikan jawaban itu
Namun pada nilai piksel 8 bit, jika format file tidak punya metadata yang memadai untuk menyampaikan maksud representasinya, kita akan terombang-ambing dan tidak ada jawaban yang benar. Seperti kata penulis, tidak adil menyalahkan orang yang memilih pendekatan yang memberi hasil lebih baik untuk kebutuhannya sendiri, tetapi kita tetap bisa mengingatkan bahwa bit tanpa konteks berarti maknanya sudah rusak
Kurang lebih seperti ini: Digital Number DN=0 dibiarkan sebagai nilai “NO_DATA”, dan saat DN berada dalam rentang [1; 1;215-1], nilai reflektansi L2A SR dihitung sebagai L2A_SRi = (L2A_DNi + BOA_ADD_OFFSETi) / QUANTIFICATION_VALUE
https://sentiwiki.copernicus.eu/web/s2-products
Ada kekeliruan dengan menganggap ada 256 tingkat dari 0 sampai 255. Sebenarnya ada 256 nilai yang bisa direpresentasikan dengan 8-bit, dan jarak dari 0 (hitam) ke 255 (putih murni) adalah 255 langkah
Jadi membagi dengan 255 bukanlah masalah. Tentu saja 128 bukan abu-abu setengah yang persis, dan nilai 8-bit terkuantisasi 0~255 hampir selalu berada di sRGB, bukan ruang persepsi linear
Kebingungan serupa juga muncul di API modern saat menangani posisi sampling. Ini karena posisinya dinyatakan sebagai koordinat, bukan pusat piksel
Secara aljabar, jawabannya jelas: f(x) -> [0, 255]
Jika f(n * 0) == n * f(0) tidak berlaku, hal aneh akan terjadi. Misalnya jika f(x) -> [0, 255], maka f(0) + f(0) + f(0) = 0 + 0 + 0 = 0 = f(0)
Sebaliknya, jika f(x) -> [0.5/8, 7.5/8], maka f(0) + f(0) + f(0) = 0.5/8 + 0.5/8 + 0.5/8 = 1.5/8 != f(0)
Jika memilih yang belakang, kita tidak bisa berharap perhitungan di sisi x dan perhitungan di sisi f(x) akan saling cocok. Artinya korespondensi aljabar rusak
Saya cenderung mendukung solusi +0.5. Pertama, saya tidak suka interval setengah ukuran di tepi, dan kedua, representasi berbasis 255 biasanya bukan HDR melainkan gambar SDR
Nilai RGB merepresentasikan luminans untuk suatu keadaan adaptasi, dan “0” pada adegan siang bukan berarti “luminans 0”. Itu hanya sekitar 0,001 kali titik paling terang, dan jumlah fotonnya masih jutaan, jauh lebih besar dari 0
Dalam satu pengertian, mata mengalami kontras sebagai skala yang bergeser, dan tidak ada 0 absolut di dalam sistem. Misalnya, sistem siaran secara historis memakai 16~235 untuk rentang luminans SDR. Saya melihat logika “0 harus ada” sebagai sesuatu yang menimbulkan bias, dan menurut saya dalam kebanyakan kasus 0 tidak diperlukan
Selain itu, cukup banyak workflow pemrosesan gambar dan compositing yang, benar atau salah, mengasumsikan bahwa 0 berarti 0. Karena itu, banyak yang menganggap pada 8-bit, 0u dipetakan ke 0.0f dan 255 ke 1.0f. Jika nilai 0 pada mask atau alpha menjadi sedikit lebih besar dari 0.0, akan muncul artefak ketika ada kode yang memakai ambang keras 0.0 untuk memask operasi lain. Sebaliknya, jika 255 pada alpha tidak lagi bernilai 1.0f, objek akan menjadi sangat sedikit transparan setelah premultiplication
Hal yang sama bisa terjadi ketika +0.5 membuat 254 menjadi 1.0f dalam masking
Intinya bukan apakah kita merepresentasikan 0 foton, melainkan apakah kita memaksimalkan informasi yang disimpan dalam 1 byte. Idealnya, kita tidak boleh mengurangi penggunaan nilai byte 0, dan juga tidak boleh menambahkan bias pada data yang seharusnya masuk ke bucket ke-0. Bahkan dalam ruang warna yang berjalan dari terang ke sangat terang, semua byte seharusnya merepresentasikan potongan rentang kecerahan dengan ukuran yang sama
Jika penggaris punya tanda sampai 12 inci, normalisasinya harus berdasarkan panjang L, bukan 13 yang merupakan jumlah titik pada penggaris
>> 8jauh lebih cepatTulisan ini menyenangkan untuk dibaca karena membahas topik yang sudah lama tidak saya pikirkan. Ini mengingatkan saya pada momen-momen di pengembangan game ketika logika game memakai matematika floating-point, tetapi pixel art harus digambar pada koordinat bilangan bulat
Di beberapa tempat saya memakai pendekatan yang mirip +0.5 agar hasilnya terlihat tidak terlalu aneh. Terutama saat ada kamera yang bergerak, dan kameranya juga harus dipotong
Tulisan Jonathan Blow dari 2002 yang ditautkan di bawah [1] juga menarik. Visualisasi pada tulisan pertama sangat membantu saat masuk lebih dalam
[1] https://web.archive.org/web/20240706043551/https://number-no...
Pendapat di Lobste.rs
Kalau terasa tidak intuitif, lihat kasus terdegenerasi 2-bit. Jika satu-satunya nilai integer yang mungkin adalah 0, 1, 2, 3, lalu kita hitung seluruh konversi integer→floating point, maka untuk menghindari perilaku aneh seperti hitam/putih yang bukan benar-benar hitam/putih atau jarak yang jelas tidak merata, hasilnya menjadi 0.0, 0.33..., 0.66..., 1.0
Karena itu, konversi baliknya bukan dengan mengalikan 4(2^2), melainkan mengalikan 3
Konversi balik membutuhkan kuantisasi (pembulatan), dan justru di situlah simetri pecah
Jika Anda membuat gradien bilangan real yang seragam pada rentang 0..=1 lalu mengkuantisasinya menjadi 0, 1, 2, 3, akan terlihat bahwa mengalikan 3 menghasilkan distribusi yang tidak merata.
round()setelah ×3 membuat 1 dan 2 terwakili berlebihan, sementaraflooratauceilsetelah ×3 membuat 0 atau 3 seperti titik singular sehingga gradien tampak hanya memakai 3 dari 4 warnaLogika
/3dan×3tampak baik untuk konversi bolak-balik angka yang tepat, tetapi nilai antara sangat dipengaruhi oleh pilihan pembulatan, dan itu menjadi penting begitu Anda mulai memproses dataProporsi integer hanya menjadi seragam jika Anda mengalikan dengan (4-ε) lalu floor, yang setara dengan ×4,
floor(), danclamp(). Ini terasa seperti kesalahan aneh selisih 1 atau ε, tetapi secara intuitif itulah solusi yang paling enak dilihatBagi saya jawabannya selalu “jelas” [0.0..255.0], tetapi tampaknya itu tidak sejelas itu bagi semua orang
Tulisan itu mengatakan bahwa rentang “ekstrem” hanya memiliki setengah kapasitas dibanding rentang lain, dan menurut saya framing ini juga kurang tepat
Jika tidak ada nilai di luar [0..1], maka yang terlihat seperti rentang sempit itu hanyalah artefak perenderan. Itu hanya dirender lebih sempit karena bucket-nya dipotong dengan pengetahuan bahwa tidak ada nilai di luar rentang
Sebaliknya, jika ada nilai di luar [0..1], maka rentang itu tak terbatas. Tulisan tersebut mengakui yang kedua, tetapi tidak mengakui yang pertama
Begitu yang pertama diakui, perilaku yang benar tampak jelas, tetapi fakta bahwa tulisan seperti ini bisa muncul juga berarti masalah ini secara objektif tidak benar-benar “jelas” :D
Jika 0..<1 pergi ke integer 0, dan 254>..255.0 pergi ke integer 255, maka 128 akan hilang. Mungkin yang diinginkan adalah 127.5..128.5 menjadi 128, tetapi lalu setengah rentang ini harus pergi ke mana?
Jika seluruhnya digeser sedikit demi menyesuaikan 128, maka 0..0.99609375 akan dipetakan ke integer 0
round()Karena cara itu terasa cukup alami bagi banyak orang, sepertinya ia menjadi standar karena kesederhanaannya
pngcrush. Atau maksudnya isi gambarnya ada yang salah?