图标显示之bmp数据提取

        在Windows下,任何各式的图片文件(包括视频播放)都要转化为位图个时候才能显示出来,各种格式的图片文件也都是在位图格式的基础上采用不同的压缩算法生成的(Flash中使用了适量图,是按相同颜色区域存储的)。

一、下面我们来看看位图文件(*.BMP)的格式。

位图文件主要分为如下3个部分:

块名称

对应Windows结构体定义

大小(Byte)

文件信息头

BITMAPFILEHEADER

14

位图信息头

BITMAPINFOHEADER

40

RGB颜色阵列

BYTE*

由图像长宽尺寸决定

1、   文件信息头BITMAPFILEHEADER

结构体定义如下:

typedef struct tagBITMAPFILEHEADER { /* bmfh */

UINT bfType;  
DWORD bfSize; 
UINT bfReserved1; 
UINT bfReserved2; 
DWORD bfOffBits;

} BITMAPFILEHEADER;

其中:

bfType

说明文件的类型,该值必需是0x4D42,也就是字符'BM'。

bfSize

说明该位图文件的大小,用字节为单位

bfReserved1

保留,必须设置为0

bfReserved2

保留,必须设置为0

bfOffBits

说明从文件头开始到实际的图象数据之间的字节的偏移量。这个参数是非常有用的,因为位图信息头和调色板的长度会根据不同情况而变化,所以你可以用这个偏移值迅速的从文件中读取到位数据。

2、位图信息头BITMAPINFOHEADER

结构体定义如下:

typedef struct tagBITMAPINFOHEADER { /* bmih */

DWORD biSize; 
LONG biWidth; 
LONG biHeight; 
WORD biPlanes; 
WORD biBitCount; 
DWORD biCompression; 
DWORD biSizeImage; 
LONG biXPelsPerMeter; 
LONG biYPelsPerMeter; 
DWORD biClrUsed; 
DWORD biClrImportant;

} BITMAPINFOHEADER;

其中:

biSize

说明BITMAPINFOHEADER结构所需要的字数。

biWidth

说明图象的宽度,以象素为单位。

biHeight

说明图象的高度,以象素为单位。注:这个值除了用于描述图像的高度之外,它还有另一个用处,就是指明该图像是倒向的位图,还是正向的位图。如果该值是一个正数,说明图像是倒向的,如果该值是一个负数,则说明图像是正向的。大多数的BMP文件都是倒向的位图,也就是时,高度值是一个正数。

biPlanes

为目标设备说明位面数,其值将总是被设为1。

biBitCount

说明比特数/象素,其值为1、4、8、16、24、或32。但是由于我们平时用到的图像绝大部分是24位和32位的,所以我们讨论这两类图像。

biCompression

说明图象数据压缩的类型,同样我们只讨论没有压缩的类型:BI_RGB。

biSizeImage

说明图象的大小,以字节为单位。当用BI_RGB格式时,可设置为0。

biXPelsPerMeter

说明水平分辨率,用象素/米表示。

biYPelsPerMeter

说明垂直分辨率,用象素/米表示。

biClrUsed

说明位图实际使用的彩色表中的颜色索引数(设为0的话,则说明使用所有调色板项)。

biClrImportant

说明对图象显示有重要影响的颜色索引的数目,如果是0,表示都重要。

3、RGB颜色阵列

有关RGB三色空间我想大家都很熟悉,这里我想说的是在Windows下,RGB颜色阵列存储的格式其实BGR。也就是说,对于24位的RGB位图像素数据格式是:

蓝色B值

绿色G值

红色R值

对于32位的RGB位图像素数据格式是:

蓝色B值

绿色G值

红色R值

透明通道A值

透明通道也称Alpha通道,该值是该像素点的透明属性,取值在0(全透明)到255(不透明)之间。对于24位的图像来说,因为没有Alpha通道,故整个图像都不透明。

二、搞清了文件格式,下一步我们要实现加载。

            加载文件的目的是要得到图片属性,以及RGB数据,然后可以将其绘制在DC上(GDI),或是生成纹理对象(3D:OpenGL/Direct3D)。这两种用途在数据处理上有点区别,我们主要按前一种用法讲,在和3D有不同的地方,我们再提出来。

