用wxStaticBitmap控件显示从网络摄像头获取的数据 Topic is solved

这是wxWidgets论坛的中文版本。在这里,您可以用您的母语汉语讨论上面任一子论坛所涉及的所有关于wxWidgets的话题。欢迎大家参与到对有价值的帖子的中英互译工作中来!
Post Reply
nalisaki
Earned a small fee
Earned a small fee
Posts: 17
Joined: Wed Mar 21, 2012 1:36 pm

用wxStaticBitmap控件显示从网络摄像头获取的数据

Post by nalisaki »

现在已可以从网络摄像头获取数据并把数据转换为.bmp文件,想在wxwidget中的wxStaticBitmap控件中进行显示,当然是用控件显示,因为,会一直不停地从网络摄像头中获取数据并显示,这也是自己想做成的效果。现在的做法是,把一个回调函数传给采集图像的函数,我在这个回调函数中进行了一些显示图像的操作,但图像并没有显示出来,不知道是什么原因。个人感觉好像是一些事件没被触发一样。
因为在采集图像的函数中包含一个死循环,我做的一个示例的流程是:
当点击采集按钮时,在其事件响应中新建一个线程1,在线程1中调用彩集图像的函数,这样,图像就可以一直采集了。
在回调函数中,创建线程2,在线程2中进行图像显示的操作(用到一些全局变量),然后join,这样可以保证只有在图像处理完后,才能采集一下帧图像。

如果不新建线程2,而在回高函数里直接进行图像显示操作,对话框界面会显示成空白,就是什么都没有,但按照上面的作法,就不会出现这种情况。

但现在的问题是,图像没有显示出来,是哪里的原因呢?下面的我的代码,其中ShowFun是线程2中调用的函数,ShowBmp是线程1中调用的函数,即回调函数。

Code: Select all

void soDlgDialog::ShowBmp(IMGBUF* pImgFr,void* pvd)
{
    //s_mutexProtectingTheGlobalData->Lock();
//    if(pImg == NULL)
//        pImg = pImgFr;
//    else
//        pDlg->Refresh();
    //s_mutexProtectingTheGlobalData->Unlock();
    pthread_t p2;
    int res2;
    res2 = pthread_create(&p2,NULL,ShowFun,(void*)pImgFr);
    if(res2 != 0)
    {
        wxMessageBox(wxT("pthread_create error!"));
        return;
    }
    pthread_join(p2,NULL);
}
void *ShowFun(void *arg)
{

    IMGBUF* pImgFr = (IMGBUF*)arg;

    BITMAPFILEHEADER bHead;
    CLEAR(bHead);
    bHead.bfType = 0x4D42;
    bHead.bfSize = pImgFr->lBufferSize + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
    bHead.bfReserved1 = 0;
    bHead.bfReserved2 = 0;
    bHead.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
//    FILE* f = fopen("./bmp1.bmp","wb+");
//    fwrite(&bHead,sizeof(BITMAPFILEHEADER),1,f);
//    fwrite(&(pImgFr->bih),sizeof(pImgFr->bih),1,f);
//    fwrite(pImgFr->pBuffer,pImgFr->lBufferSize,1,f);
//    fclose(f);
    char * bufB = (char*)malloc(bHead.bfSize);
    if(bufB == NULL)
        wxMessageBox(wxT("malloc error!"));
    memcpy(bufB,&bHead,sizeof(bHead));
    memcpy(bufB+sizeof(bHead),&(pImgFr->bih),sizeof(pImgFr->bih));
    memcpy(bufB+bHead.bfOffBits,pImgFr->pBuffer,pImgFr->lBufferSize);

//    FILE* f = fopen("./bmp2.bmp","wb+");
//    fwrite(bufB,bHead.bfSize,1,f);
//    fclose(f);
    wxBitmap bmpTmp(bufB,pImgFr->bih.biWidth,pImgFr->bih.biHeight,24);
    //wxBitmap bmpTmp(wxT("./bmp2.bmp"));
    //int r = bmpTmp.SaveFile(wxT("./test111.bmp"),wxBITMAP_TYPE_BMP);
    //soDlgDialog::bmp1->Clean();
    soDlgDialog::bmp1->SetBitmap(bmpTmp);
//    wxMemoryDC memDC;
//    //wxBitmap bmpTmp(wxT("./bmp1.bmp"));
//    //wxBitmap bmpTmp((const char*)pImgFr->pBuffer,pImgFr->bih.biWidth,pImgFr->bih.biHeight,24);
//    //destDC.Clear();
//    memDC.SelectObject(bmpTmp);
//    wxClientDC destDC(soDlgDialog::bmp1);
//    //Draw the bitmap at 100, 100 on the destination DC
//    destDC.Blit(0, 0, // Draw at (100, 100)
//                bmpTmp.GetWidth(),
//                bmpTmp.GetHeight(), // Drawfullbitmap
//                &memDC, // Draw from memDC
//                0, 0,   // Draw from bitmap origin
//                wxCOPY, // Logical operation
//                false) ; // Take mask into account no
//    memDC.SelectObject(wxNullBitmap);
//    //Alternative method: use DrawBitmap
//    destDC.DrawBitmap(bmpTmp, 0, 0, true);

    //soDlgDialog::bmp1->SetBitmap(bmpTmp);
    free(bufB);
    //soDlgDialog::bmp1->Refresh();
    //soDlgDialog::bmp1->Update();
    //soDlgDialog::this->Refresh();
    pthread_exit(NULL);
}
请多指教,多谢!
Utensil
Moderator
Moderator
Posts: 423
Joined: Sun Feb 03, 2008 11:38 am
Location: China

