vc bmp对象与Opencv Iplimage对象相互转换

时间:2021-02-20 17:52:50
 首先我们要了解两种数据结构

IplImag 对象结构:

/**************************************************************************************************
    *                                                                                                 *
    *  NOTE:                                                                                          *
    *    Only use the "8 bit, 1 or 3 channels" image, the BitMap use LowerLeft (底左),              *
    *    the IplImage use TopLeft (顶左)                                                            *
    *  IplImage:                                                                                      *
    *    nChannels = 1 or 3       number of channels                                                  *
    *    depth = IPL_DEPTH_8U     pixel depth (8 bit), IPL_DEPTH_8U=8                                 *
    *    dataOrder = 0            交叉存取颜色通道                                                    *
    *    origin = IPL_ORIGIN_TL   图像数据保存形式,IPL_ORIGIN_BL底左结构, IPL_ORIGIN_TL顶左结构      *
    *    align = 4                行数据对齐方式,保证下一行数据从整4字节位置开始                     *
    *    width                                                                                        *
    *    height                                                                                       *
    *    widthStep                图像数据行大小,单位字节                                            *
    *    imageSize                图像数据大小(=height*widthStep),单位字节                           *
    *    imageData                指向图像数据区,char *                                              *
    *  BITMAPINFOHEADER:                                                                              *
    *    biSize                   Specifies the number of bytes required by the structure             *
    *    biWidth                                                                                      *
    *    biHeight(>0)             biHeight>0底左结构;biHeight<0顶左结构                              *
    *    biPlanes = 1             Specifies the number of planes for the target device. This value    *
    *                             must be set to 1.                                                   *
    *    biBitCount =8 or 24      bits-per-pixel,8-(pixelDepth=8,channels=1),                         *
    *                             24-(pixelDepth=8,channels=3)                                        *
    *    biCompression = BI_RGB   An uncompressed format                                              *
    *    biSizeImage              Specifies the size, in bytes, of the image.This may be set to zero  *
    *                             for BI_RGB bitmaps.                                                 *
    *    biXPelsPerMeter = 0                                                                          *
    *    biYPelsPerMeter = 0                                                                          *
    *    biClrUsed = 0                                                                                *
    *    biClrImportant = 0                                                                           *
    *                                                                                                 *
    ***************************************************************************************************/

 

BMP文件对象

1. BMP文件组成
BMP文件由文件头、位图信息头、颜色信息和图形数据四部分组成。
2. BMP文件头
BMP文件头数据结构含有BMP文件的类型、文件大小和位图起始位置等信息。

其结构定义如下:

typedef struct tagBITMAPFILEHEADER
{
WORDbfType; // 位图文件的类型,必须为BM
DWORD bfSize; // 位图文件的大小,以字节为单位
WORDbfReserved1; // 位图文件保留字,必须为0
WORDbfReserved2; // 位图文件保留字,必须为0
DWORD bfOffBits; // 位图数据的起始位置,以相对于位图
// 文件头的偏移量表示,以字节为单位
} BITMAPFILEHEADER;

3. 位图信息头

BMP位图信息头数据用于说明位图的尺寸等信息。
typedef struct tagBITMAPINFOHEADER{
DWORD biSize; // 本结构所占用字节数
LONGbiWidth; // 位图的宽度,以像素为单位
LONGbiHeight; // 位图的高度,以像素为单位
WORD biPlanes; // 目标设备的级别,必须为1
WORD biBitCount// 每个像素所需的位数,必须是1(双色),
// 4(16色),8(256色)或24(真彩色)之一
DWORD biCompression; // 位图压缩类型,必须是 0(不压缩),
// 1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一
DWORD biSizeImage; // 位图的大小,以字节为单位
LONGbiXPelsPerMeter; // 位图水平分辨率,每米像素数
LONGbiYPelsPerMeter; // 位图垂直分辨率,每米像素数
DWORD biClrUsed;// 位图实际使用的颜色表中的颜色数
DWORD biClrImportant;// 位图显示过程中重要的颜色数
} BITMAPINFOHEADER;

