Как вам маршал Python cv2.cv.LoadImage tostring данных в структуру C IplImage-> imageData

0

Корень этого вопроса: Каков побитовый формат свойства OpenCV IplImage-> imageData?

Справочная информация. Я использую ctypes Python, чтобы разрешить питоновский доступ к низкоуровневой библиотеке C, которая использует OpenCV. Я смог получить почти все функции, доступные из python, но я застрял на этом, который требует данных старой структуры OpenCV, известной как IplImage, в частности свойство imageData. Я не могу понять, как IplImage-> imageData организована по сравнению с типом типа python cv2.cv.LoadImage iplimage, который якобы имеет те же данные, что и структура C, но, похоже, он организован по-разному.

Так, например, у меня есть 4-пиксельное изображение размером 2x2 пикселя. Верхний левый пиксель на 100% краснеет. Верхний правый пиксель 100% ЗЕЛЕНЫЙ. Нижний левый пиксель 100% ГОЛУБОЙ, нижний правый пиксель 100% белый.

В python информация выглядит так:

import cv2

img = cv2.cv.LoadImage('rgbw.png')
pixels = []
for ch in img.tostring():
  pixels.append(ord(ch))
print pixels

[0, 0, 255, 0, 255, 0, 255, 0, 0, 255, 255, 255]

Что имеет смысл для меня: первые три значения [0, 0, 255] представляют B: 0, G: 0, R: 255, красный пиксель. Второй, зеленый, третий - нижний левый, синий, а последний нижний правый - белый.

Я помещаю это в библиотеку, и библиотека работает хорошо, но она не кажется "видя" что-либо в imageData (я получаю код возврата, который означает "я ничего не видел", когда ясно, что эти данные понятны, когда я передаю его в библиотека, использующая C api напрямую.

Поэтому, конечно, я подозреваю, что C IplImage-> imageData имеет данные, которые были организованы совершенно по-другому, поэтому я смотрю в отладчике и с удивлением вижу, что данные не только разные, но я не могу понять это: вот оно, начиная с cvLoadImage ("rgbw.png"), назначая его структуре IplImage с именем 'image'.

Breakpoint 1, main (argc=2, argv=0x7fffffffe418) at IplImageInfo.cpp:44
44          printf("imageData %s\n", image->imageData);
(gdb) x/16ub image->imageData
0x618c90:   0   0   255 0   255 0   0   0
0x618c98:   255 0   0   255 255 255 0   0
(gdb)

Поэтому, сравнивая его побайтно, добавляя нули для сравнения:

Python:

000 000 255 | 000 255 000 | 255 000 000 | 255 255 255

C: (печать первых 16 байтов, а не 12, что я и ожидал, см. Ниже)

000 000 255 | 000 255 000 | 000 000 255 | 000 000 255 | 255 255 000 | 000

Обратите внимание, что первые шесть байтов одинаковы для обоих. Но потом, что происходит? У нас есть еще два КРАСНЫХ пиксела, затем... Синий пиксель? Другое дело, этот файл имеет размер 12 байт (4 пикселя, по 3 байта каждый). Когда я распечатываю свойство image-> imageSize из C, я получаю 16, а не 12. Так что что-то гнилое, я его не понимаю. Очевидно, что что-то не так с моей моделью того, что в imageData. Вы можете это объяснить?

  • 0
    хм, устаревший API cv2.cv не появится в следующей версии opencv. может быть, вы просто научитесь жить с cv2 / numpy?
  • 0
    Библиотека, которую я использую, использует старую версию, и у меня нет источника для нее. Поэтому я должен заставить его работать таким образом сейчас. Несмотря на это, у объекта cv2 Mat есть та же проблема: свойство data аналогично IlpImage-> imageData.
Показать ещё 1 комментарий
Теги:
opencv
iplimage

1 ответ

1
Лучший ответ

В коде python, который я использовал, отсутствовала некоторая требуемая логика. Эта логика не применяется в интерфейсе Python, и в Python нет подсказки, как это работает в библиотеке C. В принципе, IplImage (и я считаю, что Mat тоже, C++, преемник старой структуры IplImage) выставляет строки пикселей в свойстве imageData, чтобы делиться на 4, добавляя это число пустых (0-значных) байтов. Итак, код, который у меня был:

import cv2

img = cv2.cv.LoadImage('rgbw.png')
pixels = []
for ch in img.tostring():
  pixels.append(ord(ch))
print pixels

[0, 0, 255, 0, 255, 0, 255, 0, 0, 255, 255, 255]

Отсутствовала эта логика. Я решил это следующим образом:

import cv2

img = cv2.cv.LoadImage('rgbw.png')
height = img.height
width = img.width
raw_data = img.tostring()

# iplImage->imageData requires rows to be padded with zero bytes at the end 
# so they be divisible by 4
pad_bytes_per_row = width % 4

# create the ctypes structure
ubyte_array_type = c_ubyte * (len(raw_data) + (height * pad_bytes_per_row))
ubyte_array = ubyte_array_type()
index = 0
for ch in raw_data:
    ubyte_array[index] = ord(ch)
    index += 1
    if 0 == index % width: # end of row
        pad_index = 0
        while pad_index < pad_bytes_per_row:
            ubyte_array[index] = 0
            pad_index += 1
            index += 1

Теперь ubyte_array заполняется правильной информацией из API python opencv. Обратите внимание, что это было бы одинаково, если вы использовали метод numpy_array.tostring() для данных и хотели использовать его для заполнения объекта Mat. Надеюсь, это поможет кому-то.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню