OPENCV中IplImage与MFC中CDib类的相互转换

时间:2021-09-11 17:48:44

IplImageCDib的相互转换

    关于MFC中使用OPENCV的论述在这里就不重复了,很好的OPENCV入门文章,读者请参考

http://wiki.opencv.org.cn/index.php/%e5%9c%a8MFC%e4%b8%ad%e4%bd%bf%e7%94%a8OpenCV

http://wiki.opencv.org.cn/index.php/MFC%E4%B8%AD%E5%BF%AB%E9%80%9F%E5%BA%94%E7%94%A8OpenCV

         朋友们如果配置好了OPENCV,这里下载本篇文章的示例代码http://download.csdn.net/detail/li171049/6754749。(vs2008)

         本文探讨OPENCV中表示图像的结构体变量IplImageMFC中的CDib类的相互转换,以方便我们在选择使用算法时可以切换OPENCV算法或者CDib类的算法。这里我们仅讨论灰度图,即单通道8 BIT之间的转换。

       让我们先讲结果再说基础的数据结构。

OpenCV程序在MFC中实现的方法通常是采用CvvImage类。但是OpenCV2.2里面,把原来的CvvImage整个类给删除掉了,因此在MFC下使用带来诸多不方便,大家可以通过提前opencv2.1中的代码的方法来解决(弄一个h文件和一个cpp文件,然后放到你的项目里面一起编译就可以了)。具体的方法和文件内容,请看:Re: OpenCV2.2CImage(CvvImage)取消,MFC下显示图片少了个好方法

这里我们使用OPNECV2.1, CvvImage类定义在highgui.h文件中,读者可以自己看一下这个类的定义,该类中函数大多定义为虚函数,以方便我们子类派生。我们就做个该类的派生类就可以使用该类的函数了,具体定义openCVImage.h头文件如下:

//openCVImage.h

#include "highgui.h"//openCV接口头文件

#include "cv.h"//包含openCV中的图像处理算法

#include "Dib.h"

class OpenCVImage : public CvvImage

{

public:

     OpenCVImage();

     ~OpenCVImage();

     bool Ipl2Dib(IplImage *ImageScr ,CDib *m_PhotoImageCDib);//ImageScr8位通道,Ipl->Dib

     bool Dib2Ipl(CDib *CDibScr,IplImage *IplDst);//ImageScr8位通道,Dib->Ipl   

};

上述类中的两个函数完成两种数据类型的转换。其函数openCVImage.cpp如下:

#include "stdafx.h"//MFC新类必须包含的头文件

#include "OpenCVImage.h"

OpenCVImage::OpenCVImage()

{

}

OpenCVImage::~OpenCVImage()

{

}

bool OpenCVImage::Ipl2Dib(IplImage *ImageScr ,CDib *m_PhotoImageCDib)

