Преобразование данных из glReadPixels () в OpenCV::Mat
Я хочу получить каждый кадр OpenGL из анимации с glReadPixels() и преобразовать данные в OpenCV:: Mat. Я знаю это glReadPixels() получает данные по строкам от Нижнего к верхнему, слева направо. С другой стороны, OpenCV хранит данные по-разному.
кто-нибудь знает любой библиотеки или любой учебник/пример, который помогает мне конвертировать данные из glReadPixels до OpenCV: Мат in C++?
резюме
OpenGL frame -----------------------> CV::Mat
Data from left to right, Data from left to right,
bottom to top. top to bottom.
2 ответов
Сначала мы создаем пустой (или unititialized) cv::Mat
для наших данных, котор нужно прочитать в сразу. Это можно сделать один раз при запуске, но с другой стороны cv::Mat::create
на самом деле не стоит много, когда изображение уже имеет соответствующий размер и тип. Тип зависит от ваших потребностей, обычно это что-то вроде CV_8UC3
для 24-битного цветного изображения.
cv::Mat img(height, width, CV_8UC3);
или
img.create(height, width, CV_8UC3);
тогда вы должны учитывать cv::Mat
не обязательно хранить рядом строк изображения. Там может быть небольшое значение заполнения в конце каждой строки, чтобы выровнять строки 4 байта (или 8?). Поэтому вам нужно возиться с режимами хранения пикселей:
//use fast 4-byte alignment (default anyway) if possible
glPixelStorei(GL_PACK_ALIGNMENT, (img.step & 3) ? 1 : 4);
//set length of one complete row in destination data (doesn't need to equal img.cols)
glPixelStorei(GL_PACK_ROW_LENGTH, img.step/img.elemSize());
далее, тип матрицы влияет на формат и параметры типа glReadPixels
. Если вы хотите цветные изображения, вы должны иметь в виду, что OpenCV обычно хранит значения цвета в порядке BGR, поэтому вам нужно использовать GL_BGR(A)
(которые были добавлены с OpenGL 1.2) вместо GL_RGB(A)
. Для одного компонента изображения используйте либо GL_LUMINANCE
(который суммирует отдельные цветовые компоненты) или GL_RED
, GL_GREEN
, ... (для получения отдельного компонента). Так для наших CV_8UC3
изображение последний вызов, чтобы прочитать его непосредственно в cv::Mat
будет:
glReadPixels(0, 0, img.cols, img.rows, GL_BGR, GL_UNSIGNED_BYTE, img.data);
наконец, OpenCV хранит изображения сверху вниз. Поэтому вам может потребоваться либо перевернуть их после их получения, либо сделать их перевернутыми в OpenGL (это можно сделать, отрегулировав матрицу проекции, но в этом случае следите за ориентацией треугольника). Чтобы перевернуть cv::Mat
вертикально, вы можете использовать cv::flip
:
cv::flip(img, flipped, 0);
так что имейте в виду OpenCV:
- сохраняет изображения сверху вниз, слева направо
- сохраняет цветные изображения в порядке BGR
- может не хранить строки изображений плотно упакованы
unsigned char* getPixelData( int x1, int y1, int x2, int y2 )
{
int y_low, y_hi;
int x_low, x_hi;
if ( y1 < y2 )
{
y_low = y1;
y_hi = y2;
}
else
{
y_low = y2;
y_hi = y1;
}
if ( x1 < x2 )
{
x_low = x1;
x_hi = x2;
}
else
{
x_low = x2;
x_hi = x1;
}
while ( glGetError() != GL_NO_ERROR )
{
;
}
glReadBuffer( GL_BACK_LEFT );
glDisable( GL_TEXTURE_2D );
glPixelStorei( GL_PACK_ALIGNMENT, 1 );
unsigned char *data = new unsigned char[ ( x_hi - x_low + 1 ) * ( y_hi - y_low + 1 ) * 3 ];
glReadPixels( x_low, y_low, x_hi-x_low+1, y_hi-y_low+1, GL_RGB, GL_UNSIGNED_BYTE, data );
if ( glGetError() != GL_NO_ERROR )
{
delete[] data;
return 0;
}
else
{
return data;
}
}
использование:
CvSize size = cvSize( 320, 240 );
unsigned char *pixel_buf = getPixelData( 0, 0, size.width - 1, size.height - 1 );
if ( pixel_buf == 0 )
return 0;
IplImage *result = cvCreateImage( size, IPL_DEPTH_8U, 3 );
memcpy( result->imageData, pixel_buf, size.width * size.height * 3 );
delete[] pixel_buf;