Иногда возникает задача преобразовать картинку OpenCV из обычного формата в какой-нибудь сжатый формат (вроде jpeg) для последующей передачи в сокет или куда-нибудь ещё. Просто сохранять в файл и потом его считывать — явно не лучший вариант.
Здесь нам на выручку придёт функция cv::imencode().
С++:
bool cv::imencode (const String &ext, InputArray img, std::vector< uchar > &buf, const std::vector< int > ¶ms=std::vector< int >())
Python:
cv.imencode(ext, img[, params]) -> retval, buf
Кодирует изображение в буфер памяти.
Функция imencode сжимает изображение и сохраняет его в буфере памяти, размер которого изменяется в соответствии с результатом.
Параметры
ext — Расширение файла, определяющее выходной формат.
img — исходное изображение для преобразования.
buf — буфер для хранения результата.
params — параметры, зависящие от формата (см. cv::ImwriteFlags).
Таким образом, чтобы просто получить сжатую картинку формата jpeg достаточно выполнить:
# set encode param encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 90] # compress image into buffer result, imgencode = cv2.imencode(".jpg", img, encode_param)
На выходе — флаг успешности операции и буфер с результатом сжатия изображения.
Рассмотрим как можно использовать эту функцию для сжатия изображения и последующей кодировки в base64 (что-то подобное использует labelme для хранения картинок в json-файлах).
#!/usr/bin/env python3 import numpy as np import cv2 import base64 def get_base64_from_image(img): # return base64 data from compressed to JPEG image if img is None: return None # set encode param encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 90] # compress image into buffer result, imgencode = cv2.imencode(".jpg", img, encode_param) print(result, type(imgencode)) data = np.array(imgencode) print(data.shape, data.dtype) # base64 encode img_data = base64.b64encode(data) print(len(img_data), type(img_data)) res = img_data.decode("ascii") return res def main(): print("cv2 v.", cv2.__version__) filename = "0022.jpg" img = cv2.imread(filename) if img is None: print("Error read image:", filename) exit(0) print(img.shape, img.dtype) img_data = get_base64_from_image(img) print(len(img_data), type(img_data)) #print(img_data) if __name__ == "__main__": main()
Результат работы:
cv2 v. 4.5.5 (1080, 1920, 3) uint8 True <class 'numpy.ndarray'> (708049,) uint8 944068 <class 'bytes'> 944068 <class 'str'>
далее: OpenCV: imdecode() — функция декодирует изображение из буфера памяти
Ссылки
По теме