【问题标题】:Converting cv::Mat to SDL_Texture将 cv::Mat 转换为 SDL_Texture
【发布时间】:2014-05-07 07:30:21
【问题描述】:

我正在尝试使用 SDL 播放视频。为此,我使用 opencv 加载视频并获取帧。然后我只需要将那些我需要的帧转换为SDL_Texture*,然后我就可以在屏幕上绘制它们了。

这是我的问题,我将其转换为 SDL_Surface*,但随后转换为 SDL_Texture 失败,我不知道为什么。这是我的代码:

void Cutscene::play()
{
  this->onLoop();
  this->onRender();

  while(!frameMat.empty())
  {
    this->onLoop();
    this->onRender();
  }
}

void Cutscene::onLoop()
{
  video >> frameMat;

  convertCV_MatToSDL_Texture();
}

void Cutscene::onRender()
{
  Image::onDraw(GameEngine::getInstance()->getRenderer(), frameTexture);

}

void Cutscene::convertCV_MatToSDL_Texture()
{
  IplImage opencvimg2 = (IplImage)frameMat;
  IplImage* opencvimg = &opencvimg2;

  //Convert to SDL_Surface
  frameSurface = SDL_CreateRGBSurfaceFrom((void*)opencvimg->imageData,
                         opencvimg->width, opencvimg->height,
                         opencvimg->depth*opencvimg->nChannels,
                         opencvimg->widthStep,
                         0xff0000, 0x00ff00, 0x0000ff, 0);

  if(frameSurface == NULL)
  {
    SDL_Log("Couldn't convert Mat to Surface.");
    return;
  }

  //Convert to SDL_Texture
  frameTexture = SDL_CreateTextureFromSurface(
                    GameEngine::getInstance()->getRenderer(), frameSurface);
  if(frameTexture == NULL)
  {
    SDL_Log("Couldn't convert Mat(converted to surface) to Texture."); //<- ERROR!!
    return;
  }

  //cvReleaseImage(&opencvimg);
  //MEMORY LEAK?? opencvimg opencvimg2
}

我在项目的其他部分使用了这个函数SDL_CreateTextureFromSurface,它在那里工作。所以问题是:你知道我在代码中做的转换有什么问题吗?如果没有,有没有更好的方法来做我想做的事情?

【问题讨论】:

    标签: c++ opencv video sdl-2


    【解决方案1】:

    我让它工作了!我认为唯一的问题是我必须使用 &frameMat 而不是 frameMat。 如果有人可能感兴趣,这是我的代码:

    SDL_Texture* Cutscene::convertCV_MatToSDL_Texture(const cv::Mat &matImg)
    {
        IplImage opencvimg2 = (IplImage)matImg;
        IplImage* opencvimg = &opencvimg2;
    
         //Convert to SDL_Surface
        frameSurface = SDL_CreateRGBSurfaceFrom(
                             (void*)opencvimg->imageData,
                             opencvimg->width, opencvimg->height,
                             opencvimg->depth*opencvimg->nChannels,
                             opencvimg->widthStep,
                             0xff0000, 0x00ff00, 0x0000ff, 0);
    
        if(frameSurface == NULL)
        {
            SDL_Log("Couldn't convert Mat to Surface.");
            return NULL;
        }
    
        //Convert to SDL_Texture
        frameTexture = SDL_CreateTextureFromSurface(
                        GameEngine::getInstance()->getRenderer(), frameSurface);
        if(frameTexture == NULL)
        {
            SDL_Log("Couldn't convert Mat(converted to surface) to Texture.");
            return NULL;
        }
        else
        {
            SDL_Log("SUCCESS conversion");
            return frameTexture;
        }
    
        cvReleaseImage(&opencvimg);
    

    }

    【讨论】:

    • 我觉得这很有帮助!
    【解决方案2】:

    这是没有IplImage的另一种方式:

    cv::Mat m ...;
    // I'm using SDL_TEXTUREACCESS_STREAMING because it's for a video player, you should
    // pick whatever suits you most: https://wiki.libsdl.org/SDL_TextureAccess
    // remember to pick the right SDL_PIXELFORMAT_* !
    SDL_Texture* tex = SDL_CreateTexture(
            ren, SDL_PIXELFORMAT_BGR24, SDL_TEXTUREACCESS_STREAMING, m.cols,
            m.rows);
    SDL_UpdateTexture(tex, NULL, (void*)m.data, m.step1());
    
    // do stuff with texture
    SDL_RenderClear(...);
    SDL_RenderCopy(...);
    SDL_RenderPresent(...);
    // cleanup (only after you're done displaying. you can repeatedly call UpdateTexture without destroying it)
    SDL_DestroyTexture(tex)
    

    我更喜欢创建表面方法,因为您不需要释放表面并且它更灵活(例如,您可以轻松更新纹理,而不是创建/销毁)。我还要注意我无法结合这些方法:即使用SDL_CreateRGBSurfaceFrom 创建纹理,然后再更新它。这导致了灰色条纹和图像被弄乱了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-29
      • 2011-06-07
      • 2016-04-13
      • 2011-10-23
      • 1970-01-01
      • 1970-01-01
      • 2012-01-03
      • 1970-01-01
      相关资源
      最近更新 更多