1、加载文件头

            //Load the file header

            BITMAPFILEHEADER header;

            memset(&header, 0, sizeof(header));

            inf.read((char*)&header, sizeof(header));

            if(header.bfType != 0x4D42)

                        return false;

            这个很简单,没有什么好说的。

            2、加载位图信息头

            //Load the image information header

            BITMAPINFOHEADER infoheader;

            memset(&infoheader, 0, sizeof(infoheader));

            inf.read((char*)&infoheader, sizeof(infoheader));

            m_iImageWidth = infoheader.biWidth;

            m_iImageHeight = infoheader.biHeight;

            m_iBitsPerPixel = infoheader.biBitCount;

            这里我们得到了3各重要的图形属性:宽,高,以及每个像素颜色所占用的位数。

3、行对齐

由于Windows在进行行扫描的时候最小的单位为4个字节,所以当

图片宽 X 每个像素的字节数 != 4的整数倍

时要在每行的后面补上缺少的字节,以0填充(一般来说当图像宽度为2的幂时不需要对齐)。位图文件里的数据在写入的时候已经进行了行对齐,也就是说加载的时候不需要再做行对齐。但是这样一来图片数据的长度就不是:宽 X 高 X 每个像素的字节数  了,我们需要通过下面的方法计算正确的数据长度:

//Calculate the image data size

int iLineByteCnt = (((m_iImageWidth*m_iBitsPerPixel) + 31) >> 5) << 2;

m_iImageDataSize = iLineByteCnt * m_iImageHeight;

4、加载图片数据

对于24位和32位的位图文件,位图数据的偏移量为sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER),也就是说现在我们可以直接读取图像数据了。

            if(m_pImageData) delete []m_pImageData;

            m_pImageData = new unsigned char[m_iImageDataSize];

            inf.read((char*)m_pImageData, m_iImageDataSize);

如果你足够细心,就会发现内存m_pImageData里的数据的确是BGR格式,可以用个纯蓝色或者是纯红色的图片测试一下。

5、绘制

好了,数据和属性我们都有了,现在就可以拿来随便用了,就和吃馒头一样,爱粘白糖粘白糖,爱粘红糖粘红糖。下面是我的GDI绘制代码,仅作参考。

void CImage::DrawImage(HDC hdc, int iLeft, int iTop, int iWidth, int iHeight)

{

            if(!hdc || m_pImageData == NULL)

                        return;

            BITMAPINFO bmi;

            memset(&bmi, 0, sizeof(bmi));

            bmi.bmiHeader.biSize = sizeof(BITMAPINFO);

            bmi.bmiHeader.biWidth = m_iImageWidth;

            bmi.bmiHeader.biHeight = m_iImageHeight;

            bmi.bmiHeader.biPlanes = 1;

            bmi.bmiHeader.biBitCount = m_iBitsPerPixel;

            bmi.bmiHeader.biCompression = BI_RGB;

            bmi.bmiHeader.biSizeImage = m_iImageDataSize;

            StretchDIBits(hdc, iLeft, iTop, iWidth, iHeight,

                                                0, 0, m_iImageWidth, m_iImageHeight,

                                                m_pImageData, &bmi, DIB_RGB_COLORS, SRCCOPY);

}

6、3D(OpenGL)的不同之处

如果你是想用刚才我们得到的数据生成纹理对象,那么你还要请出下面的问题。

首先,用来生成纹理的数据不需要对齐,也就是说不能在每行的后面加上对齐的字节。当然在OpenGL里要求纹理图片的尺寸为2的幂,所以这个问题实际上不存在;

其次,我们得到的图形数据格式是BGR(BGRA),所以在生成纹理的时候,需指定格式为GL_BGR_EXT(GL_BGRA_EXT);否则需要做BGR->RGB(BGRA->RGBA)的转化。

 

程序分析:

#include <config.h>
#include <pic_operation.h>
#include <stdlib.h>
#include <string.h>

#pragma pack(push) /* 将当前pack设置压栈保存 */
#pragma pack(1)    /* 必须在结构体定义之前使用 */

