web-dev-qa-db-ja.com

glReadPixels()からOpenCV :: Matへのデータの変換

glReadPixels()のアニメーションからすべてのOpenGLフレームを取得し、データをOpenCV :: Matに変換したいと思います。 glReadPixels()は、左から右に、下から上の行でデータを取得することを知っています。一方、OpenCVはデータの保存方法が異なります。

C++でデータをglReadPixelsからOpenCV:Matに変換するのに役立つライブラリやチュートリアル/例を知っている人はいますか?

[〜#〜]要約[〜#〜]

 OpenGL frame      ----------------------->        CV::Mat

Data from left to right,                    Data from left to right,
bottom to top.                              top to bottom.
21
Jav_Rock

まず、データを直接読み込むための空の(または単一化された)_cv::Mat_を作成します。これは起動時に1回実行できますが、一方で、イメージのサイズとタイプがすでに一致している場合、_cv::Mat::create_はそれほどコストがかかりません。タイプはニーズによって異なります。通常、24ビットカラー画像の場合は_CV_8UC3_のようになります。

_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)の代わりにGL_RGB(A)(OpenGL 1.2で追加された)を使用する必要があることに注意する必要があります。 。 1つのコンポーネントの画像には、_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;
1
user1393469