Приключения продолжаются. На этот раз я обнаружил, что OpenCV игнорирует alpha-канал при загрузке изображений функцией
Небольшое гугление показывает, что это уже давно баян и что есть радикальное решение проблемы, состоящее в корректировке кода и перекомпиляции библиотеки. Но мы же не станем этого делать. Изобретём более некрасивый путь и спасём наши скриптёныши от страшного "mpplus_sand.png"!
Устанавливаем PyPNG, и в дальнейшем вместо
Всё очень просто. Для начала:
Дальше мы создаём обект
cvLoadImage, и никакие CV_LOAD_IMAGE_UNCHANGED не помогут. Достаточно взглянуть на исходный файл grfmt_png.cpp (версия библиотеки 2.2), и надежды испаряются. Вот, например, из этого файла текстово-разъяснительно и потом кодово-мнемонично:
/* observation: png_read_image() writes 400 bytes beyond
* end of data when reading a 400x118 color png
* "mpplus_sand.png". OpenCV crashes even with demo
* programs. Looking at the loaded image I'd say we get 4
* bytes per pixel instead of 3 bytes per pixel. Test
* indicate that it is a good idea to always ask for
* stripping alpha.. 18.11.2004 Axel Walthelm
*/
png_set_strip_alpha( png_ptr );Небольшое гугление показывает, что это уже давно баян и что есть радикальное решение проблемы, состоящее в корректировке кода и перекомпиляции библиотеки. Но мы же не станем этого делать. Изобретём более некрасивый путь и спасём наши скриптёныши от страшного "mpplus_sand.png"!
Устанавливаем PyPNG, и в дальнейшем вместо
cv.LoadImage загружаем данные изображений средствами этого пакета, конвертируя их в объекты IplImage. Всё очень просто. Для начала:
import png
Допустим, требуется загрузить файл, путь к которому в filepath.
pr = png.Reader(filepath)
Дальше предусмотрим две возможности: в случае если мы имеем дело не с PNG форматом, просто вызываем стандартную функцию.
try:
w, h, data, properties = pr.asRGBA8()
except png.FormatError:
return cv.LoadImage(filepath)
Здесь мы получим размеры картинки, поток данных и словарь с некоторыми её свойствами. Использование метода asRGBA8() вместо read() спасает от возни со всякими неприятностями вроде не 8-битного кодирования элементов данных. Дальше мы создаём обект
IplImage
nChannels = properties['planes']
img = cv.CreateImage((w, h), 8, nChannels)
и заполняем его прочитанными данными. PyPNG предоставляет несложный интерфейс для итерации по элементам изображения:
for row in pr.iterboxed(data):
for e in row:
.....
В этом фрагменте рассматриваются строки изображения в виде простой последовательности байт (именно байт в следствие вызова метода asRGBA8(), как описанно выше). Записать же значение пикселя в IplImage, можно обычной cv.Set2D(). Только необходимо помнить, конечно, что записывать надо кортежами по nChannels элементов и что загруженные данные имеют формат RGBA, а записывать надо в BGRA.
Комментариев нет:
Отправить комментарий