2012-06-13 2 views
4

Я нашел очень похожую тему: how to convert an opencv cv::Mat to qimage, но это не решает мою проблему.cv :: Mat to QImage conversion

У меня есть функция преобразования резюме :: Mat в QImage

QImage cvMatToQImg(cv::Mat& mat) 
{ 
    cv::Mat rgb; 
    if(mat.channels()==1) 
    { 
     cv::cvtColor(mat,rgb,CV_GRAY2BGR); 
     cv::cvtColor(rgb,rgb,CV_BGR2BGRA); 
     QImage temp = QImage((unsigned char*)(rgb.data), rgb.cols, 
           rgb.rows,QImage::Format_ARGB32); 

     QImage returnImage = temp.copy(); 
     return returnImage; 
} 

И это работает для моих, но я хочу, чтобы сделать его более эффективным. Во-первых: почему изменение 2 cvtColor функции с:

cv::cvtColor(mat,rgb,CV_GRAY2BGRA) 

терпит неудачу на

QImage returnImage = temp.copy() 

с Segfault.

Тогда как устранить копирование QImage. Когда я просто возвращаю временное изображение, я получаю segfault.

Любые другие оптимизации могут быть выполнены там? Это очень часто используемая функция, поэтому я хочу сделать ее как можно быстрее.

+0

Вы не указали формат изображения 'mat', это даже 24-битное изображение в оттенках серого? – cmannett85

+0

В основном я работаю с 8-битным оттенком серого. Но чем больше дел справляется, тем лучше. – krzych

+1

Нет необходимости копировать. QImage - общий указатель. Segfauld происходит не из-за копирования, а из-за неправильного выравнивания. Аналогичный конструктор QImage указывает дополнительно байты на строку - используйте это. P.S: найдено по googling: http://code.google.com/p/qt-opencv-multithreaded/source/browse/trunk/src/MatToQImage.cpp?r=75 –

ответ

4

Ваше решение проблемы неэффективно, в частности, оно менее эффективно, чем код, который я разместил по другому вопросу, на который вы ссылаетесь.

Ваша проблема в том, что вам нужно преобразовать из оттенков серого в цвет или RGBA. Как только вам понадобится этот разговор, естественно, нужна копия данных.

Мое решение выполняет преобразование между оттенками серого и цветом, а также между cv :: Mat и QImage в одно и то же время. Вот почему это самый эффективный способ получить.

В вашем решении вы сначала попытаетесь преобразовать, а затем хотите построить QImage вокруг данных OpenCV, чтобы сэкономить вторую копию. Но данные, на которые вы указываете, являются временными. Как только вы покидаете функцию, cv :: Mat free имеет связанную с ней память, и поэтому она недействительна и в QImage. Вы можете вручную увеличить контрольный счетчик cv :: Mat заранее, но после этого откроется дверь для утечки памяти.

В конце концов, вы пытаетесь решить грязное решение проблемы, которая будет решена чистым способом.

3

Это может быть проще всего свернуть собственное решение. Ниже приводится текущая реализация OpenCV для перехода от серого до формата RGBA:

template<typename _Tp> 
struct Gray2RGB 
{ 
    typedef _Tp channel_type; 

    Gray2RGB(int _dstcn) : dstcn(_dstcn) {} 
    void operator()(const _Tp* src, _Tp* dst, int n) const 
    { 
     if(dstcn == 3) 
      for(int i = 0; i < n; i++, dst += 3) 
      { 
       dst[0] = dst[1] = dst[2] = src[i]; 
      } 
     else 
     { 
      _Tp alpha = ColorChannel<_Tp>::max(); 
      for(int i = 0; i < n; i++, dst += 4) 
      { 
       dst[0] = dst[1] = dst[2] = src[i]; 
       dst[3] = alpha; 
      } 
     } 
    } 

    int dstcn; 
}; 

Вот где происходит фактическая cvtColor вызов:

case CV_GRAY2BGR: case CV_GRAY2BGRA: 
     if(dcn <= 0) dcn = 3; 
     CV_Assert(scn == 1 && (dcn == 3 || dcn == 4)); 
     _dst.create(sz, CV_MAKETYPE(depth, dcn)); 
     dst = _dst.getMat(); 

     if(depth == CV_8U) 
      CvtColorLoop(src, dst, Gray2RGB<uchar>(dcn)); 

Этот код содержится в color.cpp файл в imgproc библиотеке.

Как вы можете видеть, поскольку вы не устанавливаете параметр dstCn в своих вызовах cvtColor, по умолчанию он равен dcn = 3. Чтобы перейти с серого на BGRA, установите dstCn - 4. Поскольку порядок цветов по умолчанию для OpenCV - BGR, вам все равно нужно поменять цветные каналы, чтобы он выглядел правильно (если вы получили данные изображения из функции OpenCV). Таким образом, может быть целесообразно реализовать собственный конвертер, возможно, следуя приведенному выше примеру или используя ypnos ответ here.

Кроме того, взгляните на мой другой answer, содержащий вопрос о том, как интегрировать OpenCV с Qt.

1

Проблема в том, что и данные cv :: Mat и QImage не обязательно смежны. новые строки данных в OpenCV начинаться на границе 32-битный (не уверен QImage - Я думаю, что это зависит от системы), поэтому вы не можете скопировать Memeory блок, если ваши строки не случится быть точными кратными 4 байта

См How to output this 24 bit image in Qt

Смежные вопросы