Alasan bodoh mengapa aplikasi penglihatan mesin Anda yang licik tidak berfungsi: orientasi di EXIF

Saya menulis banyak tentang visi komputer dan proyek pembelajaran mesin, seperti sistem pengenalan objek dan proyek pengenalan wajah . Saya juga memiliki open source library pengenalan wajah Python yang entah bagaimana membuatnya menjadi top 10 perpustakaan pembelajaran mesin paling populer di Github . Semua ini telah mengarahkan pendatang baru ke Python dan visi mesin untuk mengajukan banyak pertanyaan kepada saya.



Dari pengalaman, ada satu masalah teknis khusus yang paling sering membingungkan orang. Tidak, ini bukan pertanyaan teoretis yang sulit atau masalah dengan GPU yang mahal. Faktanya adalah bahwa hampir semua orang memuat gambar ke dalam memori yang diputar, tanpa menyadarinya. Dan komputer tidak mendeteksi objek dengan sangat baik atau mengenali wajah dalam gambar yang diputar.

Bagaimana kamera digital secara otomatis memutar gambar


Ketika Anda mengambil gambar, kamera mendaftarkan posisi telepon, sehingga di program lain gambar akan ditampilkan dalam orientasi yang benar:



Tetapi kamera sebenarnya tidak memutar data piksel di dalam file. Karena sensor gambar dalam kamera digital dibaca baris demi baris sebagai aliran informasi piksel yang berkelanjutan, kamera lebih mudah untuk selalu menyimpan data piksel dalam urutan yang sama, terlepas dari posisi aktual ponsel.



Ini adalah masalah program untuk menonton - memutar gambar dengan benar sebelum menampilkannya di layar. Seiring dengan data gambar itu sendiri, kamera juga menyimpan metadata - pengaturan lensa, data lokasi dan, tentu saja, sudut rotasi kamera. Penampil harus menggunakan informasi ini untuk ditampilkan dengan benar.

Format metadata gambar yang paling umum disebut EXIF (kependekan dari Exchangeable Image File Format). Metadata EXIF ​​tertanam di setiap file jpeg. Anda tidak dapat melihatnya di layar, tetapi dibaca oleh program apa pun yang tahu ke mana harus mencari.

Berikut adalah metadata EXIF ​​di dalam gambar JPEG angsa kami dari alat exiftool :



Lihat elemen 'Orientasi'? Dia memberi tahu pemirsa bahwa sebelum ditampilkan di layar, gambar harus diputar 90 derajat searah jarum jam. Jika program lupa melakukan ini, gambar akan berada di sisinya!



Mengapa ini merusak begitu banyak aplikasi penglihatan mesin dengan Python?


Metadata EXIF ​​pada awalnya bukan bagian dari format JPEG. Mereka diperkenalkan jauh kemudian, meminjam ide dari format TIFF. Untuk kompatibilitas mundur, metadata ini bersifat opsional, dan beberapa program tidak perlu repot untuk menguraikannya.

Kebanyakan pustaka gambar Python, seperti numpy, scipy, TensorFlow, Keras, dll., Menganggap diri mereka alat ilmiah bagi orang - orang serius yang bekerja dengan kumpulan data bersama. Mereka tidak peduli dengan masalah tingkat konsumen , seperti rotasi gambar otomatis, meskipun ini diperlukan untuk hampir semua foto di dunia yang diambil dengan kamera modern.

Ini berarti bahwa ketika memproses gambar dengan hampir semua perpustakaan Python, Anda mendapatkan data gambar asli tanpa rotasi. Dan coba tebak apa yang terjadi ketika Anda mencoba mengunggah foto di sisi Anda atau terbalik dalam model deteksi wajah atau objek? Detektor tidak menyala karena Anda memberikan data yang buruk.

Anda mungkin berpikir bahwa masalah hanya muncul di program pemula dan siswa, tetapi tidak demikian! Bahkan versi demo API Visi andalan Google tidak menangani orientasi EXIF ​​dengan benar:


Demo Google Vision API tidak tahu cara memutar gambar berorientasi potret yang diambil dari ponsel standar

Meskipun Google Vision mengenali beberapa hewan di sisinya, ia menandai mereka dengan label umum “hewan”, karena model visi mesin jauh lebih sulit untuk mengenali angsa di sisinya daripada angsa vertikal. Inilah hasilnya, jika Anda memutar gambar dengan benar sebelum mengirimkannya ke model:



Dengan orientasi yang benar, Google mendeteksi burung dengan tanda angsa yang lebih spesifik dan indikator kepercayaan yang lebih tinggi. Jauh lebih baik!

Ini adalah masalah yang sangat jelas ketika Anda melihat dengan jelas bahwa gambar berada di sisinya , seperti dalam demo ini. Tapi di sinilah semuanya menjadi berbahaya - biasanya Anda tidak melihatnya! Semua program normal di komputer Anda akan menampilkan gambar dalam orientasi yang benar, dan bukan bagaimana sebenarnya disimpan di disk. Karena itu, ketika Anda mencoba melihat gambar untuk melihat mengapa model Anda tidak berfungsi, itu akan ditampilkan dengan benar, dan Anda tidak akan mengerti mengapa model itu tidak berfungsi!


Finder di Mac selalu menampilkan foto yang diputar dengan benar dari EXIF. Tidak ada cara untuk melihat bahwa gambar sebenarnya disimpan di sisinya

Ini pasti mengarah ke banyak tiket terbuka di Github: orang mengeluh bahwa proyek open source rusak dan modelnya tidak terlalu akurat. Tapi masalahnya jauh lebih sederhana - mereka hanya memasukkan foto yang diputar atau terbalik ke pintu masuk!

Koreksi


Solusinya adalah bahwa setiap kali Anda memuat gambar ke program Python, Anda harus memeriksa metadata orientasi EXIF ​​dan memutar gambar jika perlu. Ini cukup mudah dilakukan, tetapi di internet sangat sulit menemukan contoh kode yang melakukannya dengan benar untuk semua orientasi.

Berikut adalah kode untuk memuat gambar apa saja ke dalam array numpy dengan orientasi yang benar:

import PIL.Image import PIL.ImageOps import numpy as np def exif_transpose(img): if not img: return img exif_orientation_tag = 274 # Check for EXIF data (only present on some files) if hasattr(img, "_getexif") and isinstance(img._getexif(), dict) and exif_orientation_tag in img._getexif(): exif_data = img._getexif() orientation = exif_data[exif_orientation_tag] # Handle EXIF Orientation if orientation == 1: # Normal image - nothing to do! pass elif orientation == 2: # Mirrored left to right img = img.transpose(PIL.Image.FLIP_LEFT_RIGHT) elif orientation == 3: # Rotated 180 degrees img = img.rotate(180) elif orientation == 4: # Mirrored top to bottom img = img.rotate(180).transpose(PIL.Image.FLIP_LEFT_RIGHT) elif orientation == 5: # Mirrored along top-left diagonal img = img.rotate(-90, expand=True).transpose(PIL.Image.FLIP_LEFT_RIGHT) elif orientation == 6: # Rotated 90 degrees img = img.rotate(-90, expand=True) elif orientation == 7: # Mirrored along top-right diagonal img = img.rotate(90, expand=True).transpose(PIL.Image.FLIP_LEFT_RIGHT) elif orientation == 8: # Rotated 270 degrees img = img.rotate(90, expand=True) return img def load_image_file(file, mode='RGB'): # Load the image with PIL img = PIL.Image.open(file) if hasattr(PIL.ImageOps, 'exif_transpose'): # Very recent versions of PIL can do exit transpose internally img = PIL.ImageOps.exif_transpose(img) else: # Otherwise, do the exif transpose ourselves img = exif_transpose(img) img = img.convert(mode) return np.array(img) 

Dari sini, Anda dapat mentransfer array data gambar ke pustaka visi mesin Python standar apa pun yang mengharapkan array input: misalnya, Keras atau TensorFlow.

Karena masalahnya ada di mana-mana, saya menerbitkan fungsi ini sebagai pustaka pip bernama image_to_numpy . Anda dapat menginstalnya sebagai berikut:

  pip3 instal image_to_numpy 

Ia bekerja dengan program Python apa pun, memperbaiki pemuatan gambar, misalnya:

 import matplotlib.pyplot as plt import image_to_numpy # Load your image file img = image_to_numpy.load_image_file("my_file.jpg") # Show it on the screen (or whatever you want to do) plt.imshow(img) plt.show() 

Lihat file readme untuk lebih jelasnya.

Selamat menikmati!

Source: https://habr.com/ru/post/id471112/


All Articles