typedef struct tagBITMAPFILEHEADER { /* bmfh */
	unsigned short bfType; //bfType 说明文件的类型,该值必需是0x4D42,也就是字符'BM'。
	unsigned long  bfSize;//bfSize 说明该位图文件的大小,用字节为单位
	unsigned short bfReserved1;//bfReserved1 保留,必须设置为0
	unsigned short bfReserved2;//bfReserved2保留,必须设置为0
	unsigned long  bfOffBits;//说明从文件头开始到实际的图象数据之间的字节的偏移量。这个参数是非常有用的,因为位图信息头和调色板的长度会根据不同情况而变化,所以你可以用这个偏移值迅速的从文件中读取到位数据。
} BITMAPFILEHEADER;

typedef struct tagBITMAPINFOHEADER { /* bmih */
	unsigned long  biSize;//biSize 说明BITMAPINFOHEADER结构所需要的字数
	unsigned long  biWidth;//biWidth说明图象的宽度,以象素为单位。
	unsigned long  biHeight;//说明图象的高度,以象素为单位。注:这个值除了用于描述图像的高度之外,它还有另一个用处,就是指明该图像是倒向的位图,还是正向的位图。如果该值是一个正数,说明图像是倒向的,如果该值是一个负数,则说明图像是正向的。大多数的BMP文件都是倒向的位图,也就是时,高度值是一个正数。
	unsigned short biPlanes;//为目标设备说明位面数,其值将总是被设为1。
	unsigned short biBitCount;//说明比特数/象素,其值为1、4、8、16、24、或32。但是由于我们平时用到的图像绝大部分是24位和32位的,所以我们讨论这两类图像。
	unsigned long  biCompression;//说明图象数据压缩的类型,同样我们只讨论没有压缩的类型:BI_RGB。
	unsigned long  biSizeImage;//说明图象的大小,以字节为单位。当用BI_RGB格式时,可设置为0。
	unsigned long  biXPelsPerMeter;//说明水平分辨率,用象素/米表示
	unsigned long  biYPelsPerMeter;//说明垂直分辨率,用象素/米表示。
	unsigned long  biClrUsed;//说明位图实际使用的彩色表中的颜色索引数(设为0的话,则说明使用所有调色板项)。
	unsigned long  biClrImportant;//说明对图象显示有重要影响的颜色索引的数目,如果是0,表示都重要。
} BITMAPINFOHEADER;

#pragma pack(pop) /* 恢复先前的pack设置 */

static int isBMPFormat(unsigned char *aFileHead);
static int GetPixelDatasFrmBMP(unsigned char *aFileHead, PT_PixelDatas ptPixelDatas);
static int FreePixelDatasForBMP(PT_PixelDatas ptPixelDatas);

T_PicFileParser g_tBMPParser = {
	.name           = "bmp",
	.isSupport      = isBMPFormat,
	.GetPixelDatas  = GetPixelDatasFrmBMP,
	.FreePixelDatas = FreePixelDatasForBMP,	
};

static int isBMPFormat(unsigned char *aFileHead)
{
	if (aFileHead[0] != 0x42 || aFileHead[1] != 0x4d)//bfType 说明文件的类型,该值必需是0x4D42,也就是字符'BM'。
		return 0;
	else
		return 1;
}

static int CovertOneLine(int iWidth, int iSrcBpp, int iDstBpp, unsigned char *pudSrcDatas, unsigned char *pudDstDatas)
{
	unsigned int dwRed;
	unsigned int dwGreen;
	unsigned int dwBlue;
	unsigned int dwColor;

	unsigned short *pwDstDatas16bpp = (unsigned short *)pudDstDatas;
	unsigned int   *pwDstDatas32bpp = (unsigned int *)pudDstDatas;

	int i;
	int pos = 0;

	if (iSrcBpp != 24)
	{
		return -1;
	}

	if (iDstBpp == 24)
	{
		memcpy(pudDstDatas, pudSrcDatas, iWidth*3);
	}
	else
	{
		for (i = 0; i < iWidth; i++)
		{
			dwBlue  = pudSrcDatas[pos++];
			dwGreen = pudSrcDatas[pos++];
			dwRed   = pudSrcDatas[pos++];
			if (iDstBpp == 32)
			{
				dwColor = (dwRed << 16) | (dwGreen << 8) | dwBlue;
				*pwDstDatas32bpp = dwColor;
				pwDstDatas32bpp++;
			}
			else if (iDstBpp == 16)
			{
				/* 565 */
				dwRed   = dwRed >> 3;
				dwGreen = dwGreen >> 2;
				dwBlue  = dwBlue >> 3;
				dwColor = (dwRed << 11) | (dwGreen << 5) | (dwBlue);
				*pwDstDatas16bpp = dwColor;
				pwDstDatas16bpp++;
			}
		}
	}
	return 0;
}

