分享

如何使用GDI或者GDI+的函数对IplImage进行图像处理?

 学海无涯GL 2013-05-05
如何将OpenCV中的IplImage显示在MFC的窗口中

:主要函数有两个,一个是填写相应的Bitmapinfo结构体,另外一个是把图片显示到CWnd类型的窗口上去。
 虽然我特殊处理了一下256位的图,但我仍然无法画灰度图,挺奇怪的。目前只支持24位的图片。
main:
IplImage *img = cvLoadImage("****");
BITMAPINFO bmi;
FillBitmapInfo(&bmi, img->width, img->height, img->depth*img->nChannels);
ShowImage(img, wnd, bmi); // 这里的wnd是目标窗口,必须是CWnd类型的。
 
void FillBitmapInfo( BITMAPINFO *bmi, int width, int height, int bpp )
{
 ASSERT( bmi && width > 0 && height > 0 &&
  (bpp == 8 || bpp == 24 || bpp == 32) );
 BITMAPINFOHEADER* bmih = &(bmi->bmiHeader);
 memset( bmih, 0, sizeof(*bmih));
 bmih->biSize   = sizeof(BITMAPINFOHEADER);
 bmih->biWidth  = width;
 bmih->biHeight = -abs(height);
 bmih->biPlanes = 1;
 bmih->biBitCount = bpp;
 bmih->biCompression = BI_RGB;
 if( bpp == 8 )
 {
  RGBQUAD* palette = bmi->bmiColors;
  int i;
  for( i = 0; i < 256; i++ )
  {
   palette[i].rgbBlue = palette[i].rgbGreen = palette[i].rgbRed = (BYTE)i;
   palette[i].rgbReserved = 0;
  }
 }
}
void ShowImage(IplImage *pImg, CWnd *wnd, BITMAPINFO &bmi)
{
 CDC *pDC = wnd->GetDC();
 HDC  hDC = pDC->GetSafeHdc();
 CRect rect;
 wnd->GetClientRect(&rect);
 if(bmi.bmiHeader.biBitCount== 8)
 {
  CPalette pal;
  HPALETTE hpal=NULL;
  HPALETTE hOldPal=NULL;
  ::SetPaletteEntries(hpal,0,256,(LPPALETTEENTRY)bmi.bmiColors);
  hOldPal = ::SelectPalette(pDC->GetSafeHdc(), hpal, TRUE);
 }
 ::SetStretchBltMode(pDC->m_hDC, COLORONCOLOR);
 ::StretchDIBits(pDC->GetSafeHdc(),rect.left,rect.top,pImg->width,pImg->height,0,0,
    pImg->width,pImg->height,pImg->imageData,&bmi,DIB_RGB_COLORS,SRCCOPY);
}



(1 )IplImage -> Bitmap and Bitmap -> IplImage

IplImage *img ;
Bitmap bitmap( 20 ,20 ,PixelFormat24bppRGB ) ;
Graphics pGra( & bitmap) ;
HDC hdc = pGra ->GetHDC() ;
CvvImage cvimg ;
cvimg .CopyOf( img , -1) ;
RECT rect = { 0 , 0 , img ->width , img ->height } ;
cvimg.DrawToHDC( hdc , &rect ) ;
pGra ->ReleaseHDC( hdc ) ;