{

     //CDib m_PhotoImageCDib=*DibDesImage;//

     int nPicWidth = ImageScr->width;

     int nPicHeight = ImageScr->height;

     int nByteCnt = ImageScr->nChannels;

     BYTE* buf =(BYTE*)ImageScr->imageData;

     // 清理空间

    m_PhotoImageCDib->Empty(TRUE);

     //m_BufloadSet=TRUE;

    // 生成位图文件头

    m_PhotoImageCDib->m_lpBmpFileHeader = (LPBITMAPFILEHEADER)new BYTE[sizeof(BITMAPFILEHEADER)];

     m_PhotoImageCDib->m_lpBmpFileHeader->bfType= (WORD)0x4D42;   //;((WORD)('M'<<8) | 'B')

     if(nByteCnt == 1)

     {

         UINT uGradeBmpLineByte = (nPicWidth + 3) / 4 * 4;

         DWORD dwGradeBmpDataSize = uGradeBmpLineByte * nPicHeight;

         DWORD dwGradeBmpSize =   sizeof(RGBQUAD) * 256 + dwGradeBmpDataSize;

         m_PhotoImageCDib->m_lpBmpFileHeader->bfSize=(DWORD)(sizeof(BITMAPFILEHEADER) +sizeof(BITMAPINFOHEADER) + dwGradeBmpSize);//指定文件大小

         m_PhotoImageCDib->m_lpBmpFileHeader->bfOffBits=(DWORD)(sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER) +sizeof(RGBQUAD) * 256);//从文件头到实际的位图数据的偏移字节数

         m_PhotoImageCDib->m_lpDib = new BYTE[nPicWidth*nPicHeight*nByteCnt+sizeof(BITMAPINFOHEADER) +sizeof(RGBQUAD) * 256];

 

     }

     else

     {

         m_PhotoImageCDib->m_lpBmpFileHeader->bfSize=(DWORD)(sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER) + nPicWidth*nPicHeight*nByteCnt);//指定文件大小

         m_PhotoImageCDib->m_lpBmpFileHeader->bfOffBits=(DWORD)(sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER));//从文件头到实际的位图数据的偏移字节数

         m_PhotoImageCDib->m_lpDib = new BYTE[nPicWidth*nPicHeight*nByteCnt+sizeof(BITMAPINFOHEADER)];

 

     }

     m_PhotoImageCDib->m_lpBmpFileHeader->bfReserved1 = 0;

     m_PhotoImageCDib->m_lpBmpFileHeader->bfReserved2 = 0;   

  

     // 生成位图信息头指针

      m_PhotoImageCDib->m_lpBmpInfoHeader = (LPBITMAPINFOHEADER)new BYTE[sizeof(BITMAPINFOHEADER)];

      m_PhotoImageCDib->m_lpBmpInfoHeader->biSize = sizeof(BITMAPINFOHEADER); //指定这个结构的长度

      m_PhotoImageCDib->m_lpBmpInfoHeader->biWidth = nPicWidth; //指定图像的宽度

      m_PhotoImageCDib->m_lpBmpInfoHeader->biHeight =nPicHeight; //指定图像的高度

      m_PhotoImageCDib->m_lpBmpInfoHeader->biPlanes = 1;         // 指定图像的位数,必须是

      m_PhotoImageCDib->m_lpBmpInfoHeader->biBitCount = nByteCnt*8;     //指定表示颜色时用到的位数

      m_PhotoImageCDib->m_lpBmpInfoHeader->biCompression = BI_RGB;//指定位图是否压缩

      m_PhotoImageCDib->m_lpBmpInfoHeader->biSizeImage = nPicWidth*nPicHeight*nByteCnt;//指定实际的位图数据占用的字节数

      m_PhotoImageCDib->m_lpBmpInfoHeader->biXPelsPerMeter = 0;

      m_PhotoImageCDib->m_lpBmpInfoHeader->biYPelsPerMeter = 0;

      m_PhotoImageCDib->m_lpBmpInfoHeader->biClrUsed = 0;

      m_PhotoImageCDib->m_lpBmpInfoHeader->biClrImportant = 0;

      m_PhotoImageCDib->m_lpBmpInfoHeader->biClrUsed=0;

 

     // 读取除位图文件头的所有数据

     memcpy(m_PhotoImageCDib->m_lpDib,m_PhotoImageCDib->m_lpBmpInfoHeader,sizeof(BITMAPINFOHEADER));

      if(nByteCnt == 1)

      {  

          LPRGBQUAD lpRgbQuad;              

          LPRGBQUAD lpGradeBmpRgbQuad = (LPRGBQUAD)(m_PhotoImageCDib->m_lpDib +sizeof(BITMAPINFOHEADER));

          memcpy( m_PhotoImageCDib->m_lpDib + m_PhotoImageCDib->m_lpBmpInfoHeader->biSize +sizeof(RGBQUAD) * 256,buf,nPicWidth*nPicHeight*nByteCnt);

          for(int k = 0; k < 256; k++)

          {

               lpRgbQuad = (LPRGBQUAD)(lpGradeBmpRgbQuad + k);

               lpRgbQuad->rgbBlue = k;

               lpRgbQuad->rgbGreen = k;

               lpRgbQuad->rgbRed = k;

               lpRgbQuad->rgbReserved = 0;

          }

      }

      else

      {

          memcpy( m_PhotoImageCDib->m_lpDib + m_PhotoImageCDib->m_lpBmpInfoHeader->biSize,buf,nPicWidth*nPicHeight*nByteCnt);

      }

      delete [] m_PhotoImageCDib->m_lpBmpInfoHeader;

      m_PhotoImageCDib->m_lpBmpInfoHeader = (LPBITMAPINFOHEADER)m_PhotoImageCDib->m_lpDib;

 

     // 设置位图信息指针

     m_PhotoImageCDib->m_lpBmpInfo = (LPBITMAPINFO)m_PhotoImageCDib->m_lpDib;

     // 设置每像素占的位数

     m_PhotoImageCDib->m_uBitCount = m_PhotoImageCDib->m_lpBmpInfoHeader->biBitCount;

     // 计算每行像素所占位数

     m_PhotoImageCDib->m_uLineByte = (m_PhotoImageCDib->GetWidth() * m_PhotoImageCDib->m_uBitCount / 8 + 3) / 4 * 4;

     // 设置位图颜色表指针

     m_PhotoImageCDib->m_lpRgbQuad = (LPRGBQUAD)(m_PhotoImageCDib->m_lpDib + m_PhotoImageCDib->m_lpBmpInfoHeader->biSize);

     // 计算颜色表长度

     DWORD dwRgbQuadLength = m_PhotoImageCDib->CalcRgbQuadLength();

 

      // 设置位图数据指针

     m_PhotoImageCDib->m_lpData = m_PhotoImageCDib->m_lpDib + m_PhotoImageCDib->m_lpBmpInfoHeader->biSize + dwRgbQuadLength;

     // 判断是否有颜色表

     if(m_PhotoImageCDib->m_lpRgbQuad == (LPRGBQUAD)m_PhotoImageCDib->m_lpData)

     {

          m_PhotoImageCDib->m_lpRgbQuad = NULL;    // 将位图颜色表指针置空

          m_PhotoImageCDib->m_bHasRgbQuad = FALSE; // 无颜色表

     }

      else

     {

          m_PhotoImageCDib->m_bHasRgbQuad = TRUE;  // 有颜色表

          m_PhotoImageCDib->MakePalette();         // 根据颜色表生成调色板

      }       

        // 设置位图大小

      m_PhotoImageCDib->m_lpBmpInfoHeader->biSizeImage = m_PhotoImageCDib->GetSize();

        // 位图有效

      m_PhotoImageCDib->m_bValid = TRUE;

 

      return true;

}

