目前正在做一个信号处理的工作,要求将信号数据以谱图形式显示。当收到新的数据后,根据每组数据的大小计算出应该显示的颜色,同时将原来位图上移一位,在picturebox控件最下方显示出新的颜色点,达到平滑移动的效果。我目前采用了GDI的双缓存技术,但是画图的速度远远没有跟的上接收数据的速度,希望大家能够给我提一些更好的改进方案,提高我画图效率。(对另外两种画图方式,我还不是很了解,在此希望大家能够多多指教)class CWBSpecView : public CFormView
{
CDC MemDC;
CBitmap MemBitmap;} //MemDC, MemBitmap为全局变量,
void CWBSpecView::OnInitialUpdate()  //内存图层初始化
{

m_nScreenx=GetSystemMetrics(SM_CXSCREEN);
m_nScreeny=GetSystemMetrics(SM_CYSCREEN);
//内存图层初始化
CWnd *Specpic=this->GetDlgItem(IDC_PIC_SPEC);
CDC *SpecpicDC=Specpic->GetDC();
Specpic->GetClientRect(Rect2);
int w=Rect2.Width();
int h=Rect2.Height();
MemDC.CreateCompatibleDC(NULL);
MemBitmap.CreateCompatibleBitmap(SpecpicDC,m_nScreenx,m_nScreeny);
}
画图函数:
///////////////////////////////////////////////////////////////////
void drawpicSpec()       
{   int count;
int nLevel;
count=4096;
CDrawpictureData* DrawpictureData=GetDrawpictureData();
ASSERT(DrawpictureData);
    CMainFrame *pFrame=(CMainFrame *)AfxGetApp()->m_pMainWnd;
CWBSpecView *pView=(CWBSpecView *)(pFrame->m_pWBSpecview);
CWnd *Specpic=pView->GetDlgItem(IDC_PIC_SPEC);
CDC *SpecpicDC=Specpic->GetDC();
CRect Rect2;
Specpic->GetClientRect(Rect2);
int w=Rect2.Width();
int h=Rect2.Height();
CBitmap *poldBit=pView->MemDC.SelectObject(&pView->MemBitmap);
for(int i=0;i<count;i++)
{
 MSG message;
 while(::PeekMessage(&message,NULL,0,0,PM_REMOVE))
 {
 ::TranslateMessage(&message);
 ::DispatchMessage(&message);
 }
 nLevel=ColorConf->Comppow(float(DrawpictureData->uiSonaData[i])); //此处计算色素索引值
pView->MemDC.SetPixelV(i*Rect2.right/count,Rect2.Height()-1,ColorConf->m_nColor[nLevel]); //根据色素索引值在最下一行画出
}
pView->MemDC.BitBlt(0,Rect2.top-1,w,h,&pView->MemDC,0,0,SRCCOPY); //将内存中图像上移一行
    SpecpicDC->BitBlt(0,Rect2.top,w,h,&pView->MemDC,0,0,SRCCOPY);//将内存中图像显示
Specpic->ReleaseDC(SpecpicDC);
}程序启动2个线程来工作,一个线程用来接收数据,令一个线程根据接收到的数据进行绘图。画图函数在线程中调用,目前我采用这种方法,每秒只能显示十几帧,根本不能将每秒全部接收的数据显示。请各路高手能帮我修改一下解决方法。在此多谢了。

解决方案 »

  1.   

    建议用Directx  不过我也不会。最近比较感兴趣。。
      

  2.   

    你的画图函数里的那个for循环是干什么的?
      

  3.   

    大家可不可以根据我的代码,用directx帮我优化一下
    尤其bitmap上移,用directx该怎么解决
      

  4.   

    我的for循环,根据接收到的最新数据,来计算出每个数据需要表示的颜色值,并用setpixel()在最下一行画出
      

  5.   

    请教一下cqvoilet,用directx,该怎么修改我上面的代码呢,
    我现在发现我的for循环里,setpixel,占用时间太长,
    如果用directx,应该怎么修改
      

  6.   

    自己建一个缓冲区, 按 BITMAPHEADER自己建立位图格式数据, 在内存中完成操作,最后使用SetDIBBits显示
      

  7.   

    for(int i=0;i <count;i++) 

    MSG message; 
    while(::PeekMessage(&message,NULL,0,0,PM_REMOVE)) 

    ::TranslateMessage(&message); 
    ::DispatchMessage(&message); 

    nLevel=ColorConf->Comppow(float(DrawpictureData->uiSonaData[i])); //此处计算色素索引值 
    pView->MemDC.SetPixelV(i*Rect2.right/count,Rect2.Height()-1,ColorConf->m_nColor[nLevel]); //根据色素索引值在最下一行画出 
    } 应该是这个for循环的问题,你可以用vs2005自带的性能分析工具测试一下,看在哪个函数哪里耗时最多.然后再那里优化他.
    你在这个循环中要调用4096次里面的循环体,我相信这多半有问题,你把PeekMessage这段移到别的地方,然后这只是一个绘制的方法,做绘制的事情吧.OGL中一般绘制的函数是这样调用的
    while( msg.message != WM_QUIT )
    {
        if( PeedMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) ){
            Translatemessage( &msg );
            DispatchMessage( &msg );
        }else
            RenderScene( );
    }
      

  8.   

    pView->MemDC.SetPixelV(i*Rect2.right/count,Rect2.Height()-1,ColorConf->m_nColor[nLevel]); //根据色素索引值在最下一行画出
     你可以把参数在for循环外面算出来,省得他在for循环里面调用多次,还有for循环里面的参数能算出来的,就算出来,不要用函数来得到吧,省得函数调用栈时的开销
      

  9.   

    如果我只需要将原来图像上移一行后,在最下行按照计算出的色素值进行填充,除了在for循环中用setpixel()外,是否还有更好的解决方法呢?
      

  10.   

    setpixel 这样的函数是很慢的.
    直接改写位图,然后一起BITBLT一下.
    这样还不行的话,可以看一下用MMX指令,能提高几倍的速度.
      

  11.   

    我觉得速度瓶颈不在于GDI输出而在于你的逻辑
      

  12.   

    如果我只需要将原来图像上移一行后,在最下行按照计算出的色素值进行填充,除了在for循环中用setpixel()外,是否还有更好的解决方法呢?现在可以确定是我的for循环占用时间太长,各位有没有些好的修改意见
      

  13.   

    图像处理中用 setpixel就是 你在再好的机器配置也是白搭。SetPixel要经过坐标系转化、剪裁区域判断、将颜色匹配为设备支持的最接近的,最后还要根据不同的颜色格式寻址、为将颜色写入其所在位进行位运算。经过这么多层处理,速度不慢才怪。 http://www.pcppc.cn/kaifa/VBjiaocheng/kaifa_18452.html