計算機視覺模型效果不佳,你可能是被相機的Exif信息坑了
曉查 發自 凹非寺
量子位 報道 | 公眾號 QbitAI
為何別人用得好好的人臉識別、目標檢測開源模型,到了初學者手中,效果卻慘不忍睹?其中原因可能很多,有時候這個原因很“愚蠢”。
最近一位Medium上的博主Adam Geitgey給初學者指出了一個極其簡單而又容易忽視的關鍵點:相機的Exif信息。
在開發和使用計算機視覺(CV)模型的過程中,由于NumPy、TensorFlow和電腦上的圖片查看器在處理Exif上存在著差異,讓這個問題變得十分隱秘。
Adam是一位知名的機器學習課程博主,他的博客內容非常實用,幾乎篇篇都能收獲上千贊,足見其受歡迎的程度。
他在最新的文章中指出了CV模型在處理Exif存在的缺失,以及補救方法,下面是他文章的主要內容。
Exif信息害死人
普通智能手機或者相機拍照時,如果手持方向發生變化,內部的重力感應器件會告訴設備,照片究竟哪個邊是向上的。
當我們在手機、相機或者電腦的Photoshop軟件上查看照片時,完全沒有問題,就像這樣:
然而眼見并非為實,實際圖像的像素數據不會旋轉。這是由于圖像傳感器是對連續的像素信息流進行逐行讀取,因此你無論縱向和橫向握持相機,圖像都是按照一個方向進行存儲。
那么拍照設備和電腦為什么就能按照正確的方向顯示圖片呢?這是因為照片里還保存著一組元數據,稱之為Exif,即可交換圖像文件格式(Exchangeable image file format)。
Exif中包含著照片的像素數、焦距、光圈等信息,其中還有一個方向(Orientation)的數據。
上圖中Orientation一項的參數是Rotate 90 CW,意思是圖像在顯示前需要順時針旋轉90度。如果圖片查看程序沒有執行此操作,你就只能擰著脖子看了。
Exif原先是用在TIFF圖像格式上,后來才加入到JPEG圖像格式中,而圖像數據集中的圖片大多是JPEG格式。
一些程序為了保持向后兼容性,不會去解析Exif數據。大多數用于處理圖像數據的Python庫(如NumPy、SciPy,TensorFlow,Keras等)就是這樣的。
這意味著當你使用這些工具導入圖像時,都將獲得原始的未旋轉圖像數據。如果把這些側躺著或上下顛倒的圖像輸入到CV模型中,會得到錯誤的檢測結果。
這個問題看起來很愚蠢,似乎初學者會犯這樣的低級錯誤。但事實并非如此!甚至連Google云上的視覺API Demo也無法正確處理Exif方向問題:
如果我們把圖像旋轉到正確的方向再上傳,檢測的結果與上圖相比將完全改變:
當我們在電腦上查看圖片時完全沒問題,但是一用到模型中就不正常。因此很難發現問題的所在。
這也導致一些開發者在Github上提問,抱怨他們正在使用的開源項目已損壞,或是模型不夠準確。但是實際上問題要簡單得多,只是圖片的方向錯了!
解決方法
解決以上問題的方法就是,在導入圖像時檢查它們的Exif數據,在必要時旋轉圖像。Adam已經寫好了一段代碼:
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)
加入以上代碼后,就可以正確地將圖像導入Keras或TensorFlow了。
如果覺得麻煩,Adam還把上面的代碼打包好了,在GitHub上這個項目叫做image_to_numpy。一行代碼就可以完成安裝:
pip3 install image_to_numpy
以后,你在自己的Python代碼中加入這樣幾句即可。
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()
傳送門
原文鏈接:
https://medium.com/@ageitgey/the-dumb-reason-your-fancy-computer-vision-app-isnt-working-exif-orientation-73166c7d39da
快速導入旋轉圖像的image_to_numpy:
https://github.com/ageitgey/image_to_numpy
- 腦機接口走向現實,11張PPT看懂中國腦機接口產業現狀|量子位智庫2021-08-10
- 張朝陽開課手推E=mc2,李永樂現場狂做筆記2022-03-11
- 阿里數學競賽可以報名了!獎金增加到400萬元,題目面向大眾公開征集2022-03-14
- 英偉達遭黑客最后通牒:今天必須開源GPU驅動,否則公布1TB機密數據2022-03-05