IplImage *tempimg = cvCreateImage(cvSize(bitmpa ->GetWidth() , bitmap ->Getheight (), 8 , 3) ;
BitmapData mydata;
Rect rect(0, 0, bitmpa ->GetWidth() , bitmap ->Getheight()) ;
bitmap.LockBits( &rect , ImageLockModeRead , PixelFormat24bppRGB ,&mydata) ;
memcpy(tempimg ->imagedata, mydata.scan0 , tempimg->width * tempimg->height* 3) ;
bitmap.UnlockBits( & objdata ) ;


(2) CBitmap ->Bitmap adn Bitmap -> CBitamp

CDC *pdc = this ->GetDC() ;
CBitmap m_Cbit;
m_Cbit.CreateCompatibleBitmap(pdc , 100 ,100 ) ;
Bitmap m_bit((HBITMAP) m_Cbit , NULL) ;

HBITMAP bitmap ;
m_bit.GetHBITMAP( Color( 0 , 0 , 0) , & bitmap ) ;
CBitmap *m_pbit = CBitmap ::FromHandle( bitmap) ;

...do something ;

m_pbit->DeleteObject() ;

(3) IplImage ->CBitmap , Cbitmap ->IplImage
CDC *pdc = this ->GetDC() ;
IplImage *img = cvCreateImage( cvSize( 100,100 ) , 8 , 3 );
CBitmap m_bitmap ;
m_bitmap.CreateCompatibleBitmap( pdc , 100 ,100 ) ;
CDC memdc ;
memdc.CreateCompatibleDC( pdc ) ;
CBitmap *pold = memdc .SelectObject( &m_bitmap) ;
CvvImage cvimg ;
Rect rect(0 , 0 , 100,100 ) ;
cvimg.CopyOf( img , -1 ) ;
cvimg.DrawToHDC( memdc.m_hDC , &rect ) ;
ReleaseDC( pdc) ;
IplImage *tempimg = cvCloneImage( img ) ;
m_bitmap.GetBitmapBits( img ->widthStep * img ->height , img ->imageData) ;

DirectShow OpenCV GDI+ 图形显示格式转换

DirectShow OpenCV GDI+ 图形显示格式转换

GDI+在显示图像方面要比GDI使用起来更方便

OpenCV图像处理方面无论深度和与VC的兼容性方面都是很好的,
DirectShow要视频采集方面目前应该说是最优秀的

但OpenCV的IplImage格式与GDI+所需要的BITMAPINFO稍有不同
同时OpenCV集成的视频捕捉部分采用的VFW,效率上远不如DirectShow

三者之间的图像转换工作我采用的如下方法,经测试效率还可以
测试架构为
1.DirectShow采集一帧图像到源内存buf,把此buf转为OpenCV的彩色IplImage格式
2.用OpenCV的方法转成灰度图得到一个新的灰度IplImage
3.把灰度IplImage转为GDI+所能识别的Bitmap,显示到指定DC中
以上所有过程没有对源内存buf的无效copy过程(当然转灰度图过程OpenCV是要建个Buf的,不可省的)

1.DirectShow采集一帧图像到源内存buf,在CB函数中..
STDMETHODIMP CSampleGrabberCB::BufferCB(double SampleTime, BYTE * pBuffer, long BufferSize )
{

//cvCreateImage opencv自带函数,建立一个空图

IplImage *pImg = cvCreateImage(cvSize(biWidth ,biHeight), 8, 3);//建立空图3*8=24位

pImg->imageData = (char*)pBuffer;//得到buf指针,图像创建完毕

::SendMessageW(m_hWnd, UM_DVBACK, 0, LPARAM(pImg));//把图发到主线程,转2

cvReleaseImage(&pImg);//释放图

return 0;

}

2.在主线程中消息响应函数中用OpenCV的方法转成灰度图得到一个新的灰度IplImage
LRESULT CMy05_ThreadSnapDlg::OnUMDVBACK(WPARAM wParam, LPARAM lParam)
{

IplImage *pImgSrc = (IplImage *)lParam;// 得到源图

IplImage* pImgGray = cvCreateImage(cvGetSize(pImgSrc), 8, 1);// 建立新的空的灰度图

cvCvtColor(pImgSrc, pImgGray, CV_BGR2GRAY);// 24位RGB彩图转灰度图,opencv自带函数,这里可以使用任何opencv函数进行图象处理

DrawImgToHwnd(m_hWnd, pImgGray); //自写函数,显示灰度图,即处理结果;转3

}

3.把灰度IplImage转为GDI+所能识别的Bitmap,显示到指定DC中
void CMy05_ThreadSnapDlg::DrawImgToHwnd(HWND hWnd, IplImage *pImg)
{

int nBitCount = (pImg->depth & 255) * pImg->nChannels;//图像色彩深度 opencv源码这样写的,也可以直接乘

int nWidth = pImg->width;

int nHeight = pImg->height;//这里特别注意,如果发现倒像,这里设为负值即可(-pImg->height)

BITMAPINFO *pBITMAPINFO = nBitCount == 24 ? m_pBITMAPINFO_24:m_pBITMAPINFO_08;

//24位图和8位图的BITMAPINFO是固定的,要提前创建好,一次即可

Bitmap* pBitmap = Bitmap::FromBITMAPINFO(pBITMAPINFO, pImg->imageData);//GDI+的图像格式

Graphics *gdiDC = Graphics::FromHWND(hWnd);//GDI+创建画板方法

gdiDC->DrawImage(pBitmap,0,0);//GDI+画图方法

delete pBitmap;

delete gdiDC;

}


使用GDI+显示OpenCV中的图像IplImage

  OpenCV虽然自带了轻量级的界面库HighGUI,但是支持的图像化元素实在是太少了,一般只在前期算法测试时使用。实际产品还是使用MFC库。因此本文记录了如何在GDI+中显示OpenCV中的IplImage格式的图像数据。

  假设创建的MFC MDI应用程序名为GdiplusTest。关于如何在MFC中使用GDI+图形化系统已经在《GDI+ 使用指南》一文中介绍了。

  显示OpenCV中的IplImage图像格式具体步骤如下:

  1. 在GdiplusTestView.cpp中添加OpenCV的头文件
    #include <cv.h>
    #include <highgui.h>
  2. 在CGdiplusTestView::OnDraw(CDC* pDC)函数中添加如下代码:
    复制代码
    //载入图像
    IplImage* srcImage = cvLoadImage("lena.jpg");
    //创建Bitmap对象
    Gdiplus::Bitmap bitmap(srcImage->width, srcImage->height, srcImage->widthStep,
    PixelFormat24bppRGB, (BYTE*)srcImage->imageData);

    Gdiplus::Graphics graphics(pDC->GetSafeHdc());
    graphics.DrawImage(&bitmap, 0, 0);

    GDI+ 使用指南(basic guiding of GDI plus )

      其实这个也没有什么用,毕竟已经是过时的技术了。不过技术的更新跟实际的使用还是有差距了,免不了还是要用这种过时的技术,所以还是记录下来,方便以后查阅。
      GDI+没记错的话是跟随XP诞生的,是XP系统上的图形绘制系统(以前的是GDI),GDI+相对于GDI提供了一些新的特性,比如渐变的画刷,支持多种图像格式等等。不过我觉得最大的变化,还是编程模型上的变化。GDI+使用了面向对象的思想,对接口进行了类封装,使用更加方便。
      在应用程序中使用GDI+库应该遵循一下步骤:
      1.包含Gdiplus.h头文件,如果图方便,加上:using namespace Gdiplus;这样使用GDI+中的任何东西就不需要重新指定命名空间了。
      2.链接DLL的导入库Gdiplus.lib。在VS中有两种方法,一是直接在项目属性->链接->输入中填入Gdiplus.lib;二是直接使用编译器原语:#pragma comment(lib, "Gdiplus.lib")
      3.在调用任何GDI+函数前一定要调用GDI+库初始化函数GdiplusStartup(),初始化GDI+库。
      4.在确定不需要使用任何GDI+函数并且所有GDI+对象均已销毁(变量超过了生存期),需要调用GDI+关闭函数GdiplusShutdown()。GDI+支持多线程,所以可以在任意一个线程中调用。

      下面讲下在实际MFC 单/多文档程序中,如何使用GDI+图形系统(程序名叫:GdiplusTest)。
      1.在Stdafx.h头文件中添加如下代码

    #include <GdiPlus.h>
    #pragma comment(lib, "Gdiplus.lib")

      2.在CGdiplusTestApp类中,添加两个变量,用于GDI+初始化函数。

    private:
    Gdiplus::GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;

    3.在CGdiplusTestApp::InitInstance()函数中添加如下代码,一定要在pMainFrame->ShowWindow(m_nCmdShow)之前,建议添加在CWinAppEx::InitInstance()之后。

    // Initialize GDI+.
    Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

    4.重载CGdiplusTestApp的ExitInstance()函数,然后添加GDI+关闭函数。

    	Gdiplus::GdiplusShutdown(gdiplusToken);

    5.在CGdiplusTestView::OnDraw(CDC* pDC)函数中使用GDI+类,显示图片lena.jpg

    Gdiplus::Graphics graphics(pDC->GetSafeHdc());
    Gdiplus::Image image(L"lena.jpg");
    graphics.DrawImage(&image, 10, 10);

    
    

    OpenCV ---HBITMAP to IplImage

    IplImage* hBitmap2Ipl(HBITMAP hBmp)
    {

    BITMAP bmp;
    ::GetObject(hBmp,sizeof(BITMAP),&bmp);
    int nChannels = bmp.bmBitsPixel == 1 ? 1 : bmp.bmBitsPixel/8 ;
    int depth = bmp.bmBitsPixel == 1 ? IPL_DEPTH_1U : IPL_DEPTH_8U;
    IplImage* img = cvCreateImageHeader( cvSize(bmp.bmWidth, bmp.bmHeight), depth, nChannels );
    img->imageData =(char*)malloc(bmp.bmHeight*bmp.bmWidth*nChannels*sizeof(char));
    memcpy(img->imageData,(char*)(bmp.bmBits),bmp.bmHeight*bmp.bmWidth*nChannels);
    return img;
    }

    void createDIB(IplImage* &pict)

    {

    IplImage * Red=cvCreateImage( cvSize(IMAGE_WIDTH,IMAGE_HEIGHT),IPL_DEPTH_8U, 1 );
    IplImage * Green=cvCreateImage( cvSize(IMAGE_WIDTH,IMAGE_HEIGHT),IPL_DEPTH_8U, 1 );
    IplImage * Blue=cvCreateImage( cvSize(IMAGE_WIDTH,IMAGE_HEIGHT),IPL_DEPTH_8U, 1 );
    cvSetImageCOI( pict, 3);
    cvCopy(pict,Red);
    cvSetImageCOI( pict, 2);
    cvCopy(pict,Green);
    cvSetImageCOI(pict, 1);
    cvCopy(pict,Blue);
    //Initialize the BMP display buffer
    bmi = (BITMAPINFO*)buffer;
    bmih = &(bmi->bmiHeader);
    memset( bmih, 0, sizeof(*bmih));
    bmih->biSize = sizeof(BITMAPINFOHEADER);
    bmih->biWidth = IMAGE_WIDTH;
    bmih->biHeight = IMAGE_HEIGHT; //
    -IMAGE_HEIGHT;
    bmih->biPlanes = 1;
    bmih->biCompression = BI_RGB;
    bmih->biBitCount = 24;
    palette = bmi->bmiColors;
    for( int i = 0; i < 256; i++ ){
    palette[i].rgbBlue = palette[i].rgbGreen = palette[i].rgbRed =(BYTE)i;
    palette[i].rgbReserved = 0;
    }
    cvReleaseImage(&Red);
    cvReleaseImage(&Green);
    cvReleaseImage(&Blue);
    }


    IplImage与CImage 图像类型的转换

    IplImage* plmg; //定义两个IplImage和CImage类型
    CImage cimg;
    plmg=cvLoadImage(pDoc->m_paName,1); //然后以路径为参数,把图形读进IplImage cimg.CopyOf(plmg); //把IplImage转换成CImage类型

    pImg =cimg.GetImage(); //把CImage类型转换成IplImage

    CRect rect(0,0,cimg.Width(),cimg.Height());
    HDC hDC=pDC->GetSafeHdc();
    cimg.DrawToHDC(hDC,rect); //CImage类型才能用DrawToHDC进行显示

    Bitmap与IplImage之间的转换

    在MFC编程中,用OpenCV来处理图像时,可能会进行Bitmap与IplImage之间的转换;所以在此留个记号,以免下次再用到的时候,还要去找。

    IplImage* BitmapToIplImage(HBITMAP hBmp)
    {
    	BITMAP bmp;    
    	
    	GetObject(hBmp, sizeof(BITMAP), &bmp);
    	int depth     = (bmp.bmBitsPixel == 1) ? IPL_DEPTH_1U : IPL_DEPTH_8U;
    	int nChannels = (bmp.bmBitsPixel == 1) ? 1 : bmp.bmBitsPixel/8;    
    	
    	IplImage* img = cvCreateImage(cvSize(bmp.bmWidth,bmp.bmHeight), depth, nChannels);  
    	
    	BYTE *pBuffer = new BYTE[bmp.bmHeight*bmp.bmWidth*nChannels];    
    	GetBitmapBits(hBmp, bmp.bmHeight*bmp.bmWidth*nChannels, pBuffer);
    	memcpy(img->imageData, pBuffer, bmp.bmHeight*bmp.bmWidth*nChannels);   
    	delete pBuffer;
    
    	IplImage *dst = cvCreateImage(cvGetSize(img), img->depth,3);    
    	cvCvtColor(img, dst, CV_BGRA2BGR);   
    	cvReleaseImage(&img);   
    	return dst;
    }

    如果要从CBitmap转为IplImage,可以先将CBitmap转为BITMAP,再由BITMAP转为IplImage;

    // CBitmap 转为 BITMAP
    CBitmap bitmap;
    bitmap.LoadBitmap(IDB_BITMAP);
    BITMAP   bmp;
    bitmap.GetBitmap(&bmp);
    
    // CBitmap与HBITMAP间的转换
    // CBitmap转为HBITMAP
    CBitmap bitmap;
    bitmap.LoadBitmap(IDB_BITMAP);
    HBITMAP bmp = HBITMAP(bitmap);
    // HBITMAP转为CBitmap
    HBITMAP  hbitmap;  
    CBitmap   bitmap;
    bitmap.Attach(hbitmap);
    

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多