5.18. Histogram dan Statistik

Selain operasi yang mengubah piksel citra, kelas Image memiliki sekumpulan metode yang mengukur piksel tersebut -- merangkum distribusi nilai piksel, mengembalikan kecerahan rata-rata dan median, menemukan cutoff optimal antara piksel gelap dan terang, melaporkan sebaran saluran warna. Pengukuran tersebut mendukung aplikasi dalam dua cara: sebagai masukan bagi kode yang memutuskan ambang batas apa yang digunakan, gain apa yang diatur, seperti apa profil tonal scene; dan sebagai sinyal diagnostik -- "apakah scene cukup terang?" -- yang dapat ditindaklanjuti oleh aplikasi tanpa harus membuat keputusan tentang piksel tertentu.

Titik awal untuk hampir setiap pengukuran adalah histogram.

5.18.1. Histogram

Histogram suatu citra adalah hitungan berapa banyak piksel yang memiliki setiap nilai kecerahan yang mungkin. Untuk citra skala abu-abu, itu adalah daftar hitungan yang diindeks berdasarkan nilai 0 hingga 255. Untuk citra warna, itu adalah tiga daftar seperti itu -- satu per saluran.

get_histogram() menghitung satu histogram:

h = img.get_histogram()

Objek yang dikembalikan adalah hasil histogram yang mengekspos daftar bin per saluran dan beberapa kueri tingkat tinggi padanya. Jumlah bin dinormalisasi sehingga totalnya adalah 1.0 -- histogram mendeskripsikan profil distribusi daripada jumlah piksel absolut, yang membuat pengukuran dapat dibandingkan di antara citra dengan ukuran berbeda.

Untuk citra skala abu-abu, histogram memiliki satu saluran bin, tersedia sebagai h.bins() (atau setara h[0]). Untuk citra RGB565, histogram dihitung dalam ruang warna LAB yang diperkenalkan pada halaman ambang batas biner, dengan tiga saluran bin tersedia sebagai h.l_bins(), h.a_bins(), h.b_bins() (atau h[0], h[1], h[2]). LAB adalah pilihan yang sama yang digunakan oleh metode ambang batas dan pelacakan; histogram sepakat dengan ambang batas tentang ruang warna mana yang diukur.

5.18.2. Bin dan jumlah bin

Histogram default memiliki satu bin per nilai piksel yang mungkin -- 256 bin untuk saluran 8-bit. Kadang-kadang resolusi tersebut lebih halus dari yang dibutuhkan aplikasi. Sebuah classifier yang hanya peduli dengan profil kasar distribusi mungkin lebih baik dilayani oleh jumlah bin yang lebih kecil -- 32 atau bahkan 8 bin -- yang berjalan lebih cepat dan menghasilkan hasil lebih bersih terhadap noise. Kata kunci bins (dan per saluran l_bins, a_bins, b_bins untuk warna) mengatur jumlahnya:

h = img.get_histogram(bins=32)

Pembatasan ROI dan ambang batas bekerja dengan cara yang sama seperti pada setiap metode pengukuran lainnya. Berikan roi untuk membatasi histogram ke persegi panjang piksel; berikan daftar thresholds untuk hanya menyertakan piksel yang cocok dengan rentang tersebut. Bentuk ambang batas adalah yang membuat "hitung histogram hanya piksel yang cocok" menjadi operasi satu panggilan -- pola umum ketika aplikasi ingin mengkarakterisasi tekstur wilayah yang sudah terdeteksi tanpa harus menelusuri piksel sendiri.

A grayscale histogram drawn as a row of bars across the brightness range 0 to 255. The distribution has two peaks -- a smaller dark peak and a larger bright peak -- separated by a clear valley. Three vertical lines are overlaid: the Otsu threshold in the valley, the mean shifted toward the larger bright peak, and the median further right where cumulative pixel count reaches one-half.

Histogram skala abu-abu dengan tiga pengukuran ringkasan yang ditumpangkan: ambang batas Otsu (cutoff yang paling baik memisahkan kluster gelap dan terang), rata-rata, dan median. Setiap pengukuran menyatakan sesuatu yang berbeda tentang distribusi yang sama.

5.18.3. Statistik

Histogram adalah deskripsi prevalensi setiap nilai; statistik adalah ringkasan numerik yang diturunkan darinya. Objek statistics yang dikembalikan oleh get_statistics() membawa kumpulan standar:

  • mean -- rata-rata aritmatika nilai piksel.

  • median -- nilai di bawah mana setengah piksel berada.

  • mode -- nilai tunggal yang paling umum.

  • stdev -- standar deviasi, ukuran sebaran di sekitar rata-rata.

  • min dan max -- nilai piksel paling terang dan paling gelap yang ada.

  • lq dan uq -- cutoff kuartil bawah dan atas.