/*
 * ptPixelDatas->iBpp 是输入的参数, 它决定从BMP得到的数据要转换为该格式
 */
static int GetPixelDatasFrmBMP(unsigned char *aFileHead, PT_PixelDatas ptPixelDatas)
{
	BITMAPFILEHEADER *ptBITMAPFILEHEADER;//文件信息头BITMAPFILEHEADER
	BITMAPINFOHEADER *ptBITMAPINFOHEADER;//位图信息头BITMAPINFOHEADER

	int iWidth;//宽度
	int iHeight;//高度
	int iBMPBpp;//位宽
	int y;

	unsigned char *pucSrc;
	unsigned char *pucDest;
	int iLineWidthAlign;
	int iLineWidthReal;
	

	ptBITMAPFILEHEADER = (BITMAPFILEHEADER *)aFileHead;
	ptBITMAPINFOHEADER = (BITMAPINFOHEADER *)(aFileHead + sizeof(BITMAPFILEHEADER));

	iWidth = ptBITMAPINFOHEADER->biWidth;//宽度
	iHeight = ptBITMAPINFOHEADER->biHeight;//高度
	iBMPBpp = ptBITMAPINFOHEADER->biBitCount;//位宽

	if (iBMPBpp != 24)//如果不是24位的就不支持
	{
		DBG_PRINTF("iBMPBpp = %d\n", iBMPBpp);
		DBG_PRINTF("sizeof(BITMAPFILEHEADER) = %d\n", sizeof(BITMAPFILEHEADER));
		return -1;
	}
	//填充像素数据描述结构体
	ptPixelDatas->iWidth  = iWidth;
	ptPixelDatas->iHeight = iHeight;
	//ptPixelDatas->iBpp    = iBpp;
	ptPixelDatas->aucPixelDatas = malloc(iWidth * iHeight * ptPixelDatas->iBpp / 8);
	ptPixelDatas->iLineBytes    = iWidth * ptPixelDatas->iBpp / 8;
	if (NULL == ptPixelDatas->aucPixelDatas)
	{
		return -1;
	}

	
	
	/*由于lcd的坐标和位图的坐标不一样,所以要进行下面的变换*/
	iLineWidthReal = iWidth * iBMPBpp / 8;
	iLineWidthAlign = (iLineWidthReal + 3) & ~0x3;   /* 由于要进行向4对齐,所以向4取整 ,真正的长度进行对齐*/
	
	pucSrc = aFileHead + ptBITMAPFILEHEADER->bfOffBits;
	pucSrc = pucSrc + (iHeight - 1) * iLineWidthAlign;

	pucDest = ptPixelDatas->aucPixelDatas;//要把数据放在哪里
	
	for (y = 0; y < iHeight; y++)
	{		
		//memcpy(pucDest, pucSrc, iLineWidthReal);
		CovertOneLine(iWidth, iBMPBpp, ptPixelDatas->iBpp, pucSrc, pucDest);
		pucSrc  -= iLineWidthAlign;
		pucDest += ptPixelDatas->iLineBytes;
	}
	return 0;	
}

static int FreePixelDatasForBMP(PT_PixelDatas ptPixelDatas)
{
	free(ptPixelDatas->aucPixelDatas);
	return 0;
}



 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