4. 颜色表
颜色表用于说明位图中的颜色,它有若干个表项,每一个表项是一个RGBQUAD类型的结构,定义一种颜色。RGBQUAD结构的定义如下:

typedef struct tagRGBQUAD {
BYTErgbBlue;// 蓝色的亮度(值范围为0-255)
BYTErgbGreen; // 绿色的亮度(值范围为0-255)
BYTErgbRed; // 红色的亮度(值范围为0-255)
BYTErgbReserved;// 保留,必须为0
} RGBQUAD;
颜色表中RGBQUAD结构数据的个数有biBitCount来确定:
当biBitCount=1,4,8时,分别有2,16,256个表项;
当biBitCount=24时,没有颜色表项。
位图信息头和颜色表组成位图信息,BITMAPINFO结构定义如下:
typedef struct tagBITMAPINFO {
BITMAPINFOHEADER bmiHeader; // 位图信息头
RGBQUAD bmiColors[1]; // 颜色表
} BITMAPINFO;


5. 位图数据
位图数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。位图的一个像素值所占的字节数:

当biBitCount=1时,8个像素占1个字节;
当biBitCount=4时,2个像素占1个字节;
当biBitCount=8时,1个像素占1个字节;
当biBitCount=24时,1个像素占3个字节;
Windows规定一个扫描行所占的字节数必须是
4的倍数(即以long为单位),不足的以0填充,


接下来实现一个相互转换的类

//bmp2ipl.h
#ifndef BMP2IPL_H
#define BMP2IPL_H

class BMP {
public:
BMP():bmpData(NULL) {
memset(&biHeader, 0, sizeof(biHeader));
}
BMP(const BMP & img);
BMP(const IplImage &img);
BMP(int width, int height, int bitCount);
~BMP(){ delete [] bmpData; }

bool CreateImage(const BITMAPINFOHEADER &biHeader);

//Export
IplImage * BMP2Ipl();
//void Show(HWND hWnd, int nID);
//void Show(CDC *pDC, CRect & rect);
//void Show(HWND hWnd);

void ReSize(int newW, int newH);

private:
void CopyData(char *dest, const char *src, int dataByteSize,
bool isConvert, int height);
// isConvert=true 进行顶左和底左之间的转换(顶左到底左或底左到顶左),否则不转换

// biSizeImage may be set to zero for BI_RGB bitmaps, so calculate it.
int ImgSize() {
return ( biHeader.biHeight * ((biHeader.biWidth * biHeader.biBitCount / 8 + 3) & (-4)));
}

public:
void Clear();
BITMAPINFOHEADER biHeader;
unsigned char * bmpData;
};
#endif


     

#include "bmp2ipl.h"


BMP::BMP(const BMP & img)
{
if(!IsSupport(img)) {
BMP();
return;
}

//biHeader = img.biHeader;
PBITMAPINFOHEADER pBmpH = (PBITMAPINFOHEADER)&img.biHeader;
memcpy(&biHeader, pBmpH, sizeof(BITMAPINFOHEADER));
biHeader.biSizeImage = ImgSize();
bool isLowerLeft = biHeader.biHeight>0;
//int rowSize=0;
if(!isLowerLeft) biHeader.biHeight=-biHeader.biHeight;

if(bmpData!=NULL) delete[] bmpData;
bmpData = new unsigned char [biHeader.biSizeImage];
//memcpy(bmpData, img.bmpData, img.biHeader.biSizeImage);
CopyData((char *)bmpData, (char*)img.bmpData, biHeader.biSizeImage,
!isLowerLeft, biHeader.biHeight);
}

BMP::BMP(const IplImage &img) {
if(!IsSupport(img)) {
BMP();
return;
}
bool isTopLeft = (img.origin == IPL_ORIGIN_TL);

biHeader.biSize = sizeof(BITMAPINFOHEADER);
biHeader.biWidth = img.width;
biHeader.biHeight = img.height;
biHeader.biPlanes = 1;
biHeader.biBitCount = img.depth * img.nChannels;
biHeader.biCompression = BI_RGB;
biHeader.biSizeImage = img.imageSize;
biHeader.biXPelsPerMeter = 0;
biHeader.biYPelsPerMeter = 0;
biHeader.biClrUsed = 0;
biHeader.biClrImportant = 0;

if(bmpData!=NULL) delete[] bmpData;
bmpData = new unsigned char [img.imageSize];
//memcpy(bmpData, img.ImageData, img.imageSize);
CopyData((char*)bmpData, (char*)img.imageData, img.imageSize,
isTopLeft, img.height);
/*int i,j;
CvScalar s;
for(i=0;i<img.width;i++)
for(j=0;j<img.height;j++){
s=cvGet2D(&img,i,j);

}
*/
}

