cvDecodeImage / OpenCV / Recog.ru - Распознавание образов для программистов


cvDecodeImage

Предположим у вас есть загруженный в память каким-то образом графический файл, например, формата JPEG. И вам его надо открыть в OpenCV, однако документирована только функция cvLoadImage, которая позволяет загружать из файла. Можно конечно создать файл в памяти, но это не нужно, поскольку в OpenCV есть полезная недокументированная функция cvDecodeImage. На ряде Интернет-ресурсов, в том числе и на русских, уже есть достаточно давно описание использования этой функции, но я решил привести здесь пример использования этой функции, поскольку мне например не сразу стало понятно, как ее использовать и безопасно ли делать это, раз она недокументирована.

IplImage* cvDecodeImage( const CvMat* _buf, int iscolor );

Формат такой же, как у cvLoadImage, за исключением того, что передается не имя файла, а указатель на данные в памяти. Однако перед тем, как использовать данную функцию я решил посмотреть ее в исходниках.
/* decode image stored in the buffer */
CV_IMPL IplImage*
cvDecodeImage( const CvMat* _buf, int iscolor )
{
    CV_Assert( _buf && CV_IS_MAT_CONT(_buf->type) );
    cv::Mat buf(1, _buf->rows*_buf->cols*CV_ELEM_SIZE(_buf->type), CV_8U, _buf->data.ptr);
    return (IplImage*)cv::imdecode_(buf, iscolor, cv::LOAD_IMAGE );
}

Т.е. вызывается imdecode_. Смотрим её и сравниваем с imread_. Вроде бы все тоже самое за исключением начала:

CV_Assert(buf.data && buf.isContinuous());
    IplImage* image = 0;
    CvMat *matrix = 0;
    Mat temp, *data = &temp;
    char fnamebuf[L_tmpnam+1];
    const char* filename = 0;

    ImageDecoder decoder = findDecoder(buf);
    if( decoder.empty() )
        return 0;

    if( !decoder->setSource(buf) )
    {
        filename = tmpnam(fnamebuf);
        if(filename[0] == '\\')
            filename++;
        FILE* f = fopen( filename, "wb" );
        if( !f )
            return 0;
        size_t bufSize = buf.cols*buf.rows*buf.elemSize();
        fwrite( &buf.data[0], 1, bufSize, f );
        fclose(f);
        decoder->setSource(filename);
    }
    if( !decoder->readHeader() )
    {
        if( filename )
            remove(filename);
        return 0;
    }


Сначала вызывается findDecoder, который просто сравнивает сигнатуры с поддерживаемыми графическими форматами, но потом есть странная вещь if( !decoder->setSource(buf) ). Если по каким то причинам setSource вернула false, то буфер записывается во временный файл, и вызываются функции как в imread_! Не очень хорошо, если бы такое условие сработало, когда мы, например, в реальном времени обрабатываем какую-то информацию. Да и бессмысленно оно, чем отличаются функции декодирования из файла или памяти – вроде бы ничем. Но надо посмотреть, а сработает ли это условие когда-нибудь. findDecoder() возвращает нам или готовый декодер, где m_buf_supported = true, или пустой, где m_buf_supported = false. После этого вызывается условие empty(), которое в случае если мы не можем возвратить найденный декодер сработает, и мы выйдем их функции. Но если мы прошли дальше, то значит m_buf_supported = true, в то время как decoder->setSource(buf) проверяет if( !m_buf_supported ) return false; По этому на мой взгляд это тестовая вещь, которую забыли или не захотели убрать, но в которую программа никогда не попадет.
Что касается самого использования функции, то оно простое:

CvMat Mat=cvMat(1, size, CV_8UC1, buffer);
IplImage* Image = cvDecodeImage(&Mat); 

где size – размер буфера, а buffer — char* указатель на память с загруженным в неё файлом.
  • 0
  • 03 марта 2012, 09:38
  • vidikon

Комментарии (0)

RSS свернуть / развернуть

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.