采用python,opencv开源库实现图片提取曲线数据 使用说明: openpic 可以选择采用自动采集测点数据或手动采集测点数据 操作过程:第一步裁剪,crop, 鼠标响应step_crop, 鼠标左键选裁剪的矩形区域,选中后键盘n表示确认进入下一步骤; 无需裁剪时键盘o直接进入下一步骤;esc表示取消,退回到开始 第二步矫正,correction,鼠标响应step_correction, 鼠标左键点选梯形矫正的四个顶点, 键盘u左上,i右上,j左下,k右下,切换当前有效操作做的顶点, 键盘w up, s down, a left, d right 或上下左右键,微调鼠标选点位置,detail display放大显示当前选点的细节; 键盘t键操作矫正,n键表示确认矫正结果进入下一步骤,b键表示取消矫正重新选梯形顶点 第三步坐标系,coordinate,鼠标响应step_coordinate, 鼠标左键点选xy坐标系的原点、x轴最大刻度点、y轴最大刻度点。 xy轴的坐标刻度值由选择图片窗口的x、y最大最小值决定,xy轴必须原点处交汇但可以从非零开始分别计算刻度 键盘u y轴,j 坐标原点,k x轴,切换当前鼠标点选的有效点 键盘w up, s down, a left, d right 或上下左右键,微调鼠标选点位置,detail display放大显示当前选点的细节; 默认图片已经矫正,坐标系仅支持直角坐标系,在设置坐标系时原点可以任意移动,x轴y轴只能依据原点位置在直角轴上移动 键盘n表示确认坐标系设置结果进入下一步,b表示取消退回到上一步,esc退回到开始 第四步采集数据:手动采集manual_sample中使用sample_points,鼠标响应step_sample_points,鼠标左键点选要采集的测点,键盘n表示确认选择开始选下一个点 键盘o表示选择完输出测点数据到csv文件。 键盘w up, s down, a left, d right 或上下左右键,微调鼠标选点位置,detail display放大显示当前选点的细节; 自动采集auto_sample中使用tracecolor,鼠标响应step_color_picker。自动采集原理为先选择曲线,然后自动等间隔采集曲线上点 开始界面中没有自动采集点数,在使用auto的函数调用时添加。 自动采集以tracecolor颜色提取构建曲线,曲线点数据平滑,间隔重采样为主要工作过程。在图片中存在同色非相关区域时,可采用颜色提取刷,手动确定曲线的有效范围 键盘l切换提取刷开关,提取刷功能开启时,鼠标右键按住滑动刷出有效的采集范围。 鼠标左键点选的位置作为提取颜色,同时具备单一颜色固定阈值提取曲线和多个颜色自动确定阈值范围的提取曲线两种模式。 键盘p选择鼠标位置的点颜色作为多个颜色参考提取,移动鼠标位置(或键盘移动)采用p键选择多个颜色点,确定提取阈值范围 键盘n表示完成颜色选择开始曲线提取显示提取后黑白曲线图,键盘b取消提取退回上一步重新操作 esc取消退回到开始 键盘o表示接受曲线提取结果,开始自动间隔采集计算曲线上点,并输出csv文件
function GRABIT Extracts data points from an image file. % % GRABIT starts a GUI program for extracting data from an image file. % It is capable of reading in BMP, JPG, TIF, GIF, and PNG files (anything % that is readable by IMREAD). Multiple data sets can be extracted from a % single image file, and the data is saved as an n-by-2 matrix variable in % the workspace. It can also be renamed and saved as a MAT file. % % Following steps should be taken: % 1. Load the image file. % 2. Calibrate axes dimensions. You will be prompted to select 4 points % on the image. Zoom and pan enabled. % 3. Grab points by clicking on points. Right-click to delete a point. % Image can be zoomed and panned. % 4. Multiple data sets will remain in memory so long as the GUI is open. % Variables can be renamed, saved to file, or edited in Array Editor. % % Panning is achieved by clicking and dragging on the image. Double-click % to center view. Right click and drag to zoom in and out. In addition, % there are keyboard shortcuts for zooming: % - zoom in % - zoom out % - reset view % % This code will also work for extracting data points from a tilted or a % skewed image (even upside-down or mirrored). The calibration stage % ensures that the imperfect orientation or quality of the image is % accounted for. % % The types of files that will most likely work are BMP, JPG, TIF, GIF (up % to 8-bit), and PNG files. Basically, any format supported by the IMREAD % is accepted. % % GRABIT(FILENAME) will start the GUI program and open the image file % FILENAME.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值