BMP::BMP(int width, int height, int bitCount) {
if(bitCount!=8 && bitCount!=24) return;

biHeader.biSize = sizeof(BITMAPINFOHEADER);
biHeader.biWidth = width;
biHeader.biHeight = height;
biHeader.biPlanes = 1;
biHeader.biBitCount = bitCount;
biHeader.biCompression = BI_RGB;
biHeader.biSizeImage = ImgSize();
biHeader.biXPelsPerMeter = 0;
biHeader.biYPelsPerMeter = 0;
biHeader.biClrUsed = 0;
biHeader.biClrImportant = 0;

if(bmpData!=NULL) delete[] bmpData;
bmpData = new unsigned char [biHeader.biSizeImage];
Clear();
}

// dest: the destination image
// dataByteSize: the Source image
// height: source image height
void BMP::CopyData(char *dest, const char *src, int dataByteSize,
bool isConvert, int height) {
char * p = dest;
if(!isConvert) {
memcpy(dest, src, dataByteSize);
return;
}
if(height<=0) return;
//int height = dataByteSize/rowByteSize;
int rowByteSize = dataByteSize / height;
src = src + dataByteSize - rowByteSize ;
for(int i=0; i<height; i++) {
memcpy(dest, src, rowByteSize);
dest += rowByteSize;
src -= rowByteSize;
}
}

IplImage * BMP::BMP2Ipl() {
if(!IsSupport(*this)) return NULL;

IplImage *iplImg;
int height;
bool isLowerLeft = biHeader.biHeight>0;
height = (biHeader.biHeight>0) ? biHeader.biHeight : -biHeader.biHeight;
iplImg = cvCreateImage( cvSize(biHeader.biWidth, height), IPL_DEPTH_8U, biHeader.biBitCount / 8);
//iplImg = cvCreateImageHeader( cvSize(biHeader.biWidth, height), IPL_DEPTH_8U, biHeader.biBitCount / 8);

//cvSetData(iplImg,(char*)bmpData,biHeader.biSizeImage/height);
CopyData( iplImg->imageData, (char*)bmpData, biHeader.biSizeImage,
isLowerLeft, height);
/*int i,j;
CvScalar s;
int channels=biHeader.biBitCount / 8;
int step=(biHeader.biWidth*channels+3) & -4;
int loc=0;
for(i=0;i<iplImg->height;i++){
for(j=0;j<iplImg->width;j++){
loc=i*step + j*channels;
s.val[0]=bmpData[loc];
if(channels==3){
s.val[1]=bmpData[loc+1];
s.val[2]=bmpData[loc+2];
}
cvSet2D(iplImg,i,j,s);
}
}*/
return iplImg;
}

void BMP::Clear() {
if(bmpData == NULL) return;
memset(bmpData, 0, ImgSize());
}

void BMP::ReSize(int newW, int newH) {
biHeader.biWidth = newW;
biHeader.biHeight = newH;
biHeader.biSizeImage = ImgSize();
if(bmpData!=NULL) delete[] bmpData;
bmpData = new unsigned char [biHeader.biSizeImage];
Clear();
}

bool BMP::CreateImage(const BITMAPINFOHEADER &bih) {
memset(&biHeader,0,sizeof(BITMAPINFOHEADER));
delete[] bmpData;
bmpData = NULL;

memcpy(&biHeader, &bih, sizeof(BITMAPINFOHEADER));
biHeader.biSizeImage = ImgSize();
bmpData = new unsigned char [ biHeader.biSizeImage ];
if(bmpData == NULL) return false;
else{
Clear();
return true;
}
}


 ok。

   花了一些时间来整理,希望对您有用。