【转】SiftGPU不自动释放GL context的bug及其修正方法

转自:http://blog.sina.com.cn/s/blog_4298002e01019gle.html

很早以前就在使用wuchangchang开发的SiftGPU库,以前就经常出现运行完Sift后程序崩溃的问题,但是一直没有空闲去跟踪这个问题的所在。直到昨天才修正了这个bug。

    仔细阅读SiftGPU的代码可以发现,SiftGPU的CreateContextGL()函数调用GlobalUtil类的静态方法GlobalUtil::CreateWindowEZ()创建了一个静态的LiteWindow对象实例,供GLSL程序使用。代码在GlobalUtil.cpp内,如下:

int GlobalUtil::CreateWindowEZ()
{
    static LiteWindow window;
    return CreateWindowEZ(&window);
}

    注意,这个LiteWindow对象不是以指针形式声明的,而且整个程序再没有销毁过该LiteWindow对象,即便SiftGPU被销毁之后,这个对象仍然存在,直到包含SiftGPU的对象被析构或者包含SiftGPU的函数退出——此时LiteWindow对象依然存在,但是其GL上下文已经丢失,相关指针变为野指针。

    这种机制为后面的程序带来了隐藏的bug:如果我们在主程序结束前都不析构包含SiftGPU的对象,等到主程序结束时再由系统自动销毁,则程序不会出现任何问题。但是如果我们一运行完SiftGPU的功能就把包含SiftGPU的对象析构了,然后再等主程序结束,就会出现LiteWindow对象无法被析构的错误——因为该对象已经在析构包含SiftGPU的对象时产生了野指针,系统再对其回收就会出现问题。

    其实wuchangchang的这个代码本意是把GlobalUtil类设计成一个单体(singleton),只创建一个LiteWindow实例。然而由于该对象不是以指针形式声明的,所以导致无法主动销毁。为了修正这个bug,我们需要对GlobalUtil的代码进行一些修改,将其变成一个完全的单体模式。修改方法如下:

    1)打开GlobalUtil.h,删除static int  CreateWindowEZ(LiteWindow* window)方法,并把static int CreateWindowEZ()方法改为:

 static LiteWindow*  CreateWindowEZ();

添加一个销毁实例的方法:

 static void DestroyWindowEZ();

添加一个保护的静态成员变量:

protected:
 static LiteWindow *m_pWindow;

    2)打开GlobalUtil.cpp,删除int GlobalUtil::CreateWindowEZ(LiteWindow* window)和int GlobalUtil::CreateWindowEZ()的代码,添加如下代码:

LiteWindow *GlobalUtil::m_pWindow = NULL;

 

LiteWindow*  GlobalUtil::CreateWindowEZ()
{
 if (m_pWindow == NULL)
 {
  m_pWindow = new LiteWindow;
 }
 
 if (!m_pWindow->IsValid())
 {
  m_pWindow->Create(_WindowInitX, _WindowInitY, _WindowDisplay);
 }
 
 if(m_pWindow->IsValid())
 {
  m_pWindow->MakeCurrent();
 }
 else
 {
  std::cerr << "Unable to create OpenGL Context!\n";
  std::cerr << "For nVidia cards, you can try change to CUDA mode in this case\n";
 }

 return m_pWindow;
}

 

void GlobalUtil::DestroyWindowEZ()
{
 if (m_pWindow != NULL)
 {
  delete m_pWindow;
  m_pWindow = NULL;
 }
}

    3)在SiftGPU.h中的SiftGPU类和SiftMatchGPU类分别添加:

SIFTGPU_EXPORT virtual void DestroyContextGL();

    4)在SiftGPU.cpp中添加:

void SiftGPU::DestroyContextGL()
{
 return GlobalUtil::DestroyWindowEZ();
}

    在SiftMatchGPU.cpp中添加:

void SiftMatchGPU::DestroyContextGL()
{
 GlobalUtil::DestroyWindowEZ();
}

    5)修改SiftGPU.h中的SIFTGPU_EXPORT int CreateLiteWindow(LiteWindow* window)为:

SIFTGPU_EXPORT LiteWindow*  CreateLiteWindow();

    6)修改GlobalUtil.cpp中的int CreateLiteWindow(LiteWindow* window)为:

LiteWindow*  CreateLiteWindow()
{
 return GlobalUtil::CreateWindowEZ();
}

    7)在自己的代码中使用完Sift的地方,手动调用析构GL context的函数,如下:

假设变量:SiftGPU *pSift;

pSift->DestroyContextGL();

或者:SiftMatchGPU *pSiftMatch;

pSiftMatch->DestroyContextGL();

    具体调用哪句,视最后使用哪个对象而定。

 

    自此,我们的程序就不会出现重复释放LietWindow的错误了。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SIFTGPU是一个用于实现尺度不变特征变换(Scale-Invariant Feature Transform,SIFT)的GPU加速库。下面是一些基本的使用教程: 1. 安装SIFTGPU:你可以从 https://github.com/pitzer/SIFTGPU 下载SIFTGPU的源代码。根据该项目中的安装说明,编译并安装SIFTGPU库。 2. 导入SIFTGPU库:在你的项目中,导入SIFTGPU库的头文件,并链接SIFTGPU的库文件。 3. 初始化SIFTGPU:在你的代码中,使用以下代码初始化SIFTGPU: ```cpp #include <GL/glew.h> #include <GL/glut.h> #include <SiftGPU.h> SiftGPU sift; int width = 640, height = 480; int main(int argc, char *argv[]) { // 初始化OpenGL上下文 glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH); glutInitWindowSize(width, height); glutCreateWindow("SIFTGPU"); // 初始化SIFTGPU if (sift.CreateContextGL() != SiftGPU::SIFTGPU_FULL_SUPPORTED) { printf("SIFTGPU is not supported!\n"); return 1; } // 设置SIFTGPU参数 sift.SetVerbose(true); sift.SetOuputFormat(SiftGPU::SIFTGPU_SIFT); sift.VerifyContextGL(); // ...其他操作 return 0; } ``` 4. 加载图像数据:使用以下代码将图像数据传递给SIFTGPU进行处理: ```cpp // 设置图像尺寸 sift.SetImageSize(width, height); // 加载图像数据 unsigned char* imageData = new unsigned char[width * height * 3]; // ...从文件或其他方式获取图像数据并存储到imageData中 // 传递图像数据给SIFTGPU sift.RunSIFT(width, height, imageData, GL_RGB, GL_UNSIGNED_BYTE); ``` 5. 提取特征点:使用以下代码提取图像中的特征点: ```cpp int numFeatures = sift.GetFeatureNum(); // 为特征点分配内存 float* featureData = new float[numFeatures * 128]; // 提取特征点 sift.GetFeatureVector(featureData); // 遍历特征点并进行处理 for (int i = 0; i < numFeatures; ++i) { // 获取特征点的关键信息(位置、尺度、方向等) SiftGPU::SiftKeypoint& keypoint = sift.GetFeature(i); // ...在这里可以对每个特征点进行处理 } // 释放内存 delete[] featureData; ``` 这只是一个简单的SIFTGPU使用教程,更详细的用法可以参考SIFTGPU的文档和示例代码。希望对你有帮助!如果你有更多问题,可以继续问我。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值