bool OpenCVImage::Dib2Ipl(CDib *CDibScr, IplImage *IplDst)//单通道u8

{

     if(CDibScr->m_lpBmpFileHeader->bfType == (WORD)0x4D42)  //;((WORD)('M'<<8) | 'B') //bmp文件

     {

         IplDst->nChannels = (int)((CDibScr->m_lpBmpInfoHeader->biBitCount)/8);//单通道u8

         if(1 == IplDst->nChannels)

         {

              IplDst->nSize = sizeof(IplImage);

              IplDst->ID = 0;

              IplDst->alphaChannel = 0;

              IplDst->depth = CDibScr->m_lpBmpInfoHeader->biBitCount;

              IplDst->colorModel[0] = 'G';

              IplDst->colorModel[1] = 'R';

              IplDst->colorModel[2] = 'A';

              IplDst->colorModel[3] = 'Y';

              IplDst->channelSeq[0] = 'G';

              IplDst->channelSeq[1] = 'R';

              IplDst->channelSeq[2] = 'A';

              IplDst->channelSeq[3] = 'Y';

    

         //   strcpy(IplDst->colorModel,"GRAY");

         //   strcpy(IplDst->channelSeq,"GRAY");

             

              IplDst->dataOrder = 0;

              IplDst->origin = 0;

              IplDst->align = 4;

              IplDst->width = CDibScr->m_lpBmpInfoHeader->biWidth;

              IplDst->height = CDibScr->m_lpBmpInfoHeader->biHeight;

              IplDst->roi = NULL;

              IplDst->maskROI = NULL;

              IplDst->imageId = NULL;

              IplDst->tileInfo = NULL;

              IplDst->imageSize = CDibScr->m_lpBmpInfoHeader->biWidth * CDibScr->m_lpBmpInfoHeader->biHeight;

              IplDst->imageData = newchar[CDibScr->m_lpBmpInfoHeader->biWidth * CDibScr->m_lpBmpInfoHeader->biHeight];

              memcpy(IplDst->imageData,CDibScr->m_lpData,CDibScr->m_lpBmpInfoHeader->biHeight * CDibScr->m_lpBmpInfoHeader->biWidth);

              IplDst->widthStep = CDibScr->m_lpBmpInfoHeader->biWidth;

              IplDst->BorderMode[0] = 0;

              IplDst->BorderMode[1] = 0;

              IplDst->BorderMode[2] = 0;

              IplDst->BorderMode[3] = 0;

              IplDst->BorderConst[0] = 0;

              IplDst->BorderConst[1] = 0;

              IplDst->BorderConst[2] = 0;

              IplDst->BorderConst[3] = 0;

              IplDst->imageDataOrigin = IplDst->imageData;

              return true;

 

         }

         else

         {

              return false;

         }

     }

     else

     {

         return false;

     }

}