Untuk citra RGB565, bentuk per saluran (l_mean, a_median, b_mode, dan seterusnya) menghasilkan pengukuran yang sama saluran per saluran.

Sebagian besar angka tersebut muncul dalam konteks tertentu. mean dan stdev bersama-sama memberikan estimasi noise: sebuah scene yang seharusnya seragam memiliki stdev kecil, sementara sensor yang berisik memberikan stdev lebih besar pada scene yang sama. min dan max memberikan kontras citra: semakin dekat nilainya, semakin datar scene; semakin jauh, semakin besar rentang dinamis yang dimiliki algoritma untuk digunakan. median adalah pusat yang kuat ketika distribusi memiliki outlier (beberapa piksel yang sangat terang tidak menarik median seperti menarik rata-rata). mode adalah nilai yang paling umum, berguna untuk menemukan tingkat latar belakang citra yang latar belakangnya mencakup sebagian besar piksel.

get_statistics() menjalankan proses histogram secara internal dan kemudian merangkumnya; memberikan argumen thresholds dan roi yang sama seperti histogram yang telah dihitung sebelumnya menghasilkan statistik untuk kumpulan piksel yang sama.

5.18.4. Persentil dan pencarian CDF

Objek histogram mengekspos metode get_percentile() yang mengubah pecahan menjadi nilai piksel -- nilai di bawah mana fraksi piksel yang diminta berada. h.get_percentile(0.5) adalah median; h.get_percentile(0.05) dan h.get_percentile(0.95) bersama-sama memberikan min/max yang kuat yang mengabaikan 5% bawah dan atas sebagai outlier.

Itulah bentuk yang digunakan aplikasi ketika ingin mengkarakterisasi rentang nilai piksel tanpa membiarkan segelintir piksel terang atau gelap yang tersesat memiringkan jawaban. Min/max yang kuat dari persentil ke-5 dan ke-95 juga merupakan masukan alami untuk proses contrast-stretching -- peta ulang per piksel yang dibahas dalam koreksi tonal.

5.18.5. Metode Otsu

Histogram menjawab pertanyaan lain yang layak disebutkan secara tersendiri: diberikan sebuah citra yang pikselnya terbagi menjadi kluster "gelap" dan "terang", apa cutoff di antara keduanya? Halaman ambang batas sudah menyebutkan mekanismenya melalui hasilnya -- ambang batas global tunggal yang dapat diberikan aplikasi ke binary() -- tetapi menunda penjelasan bagaimana caranya. Caranya adalah metode Otsu, dan itu berada pada histogram.

Intuisinya: sebuah citra dengan latar depan dan latar belakang yang jelas memiliki dua kluster dalam histogram kecerahannya, dengan lembah di antara keduanya. Tempat yang tepat untuk menentukan ambang batas adalah bagian bawah lembah -- nilai di mana dua kluster paling terpisah dengan baik. Metode Otsu mencari setiap cutoff yang mungkin dan memilih yang meminimalkan varians dalam kluster (yang sama dengan memaksimalkan varians antar kluster), dan hasilnya adalah pemisahan biner optimal untuk distribusi citra tertentu.

Objek histogram mengekspos Otsu melalui get_threshold:

h = img.get_histogram()
t = h.get_threshold()

Objek threshold yang dikembalikan memiliki atribut value (untuk skala abu-abu) atau l_value / a_value / b_value (untuk warna) yang membawa cutoff yang dipilih. Mengumpankan hasilnya langsung ke binary() menghasilkan ambang batas global yang menyesuaikan diri sendiri dengan cutoff yang dipilih oleh citra itu sendiri:

img.binary([(t.value, 255)])

Pola tersebut tidak memecahkan masalah pencahayaan tidak merata yang dipecahkan oleh ambang batas adaptif berbasis filter; yang dipecahkannya adalah pertanyaan "nilai apa yang harus saya gunakan sebagai cutoff?" ketika pendekatan ambang batas global sudah merupakan pendekatan yang tepat. Untuk scene yang perbedaan latar depan / latar belakangnya terdefinisi dengan baik, nilai yang dipilih Otsu biasanya dalam beberapa unit dari apa yang akan dipilih manusia secara visual.

5.18.6. Menghitung pada citra perbedaan

Detail yang berguna tentang get_histogram() dan get_statistics(): keduanya menerima kata kunci difference yang mengambil Image lain dan menghitung histogram (atau statistik) dari perbedaan per piksel antara sumber dan citra tersebut, tanpa mengalokasikan citra perbedaan terpisah. Itulah cara murah untuk bertanya "seberapa banyak scene telah berubah sejak bingkai referensi?" tanpa membayar untuk panggilan difference() eksplisit untuk menghasilkan citra yang satu-satunya tujuannya adalah untuk diukur. Untuk skrip deteksi gerakan yang berjalan terus-menerus, penghematannya signifikan.