使用 OpenCV 不存檔直接讀入 Flask 所傳進的圖片

在實做 flask 時,我透過 curl 指令取得了張圖片,但它的資料格式是 'werkzeug.datastructures.FileStorage',不能直接用 cv2.imread ,但我又不想跟範例程式碼一樣,先存出再讀回。所以找了其他的方法來實做。

先存出再讀回

一般常見的範例都會先存出再讀回,將像下面程式碼一樣。

1
2
3
4
5
data =request.files['file']
filename = secure_filename(file.filename) 
filepath = os.path.join("/tmp", filename);
file.save(filepath)
img = cv2.imread(filepath)

直接從記憶體中讀取

不過要先存出再讀回,我實在不是很喜歡,所以找到的 cv2.imdecode,根據解釋:

cv2.imdecode()
函數從指定的記憶體快取中讀取數據,並把數據解碼成圖像格式;主要用於從網路傳輸數據中恢復出圖像。


看到網路傳輸數據眼睛就亮起來了有沒有!當下就決定把 cv.imread 換成 cv2.imdecod,並搭配 numpyfromstring 使用字串來建立一個矩陣,完整程式碼如下:

1
2
3
filestr = request.files['file'].read()
npimg = numpy.fromstring(filestr, numpy.uint8)
img = cv2.imdecode(npimg, cv2.IMREAD_COLOR)

資料型態

用這方式讀進來的資料型態是 uint8,在我的應用中,我會接著喂進 TensorFlow 做 predict,結果會跳出:

TensorFlow TypeError
Value passed to parameter input has DataType uint8 not in list of allowed values: float16, float32


所以我又在最後加了行型態轉換:

1
2
3
4
filestr = request.files['file'].read()
npimg = numpy.fromstring(filestr, numpy.uint8)
img = cv2.imdecode(npimg, cv2.IMREAD_COLOR)
img = img.astype("float32")



關於 IO 錯誤描述
之前文句中出現 省下那兩次的 IO 的敘述有誤,感謝 Chi Gas 的指正。
在使用 imdecode()imencode() 也是進行了 IO ,所以用省下 IO 的描述並不正確。

參考資料

  1. -牧野- (2018-01-25)。OpenCV-Python cv2.imdecode()和cv2.imencode() 图片解码和编码 。檢自 牧野的博客-CSDN博客(2020-02-19)。
  2. flamelite (2017-12-28)。Reading image file (file storage object) using CV2 。檢自 Stack Overflow (2020-02-19)。
  3. tbicr (2013-11-16)。Read file data without saving it in Flask 。檢自 Stack Overflow (2020-02-19)。

更新紀錄

最後更新日期: 2020-08-19
  • 2020-08-19 更新 修正錯誤描述
  • 2020-02-19 發布