至此我们完成了IplCDib的数据转换,enjoy!!!,于是我们就可以随便切换选择算法了。下面是一些基础数据类型的介绍。

使用过MFC做图像的应该都知道CDib类,读者可以参考《VC++图像处理程序设计(杨淑莹)》,该书简单易懂,适合入门。一般的CDib类完成如下功能:

//======================================================================

// 文件:Dib.h

// 内容:设备无关位图类-头文件

// 功能:()位图的加载与保存;

//        ()位图信息的获取;

//        ()位图数据的获取;

//        ()位图的显示;

//        ()位图的转换;

//        ()位图相关判断;

// 作者:李平科

// 联系:lipingke@126.com

// 日期:2009-7-26

//======================================================================

 

#pragma once

#include "stdafx.h"

 

class CDib : public CObject

{

public:

    // 构造函数,初始化数据成员

    CDib(void);

 

    // 析构函数,释放内存空间

    ~CDib(void);

 

    // 从文件加载位图

    BOOL LoadFromFile(LPCTSTR lpszPath);

     //从内存中加载图像

     BOOL LoadFromBuf(BYTE* buf,int nPicWidth,int nPicHeight,int nByteCnt);

 

    // 将位图保存到文件

    BOOL SaveToFile(LPCTSTR lpszPath);

 

    // 获取位图文件名

    LPCTSTR GetFileName();

 

    // 获取位图宽度

    LONG GetWidth();

 

    // 获取位图高度

    LONG GetHeight();

     void SetWidth(LONG nWidth);

     void SetHeight(LONG nHeight);

 

    // 获取位图的宽度和高度

    CSize GetDimension(); 

   

    // 获取位图大小

    DWORD GetSize();

 

    // 获取单个像素所占位数

    WORD GetBitCount();

 

    // 获取每行像素所占字节数

    UINT GetLineByte();

 

    // 获取位图颜色数

    DWORD GetNumOfColor();

 

    // 获取位图颜色表

    LPRGBQUAD GetRgbQuad();

 

    // 获取位图数据

    LPBYTE GetData();

     

    // 显示位图

    BOOL Draw(CDC *pDC, CPoint origin, CSize size);

 

    // 24位彩色位图转位灰度位图

    BOOL RgbToGrade();

 

// 32位彩色位图转位彩色位图