Re: 用wxStaticBitmap控件显示从网络摄像头获取的数据

Post by Utensil »

1)显示动态图像不宜使用wxStaticBitmap控件,如你在注释掉的代码中尝试的,使用wxDC来DrawBitmap更为可行;建议还是从这个角度开始尝试,从成功显示一个图片开始;
2)回调的事件本身就在单独的EventLoop线程中处理,你创建一个线程并等其join,其实是多此一举,没用线程之时也显示不出来肯定是因为别的原因,这个方向走错了;建议去掉所有线程相关的部分;
3)从你的示例代码中看不出图像采集后如何触发显示的事件,不好判断为什么没有显示图像;
4)wxWidgets本身是一个跨平台的C++库,可是从你的代码中却看到pthread这样平台相关的调用,也看到malloc、void*等一些在C++中不建议使用的方式。从这段示例代码中看,也很容易出现资源泄漏。总体来说出现了一些不太好的编码风格。
In fascination of creating worlds by words, and in pursuit of words behind the world.

On Github: http://utensil.github.com
Technical Blog in Chinese: http://utensil.iteye.com/
Utensil
Moderator
Moderator
Posts: 423
Joined: Sun Feb 03, 2008 11:38 am
Location: China

Re: 用wxStaticBitmap控件显示从网络摄像头获取的数据

Post by Utensil »

细看了一下你的代码,你为了构造一个wxBitmap对象,你按照BMP的文件格式构造了bufB,然后用bufB调用wxBitmap对象的构造函数。其实核心问题就在这里:wxBitmap对象并不接受BMP的文件格式的buffer,而只接受XBM格式的buffer。

建议你先把 http://trac.wxwidgets.org/browser/wxWid ... rawing.cpp 这个例子吃透。
In fascination of creating worlds by words, and in pursuit of words behind the world.

On Github: http://utensil.github.com
Technical Blog in Chinese: http://utensil.iteye.com/
nalisaki
Earned a small fee
Earned a small fee
Posts: 17
Joined: Wed Mar 21, 2012 1:36 pm

Re: 用wxStaticBitmap控件显示从网络摄像头获取的数据

Post by nalisaki »

Utensil wrote:1)显示动态图像不宜使用wxStaticBitmap控件,如你在注释掉的代码中尝试的,使用wxDC来DrawBitmap更为可行;建议还是从这个角度开始尝试,从成功显示一个图片开始;
2)回调的事件本身就在单独的EventLoop线程中处理,你创建一个线程并等其join,其实是多此一举,没用线程之时也显示不出来肯定是因为别的原因,这个方向走错了;建议去掉所有线程相关的部分;
3)从你的示例代码中看不出图像采集后如何触发显示的事件,不好判断为什么没有显示图像;
4)wxWidgets本身是一个跨平台的C++库,可是从你的代码中却看到pthread这样平台相关的调用,也看到malloc、void*等一些在C++中不建议使用的方式。从这段示例代码中看,也很容易出现资源泄漏。总体来说出现了一些不太好的编码风格。
多谢,我感觉没用线程时显示不出来图片是因为一些事件没有被触发,但我已经用bmp1->Refresh()了。如果要触发重绘,那应该调用哪个函数呢,还是直接发送一个EVT_PAINT消息呢?
在这个回调函数里,不用做绘图方面的操作吗?只能在OnPaint中进行绘图吗。不过在OnPaint中进行绘图时,我感觉出现的问题还多一点,那里,我只在回调函数里把采集到的数据的指针赋值给了一个全局变量,然后在OnPaint中进行访问,访问控制是通过一个wxwidget中的互斥量,但结果是对话框界面显示空白。我再试试吧。多谢哈!
nalisaki
Earned a small fee
Earned a small fee
Posts: 17
Joined: Wed Mar 21, 2012 1:36 pm

Re: 用wxStaticBitmap控件显示从网络摄像头获取的数据

Post by nalisaki »

Utensil wrote:细看了一下你的代码,你为了构造一个wxBitmap对象,你按照BMP的文件格式构造了bufB,然后用bufB调用wxBitmap对象的构造函数。其实核心问题就在这里:wxBitmap对象并不接受BMP的文件格式的buffer,而只接受XBM格式的buffer。

建议你先把 http://trac.wxwidgets.org/browser/wxWid ... rawing.cpp 这个例子吃透。
但是XBM只运行单色的(即只支持黑白)的图片,而实际上采集的图片是彩色的。虽然wxBitmap有一个构造函数的形式是:
wxBitmap (const char bits[], int width, int height, int depth=1)
但具体的bits代表什么就不清楚了。是不带.bmp头信息的bmp数据?还是带上头信息的bmp数据?如果你清楚的话,能不能解释下?也想过从wxImage作中间过渡,也都试过,不管是带头的或不带头的,用它们(wxBitmap和wxImage)的SaveFile()都没成功。
多谢!
Post Reply