     BOOL Rgb32To24();

 

    // 8位灰度位图转位彩色位图

    BOOL GradeToRgb();

 

    // 判断是否含有颜色表

    BOOL HasRgbQuad();

 

    // 判断是否是灰度图

    BOOL IsGrade();

 

    // 判断位图是否有效

    BOOL IsValid(); 

      // 根据颜色表生成调色板

    BOOL MakePalette();

      // 计算位图颜色表长度

    DWORD CalcRgbQuadLength();

 

protected:

    // 计算位图颜色表长度

  //  DWORD CalcRgbQuadLength();

 

    // 根据颜色表生成调色板

  //  BOOL MakePalette();

public:

    // 清理空间

    void Empty(BOOL bFlag = TRUE);

 

public:

    // 位图文件名

    CString  m_fileName;

 

    // 位图文件头指针  

    LPBITMAPFILEHEADER m_lpBmpFileHeader; // 需要动态分配和释放

 

    // 位图指针(包含除位图文件头的所有内容)

     LPBYTE m_lpDib;                       // 需要动态分配和释放

 

    // 位图信息指针

    LPBITMAPINFO m_lpBmpInfo;

 

     // 位图信息头指针

     LPBITMAPINFOHEADER m_lpBmpInfoHeader; 

 

    // 位图颜色表指针

     LPRGBQUAD m_lpRgbQuad;

 

    // 位图数据指针

     LPBYTE m_lpData;

 

    // 调色板句柄

     HPALETTE m_hPalette;

 

    // 是否有颜色表

    BOOL m_bHasRgbQuad;

 

    // 位图是否有效

    BOOL m_bValid;

 

     // 每像素占的位数

     UINT m_uBitCount; 

 

     //每行像素所占字节数,为的倍数

     UINT m_uLineByte;

};

        而在OpenCV中使用IplImage结构体来表示一张图片,该结构体很容以理解,具体的参数含义请参考《OpenCV教程-基础篇》,该书很详细的介绍了每个参数的具体作用。在OPENCV中是这样定义IplImage结构体的:

typedef struct _IplImage

{

    int  nSize;             /* sizeof(IplImage) */

    int  ID;                /* version (=0)*/

    int  nChannels;         /* Most of OpenCV functions support 1,2,3 or 4 channels */

    int  alphaChannel;      /* Ignored by OpenCV */

    int  depth;             /* Pixel depth in bits: IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16S,

                               IPL_DEPTH_32S, IPL_DEPTH_32F and IPL_DEPTH_64F are supported.  */

    char colorModel[4];     /* Ignored by OpenCV */

    char channelSeq[4];     /* ditto */

    int  dataOrder;         /* 0 - interleaved color channels, 1 - separate color channels.

                               cvCreateImage can only create interleaved images */

    int  origin;            /* 0 - top-left origin,

                               1 - bottom-left origin (Windows bitmaps style).  */

    int  align;             /* Alignment of image rows (4 or 8).

                               OpenCV ignores it and uses widthStep instead.    */

    int  width;             /* Image width in pixels.                           */

    int  height;            /* Image height in pixels.                          */

    struct _IplROI *roi;    /* Image ROI. If NULL, the whole image is selected. */

    struct _IplImage *maskROI;     /* Must be NULL. */

    void  *imageId;                /* "          " */

    struct _IplTileInfo *tileInfo; /* "          " */

    int  imageSize;         /* Image data size in bytes

                               (==image->height*image->widthStep

                               in case of interleaved data)*/

    char *imageData;        /* Pointer to aligned image data.         */

    int  widthStep;         /* Size of aligned image row in bytes.    */

    int  BorderMode[4];     /* Ignored by OpenCV.                     */

    int  BorderConst[4];    /* Ditto.                                 */

    char *imageDataOrigin;  /* Pointer to very origin of image data

                               (not necessarily aligned) -

                               needed for correct deallocation */

}

IplImage;

感谢您的耐心!