图像信息处理:bmp文件、颜色空间转化、灰度图

Chapter 1: course

1.1 Why not make the aperture as small as possible?

  • The quantity of light is too small.
  • Lead to diffraction衍射 if the aperture is too small.
  • Difficult to control.

1.2 Changing the aperture size affects depth of field

1.2.1 概述

景深的“景”是指我们要拍摄的景物,“深”就是清晰度的纵深范围。当镜头对焦于拍摄目标时,这一点对应在相机的感光元件上能清晰成像。它前后一定范围内的景物也能被记录得较为清晰,这个范围就是景深。景深越大,纵深景物的清晰范围也就越大。景深越小,纵深景物的清晰范围也就越小。影响景深的三大要素是:

  1. 光圈:在镜头焦距及距离不变的情况下,光圈越小,景深越大,反之亦然。
  2. 距离:在镜头焦距及光圈不变的情况下,越接近拍摄的目标,景深越小,越远离拍摄的目标,景深越大。
  3. 焦距:在距离及光圈不变的情况下,镜头焦距越短,景深越大。即短焦镜头的景深大,长焦镜头的景深小。

图像信息处理:bmp文件、颜色空间转化、灰度图_第1张图片

1.2.2 原理

在焦点前后,光线开始聚集和扩散,点的影象变成模糊的,形成一个扩大的圆,这个圆就叫做弥散圆。

图像信息处理:bmp文件、颜色空间转化、灰度图_第2张图片

现实当中,观赏拍摄的影象是以某种方式(比如投影、放大成照片等等)来观察的,人的肉眼所感受到的影象与放大倍率、投影距离及观看距离有很大的关系,如果弥散圆的直径小于人眼的鉴别能力,在一定范围内实际影象产生的模糊是不能辨认的。这个不能辨认的弥散圆就称为容许弥散圆。

景深:

在焦点前后各有一个容许弥散圆,这两个弥散圆之间的距离就叫景深,即:在被摄主体(对焦点)前后,其影像仍然有一段清晰范围的,就是景深。换言之,被摄体的前后纵深,呈现在底片面的影象模糊度,都在容许弥散圆的限定范围内。

图像信息处理:bmp文件、颜色空间转化、灰度图_第3张图片

景深随镜头的焦距、光圈值、拍摄距离而变化。对于固定焦距和拍摄距离,使用光圈越小,也就是镜片的直径越小,景深越大,和镜头的通光量无关。

图像信息处理:bmp文件、颜色空间转化、灰度图_第4张图片

从焦点到近处容许弥散圆的的距离叫前景深,从焦点到远方容许弥散圆的距离叫后景深。

1.3 The principle imaging process of DC

  1. When taking photograph, the light from the scene goes through the lens and reaches CCD.
  2. When CCD being exposed, the photodiode光电二极管 is stimulated to release charges, and produces electrical signals.
  3. CCD controlling chip controls the electric flow through the controlling signal circuit in photoperceptive 感光的component. CCD will collect such electrical signals and output them to an amplifier放大器.
  4. After amplifying and filtering, the electrical signals reach ADC. And ADC transfer such electrical signals (continuous) to digital ones (discrete). The value of digital signal is proportional to the intensity of electrical signal and voltage. These values are corresponding to those of an image.
  5. But the above data cannot be treated as image directly. They will be further processed by DSP (digital signal processing). In DSP, color correction and white balance will be performed to obtain a qualified image, and the image will be encoded into the supported format and resolution, which can be stored as a image file.
  6. After the above steps, the image file appears on your memory card and can be previewed.

总结:电荷耦合器件(CCD)接收光学镜头传递来的影像->模拟信号->ADC(连续信号->离散)->DSP(色彩校正、白平衡)->储存到内存卡上

1.4 Digital image representation

Digital image can be represented as a 2D array or matrix

Each pixel in a grayscale image is represented by a byte (8 bits), which covers 256 degrees by [0…255]

Each pixel in a color image is represented by 3 bytes (24 bits), which are for R (red), G (Green) and B (Blue), respectively.

1.3.1 color

Color can be divided into chromatic color and achromatic color.

Chromatic color means the monochrome color (red, yellow, blue, etc.) and their combination. The colorful objects reflect the light selectively to the light spectrum of different wavelengths. Hence, they present different color under white light.

Achromatic color, also called non- chromatic color OR grayscale, means white, black and the gray intensities between them. The achromatic objects do not select the wavelength, so they are in neutral color.

1.3.2 Retina

Retina is the most important part of human eyes, like the film in an camera, to capture the light and produce image. There are two kinds of vision cell on the retina: rods and cones.

  • Rods: ~100, 000, 000, sensitive to light but cannot identify different colors.
  • Cones: ~6,000,000-7,000,000, work under strong light, but can identify different colors.

视细胞:又名感光细胞,分视杆细胞和视锥细胞。人视网膜有视杆细胞约12000万个,对弱光刺激敏感;视锥细胞有650万~700万个,对强光和颜色敏感。

1.3.3 Properties of color vision

图像信息处理:bmp文件、颜色空间转化、灰度图_第5张图片

Weber’s law

韦伯发现同一刺激差别量必须达到一定比例,才能引起差别感觉。这一比例是个常数,用公式表示:ΔI(差别阈限)/I(标准刺激强度)=k(常数/韦伯分数),这就是韦伯定律。图中,背景强度在一定范围内,这个比值是不变的。

1.3.4 Perception priority and sensitivity

  • 优先级:在同样的环境中,人类首先感知色调(H)变化,饱和(S),再然后明度值(V)
  • 灵敏度:人眼对明度变化最敏感,有最好的分辨率,这也是人眼能进行高动态光照渲染(HDR)的原因。

1.3.5 Color space

设备依赖的颜色空间模型

  • RGB Color + light, energy increases.
  • CMYK Light-Pigment mixture, energy decreases.
  • HSV Hue色调, Saturation饱和度, Intensity/Value明度。优点:色差感知与HSV锥体上的欧氏距离成正比。

图像信息处理:bmp文件、颜色空间转化、灰度图_第6张图片

非设备依赖的颜色空间模型

CIE颜色模型是一系列根据人眼对RGB仔细衡量的颜色模型,帮助人们在不同的设备,如扫描仪,显示器和打印机上一致地再现颜色。

  • CIE XYZ
  • CIE L ∗ a ∗ b L*a*b Lab
  • CIE YUV

颜色空间之间的转换

1. RGB<->CMY

C = 255 − R C=255-R C=255R

M = 255 − G M=255-G M=255G

Y = 255 − B Y=255-B Y=255B

2.RGB<->HSV

RGB<->XYZ <->HSV

3. RGB<->YUV

图像信息处理:bmp文件、颜色空间转化、灰度图_第7张图片

1.3.6 图像存储格式

a.bmp文件

windows中 .bmp=.bid
大部分情况下bmp文件是非压缩的,但是,bmp也支持run-length-encoding行程长度编码。如"AAAABBBCCDEEEE",经过变动长度编码法可将资料压缩为4A3B2C1D4E。

bmp文件头:

图像信息处理:bmp文件、颜色空间转化、灰度图_第8张图片

位图信息头:

图像信息处理:bmp文件、颜色空间转化、灰度图_第9张图片

调色盘和图像数据:

图像信息处理:bmp文件、颜色空间转化、灰度图_第10张图片

调色板其实是一张映射表,标识颜色索引号与其代表的颜色的对应关系。它在文件中的布局就像一个二维数组palette[N][4],其中N表示总的颜色索引数,每行的四个元素分别表示该索引对应的B、G、R和Alpha的值,每个分量占一个字节。如不设透明通道时,Alpha为0。因为前面知道,本图有256个颜色索引,因此N = 256。索引号就是所在行的行号,对应的颜色就是所在行的四个元素。这里截取一些数据来说明:

img

索引:(蓝,绿,红,Alpha)

0号:(fe,fa,fd,00)

1号:(fd,f3,fc,00)

2号:(f4,f3,fc,00)

3号:(fc,f2,f4,00)

4号:(f6,f2,f2,00)

5号:(fb,f9,f6,00) 等等。

一共有256种颜色,每个颜色占用4个字节,就是一共1024个字节,再加上前面的文件信息头和位图信息头的54个字节加起来一共是1078个字节。也就是说在位图数据出现之前一共有1078个字节,与我们在文件信息头得到的信息:文件头到文图数据区的偏移为1078个字节一致!

四、位图数据

下面就是位图数据了,每个像素占一个字节,取得这个字节后,以该字节为索引查询相应的颜色,并显示到相应的显示设备上就可以了。

注意:由于位图信息头中的图像高度是正数,所以位图数据在文件中的排列顺序是从左下角到右上角,以行为主序排列的。

img

也即我们见到的第一个像素60是图像最左下角的数据,第二个人像素60为图像最后一行第二列的数据,…一直到最后一行的最后一列数据,后面紧接的是倒数第二行的第一列的数据,依此类推。

如果图像是24位或是32位数据的位图的话,位图数据区就不是索引而是实际的像素值了。下面说明一下,此时位图数据区的每个像素的RGB颜色阵列排布:

24位RGB按照BGR的顺序来存储每个像素的各颜色通道的值,一个像素的所有颜色分量值都存完后才存下一个下一个像素,不进行交织存储。

32位数据按照BGRA的顺序存储,其余与24位位图的方式一样。

每行的bytes数必须是4的倍数,否则就用00补成4的倍数。6 bytes that represent a row in the bitmap:A0 37 F2 8B 31 C4 must be saved as: A0 37 F2 8B 31 C4 00 00

Chapter 2: assignment

图像信息处理:bmp文件、颜色空间转化、灰度图_第11张图片

#include
#include
#include
typedef unsigned short UINT16;
typedef unsigned long DWORD;
typedef unsigned char UNCHAR;
//存储bmp文件头 
typedef struct tagBITMAPFILEHEADER
{
//	UINT16 bfType;         //B M 加上这一行整个结构体就占16个字节,去掉就占12个字节,不知道为什么 
	DWORD  bfSize;         //size of file
	UINT16 bfReserved1;
	UINT16 bfReserved2;
	DWORD bfOffBits;       //header offset
}BITMAPFILEHEADER;         //14字节 
//存储位图信息头 
typedef struct tagBITMAPINFOHEADER{
	DWORD biSize;          //信息头大小 
	DWORD biWidth;         //图像宽度
 	DWORD biHeight;        //图像高度
	UINT16 biPlanes;       //图像的面位数
	UINT16 biBitCount;     //每个像素的位数	
	DWORD biCompression;   //压缩类型 
	DWORD biSizeImage;     //图文件大小 
	DWORD biXPelsPerMeter; //水平分辨率
	DWORD biYPelsPerMeter; //垂直分辨率
	DWORD biClrUsed;       //使用的色彩数
	DWORD biClrImportant;  //重要的颜色数 
}BITMAPINFOHEADER;         //40字节
//储存rgb图像信息
typedef struct tagrbgIMAGE{
	UNCHAR **r;//指向二维矩阵,表示图像的R信息 
	UNCHAR **g;//指向二维矩阵,表示图像的G信息 
	UNCHAR **b;//指向二维矩阵,表示图像的B信息 
}rgbIMAGE;
typedef rgbIMAGE *rgbIMAGEINFO;
//存储yuv图像信息 
typedef struct tagyuvIMAGE{
	UNCHAR **y;//指向二维矩阵,表示图像的Y信息 
	char **u;//指向二维矩阵,表示图像的U信息 
	char **v; //指向二维矩阵,表示图像的V信息 
}yuvIMAGE;
typedef yuvIMAGE *yuvIMAGEINFO;
//存储调色盘图像信息 
typedef struct RGBQUAD{
	UNCHAR rgbBlue;
	UNCHAR rgbGreen;
	UNCHAR rgbRed;
	UNCHAR rgbReserved;
};
/**
 *@brief 显示位图文件头信息 
 *@param[in] pBmpHead 指向位图文件头结构体 
*/
void showBmpHead(BITMAPFILEHEADER* pBmpHead);
/**
 *@brief 显示位图信息头 
 *@param[in] pBmpInforHead 指向位图信息头结构体 
*/
void showBmpInfoHead(BITMAPINFOHEADER* pBmpInforHead);
/**
 *@brief 读取bmp文件图像数据
 *@param[in] pBmpHead: 指向位图文件头结构体
 *          pBmpInforHead: 指向位图信息头结构体 
 *           fp: 指向位图文件返回的文件指针 
 *@return  一个存储rgb图像信息的结构体 
*/
rgbIMAGEINFO bmp2rgb(BITMAPFILEHEADER* pBmpHead,BITMAPINFOHEADER* pBmpInforHead,FILE* fp);
/**
 *@brief 将rgb图像数据经过变化得到rgb图像数据 
 *@param[in] rgb: 存储rgb图像数据的结构体 
 *          height: 图像的高 
 *          width: 图像的宽 
 *@return  一个存储yuv图像信息的结构体 
*/
yuvIMAGEINFO rgb2yuv(rgbIMAGEINFO rgb,int height,int width);
/**
 *@brief 求出一个二维矩阵的最大值或最小值 
 *@param[in] a: 表示二维矩阵 
 *          row: 二维矩阵的行数 
 *          col: 二维矩阵的列数
 *          choice: 1则返回二维矩阵最大值,2则返回二维矩阵最小值 
 *@return  返回二维矩阵的最大值或最小值 
*/
UNCHAR findmaxorminnum(UNCHAR **a,int row,int col,int choice);
/**
 *@brief 将一个二维矩阵的中的数都限定在[0,255] 之间 
 *@param[in] a: 表示二维矩阵 
 *          row: 二维矩阵的行数 
 *          col: 二维矩阵的列数
 *@return  返回处理后的二维矩阵
*/
UNCHAR **rearrange(UNCHAR **a,int row,int col);
int main(){
	//open bmp file
	FILE *fpbmp; 
	FILE *fpout,*fpout2;
	UINT16 bm;
	BITMAPFILEHEADER bmpfileheader;    //指向bmp文件头 
	BITMAPINFOHEADER bmpinfoheader;    //指向bmp信息头 
	BITMAPFILEHEADER targetfileheader; //指向目标bmp 文件头 
	BITMAPINFOHEADER targetinfoheader; //指向目标bmp 信息头 
	rgbIMAGEINFO rgbPicPoint;          //指向存储rgb图信息的结构体 
	rgbIMAGEINFO outrgb;               //指向yuv转到rgb的图信息的结构体 
	yuvIMAGEINFO yuvPicPoint;          //指向存储yuv图信息的结构体 
	int row,col;
	int i,j;

	//只读打开一个二进制文件 
	fpbmp=fopen("lena.bmp","rb");
	//如果文件读取失败,返回空指针 
	if(fpbmp==NULL){
		printf("Can not open the picture!");
		return 0;
	} 
	//让fpbmp指向bmp文件的开始
	fseek(fpbmp,0,SEEK_SET);
	//读取文件信息
	fread(&bm,sizeof(UINT16),1,fpbmp);                       //单独读取说明文件类型的两个字节 
	fread(&bmpfileheader,sizeof(BITMAPFILEHEADER),1,fpbmp);  //读取文件头信息 
	fread(&bmpinfoheader,sizeof(BITMAPINFOHEADER),1,fpbmp);  //读取信息头信息 
	showBmpHead(&bmpfileheader);                             //输出文件头信息 
	printf("**********************************************\n");
	showBmpInfoHead(&bmpinfoheader);                         //输出信息头信息 
	printf("**********************************************\n");
	int width;
	int height;	
	if(bmpinfoheader.biBitCount>=24){
		rgbPicPoint=bmp2rgb(&bmpfileheader,&bmpinfoheader,fpbmp);
		width=bmpinfoheader.biWidth;                         //图像的宽    
		height=bmpinfoheader.biHeight;	                     //图像的高 
	}
	//将RGB图片转为YUV
 	yuvPicPoint=rgb2yuv(rgbPicPoint,height,width);
 	//Rearrange gray intensity to lie between [0,255]
 	UNCHAR**grayimage=(UNCHAR**)malloc(sizeof(UNCHAR*)*height);
	for(row=0;row<height;row++){
		grayimage[row]=(UNCHAR*)malloc(sizeof(UNCHAR)*width);
	}
 	grayimage=rearrange(yuvPicPoint->y,height,width);
 	/*Write a grayscale bmp*/ 
// 	for(i=0;i<1;i++){
// 		for(j=0;j
// 			printf("%d ",yuvPicPoint->y[i][j]);
//		}
//	 }
// 	//构造灰度图的调色板
// 	RGBQUAD* rgbquad;
// 	rgbquad=(RGBQUAD*)malloc(sizeof(RGBQUAD)*256);
//	for(i=0;i<256;i++){
//		rgbquad[i].rgbBlue=i;
//		rgbquad[i].rgbGreen=i;
//      rgbquad[i].rgbRed=i;
//      rgbquad[i].rgbReserved=0;
//	} 
//	//构造灰度图的文件头 
// 	targetfileheader.bfSize=width*height+sizeof(RGBQUAD)*256+sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
//	targetfileheader.bfReserved1=0;
//	targetfileheader.bfReserved2=0;
//	targetfileheader.bfOffBits=sizeof(RGBQUAD)*256+sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
//	//构造灰度图的信息头
//	targetinfoheader.biBitCount=8;
//    targetinfoheader.biSize=sizeof(BITMAPINFOHEADER);
//    targetinfoheader.biHeight=height;
//    targetinfoheader.biWidth=width;
//    targetinfoheader.biPlanes=1;
//    targetinfoheader.biCompression=0;
//    targetinfoheader.biSizeImage=0;
//    targetinfoheader.biXPelsPerMeter=0;
//    targetinfoheader.biYPelsPerMeter=0;
//    targetinfoheader.biClrImportant=256;
//    targetinfoheader.biClrUsed=256;
    //将信息写入文件
	fpout=fopen("gray.bmp","wb");
	if(fpout==NULL){
		printf("Can not write the file!");
	}
//	else{
//		printf("ok");
//		fwrite(&bm,sizeof(UINT16),1,fpout);
//		fwrite(&targetfileheader,sizeof(BITMAPFILEHEADER),1,fpout);
//		fwrite(&targetinfoheader,sizeof(BITMAPINFOHEADER),1,fpout);
//		fwrite(rgbquad,sizeof(RGBQUAD),256,fpout);
//		fwrite(grayimage,sizeof(UNCHAR),height*width,fpout);
//		fclose(fpout);
//	}
	else{
		fwrite(&bm,sizeof(UINT16),1,fpout);                           //将文件类型写入文件 
		fwrite(&bmpfileheader,sizeof(BITMAPFILEHEADER),1,fpout);      //将文件头写入文件 
		fwrite(&bmpinfoheader,sizeof(BITMAPINFOHEADER),1,fpout);      //将信息头写入文件 
		UNCHAR *gray=(UNCHAR*)malloc(sizeof(UNCHAR)*height*width*3);  //用一个行向量储存图像数据 
		//将图像按24位存储,并将原二维数列扩充3倍,放入一维矩阵 
		for(row=0;row<height;row++){
			for(col=0;col<width;col++){
				gray[3*(row*height+col)]=grayimage[row][col];
				gray[3*(row*height+col)+1]=grayimage[row][col];
				gray[3*(row*height+col)+2]=grayimage[row][col];
			}
		}
		//将这个一维数列表示的图像数据写入文件 
		fwrite(gray,sizeof(UNCHAR),height*width*3,fpout);
		//关闭写入的文件 
		fclose(fpout);
		printf("Successfully obtained grayscale image!\n");	
	}
	//Change the luminance value Y
	for(row=0;row<height;row++){
		for(col=0;col<width;col++){
			yuvPicPoint->y[row][col]+=5;
		}
	}
	//yuv->rgb
	outrgb=(rgbIMAGEINFO)malloc(sizeof(rgbIMAGE));
	//初始化 
	outrgb->b=(UNCHAR**)malloc(sizeof(UNCHAR*)*height);
	for(row=0;row<height;row++){
		outrgb->b[row]=(UNCHAR*)malloc(sizeof(UNCHAR)*width);
	}	
	outrgb->g=(UNCHAR**)malloc(sizeof(UNCHAR*)*height);
	for(row=0;row<height;row++){
		outrgb->g[row]=(UNCHAR*)malloc(sizeof(UNCHAR)*width);
	}	
	outrgb->r=(UNCHAR **)malloc(sizeof(UNCHAR*)*height);
	for(row=0;row<height;row++){
		outrgb->r[row]=(UNCHAR*)malloc(sizeof(UNCHAR)*width);
	}
	//Rearrange gray intensity to lie between [0,255]; 
	yuvPicPoint->y=rearrange(yuvPicPoint->y,height,width);
	//通过公式将yuv转换为rgb
	for(row=0;row<height;row++){
		for(col=0;col<width;col++){
			outrgb->r[row][col]=UNCHAR(1.0000*yuvPicPoint->y[row][col]+1.1398*yuvPicPoint->v[row][col]);
			outrgb->g[row][col]=UNCHAR(0.9996*yuvPicPoint->y[row][col]-0.3954*yuvPicPoint->u[row][col]-0.5805*yuvPicPoint->v[row][col]);
			outrgb->b[row][col]=UNCHAR(1.0020*yuvPicPoint->y[row][col]+2.0361*yuvPicPoint->u[row][col]-0.0005*yuvPicPoint->v[row][col]);				
		}
	}
	//write a color bmp
	fpout2=fopen("lenaps.bmp","wb");
	if(!fpout2){
		printf("Wrong!Can not open the file!\n");
	}
	fwrite(&bm,sizeof(UINT16),1,fpout2);                              //文件类型写入文件 
	fwrite(&bmpfileheader,sizeof(BITMAPFILEHEADER),1,fpout2);         //将文件头写入文件  
	fwrite(&bmpinfoheader,sizeof(BITMAPINFOHEADER),1,fpout2);         //将信息头写入文件
	UNCHAR *rgb2=(UNCHAR*)malloc(sizeof(UNCHAR)*height*width*3);	  //用一个行向量储存图像数据	
	//按照bgr的顺序将3个二维矩阵存储为一个一维矩阵 
	for(row=0;row<height;row++){
		for(col=0;col<width;col++){
			rgb2[3*(row*height+col)]=outrgb->b[row][col];
			rgb2[3*(row*height+col)+1]=outrgb->g[row][col];
			rgb2[3*(row*height+col)+2]=outrgb->r[row][col];
		}
	}
	//将这个一维数列表示的图像数据写入文件 
	fwrite(rgb2,sizeof(UNCHAR),height*width*3,fpout2);
	//关闭文件 
	fclose(fpout2);
	printf("Successfully obtained RGB image!\n");	
	system("pause"); 
	return 0;
}

rgbIMAGEINFO bmp2rgb(BITMAPFILEHEADER* pBmpHead,BITMAPINFOHEADER* pBmpInforHead,FILE* fp){
	int bfoffbits=pBmpHead->bfOffBits;    //从文件头开始到实际图像数据之间的字节的偏移量 
	rgbIMAGEINFO imageinfo=(rgbIMAGEINFO)malloc(sizeof(rgbIMAGE));
	int row,col;	
	fseek(fp,bfoffbits,SEEK_SET);
	int width=pBmpInforHead->biWidth;     //获得图像的高 
	int height=pBmpInforHead->biHeight;   //获得图像的宽 
	//初始化 
	imageinfo->b=(UNCHAR**)malloc(sizeof(UNCHAR*)*height);
	for(row=0;row<height;row++){
		imageinfo->b[row]=(UNCHAR*)malloc(sizeof(UNCHAR)*width);
	}	
	imageinfo->g=(UNCHAR**)malloc(sizeof(UNCHAR*)*height);
	for(row=0;row<height;row++){
		imageinfo->g[row]=(UNCHAR*)malloc(sizeof(UNCHAR)*width);
	}	
	imageinfo->r=(UNCHAR **)malloc(sizeof(UNCHAR*)*height);
	for(row=0;row<height;row++){
		imageinfo->r[row]=(UNCHAR*)malloc(sizeof(UNCHAR)*width);
	}	
	//读取图像rgb信息 
	for(row=0;row<height;row++){
		for(col=0;col<width;col++){
			fread(&imageinfo->b[row][col],sizeof(UNCHAR),1,fp);
			fread(&imageinfo->g[row][col],sizeof(UNCHAR),1,fp);
			fread(&imageinfo->r[row][col],sizeof(UNCHAR),1,fp);
		}
	}
	return imageinfo;
}

yuvIMAGEINFO rgb2yuv(rgbIMAGEINFO rgb,int height,int width){
	yuvIMAGEINFO yuv=(yuvIMAGEINFO)malloc(sizeof(yuvIMAGE));
	if(!yuv){
		printf("Out of the memory!");
		return NULL;
	}
	int row,col;
	//初始化 
	yuv->y=(UNCHAR**)malloc(sizeof(UNCHAR*)*height);
	for(row=0;row<height;row++){
		yuv->y[row]=(UNCHAR*)malloc(sizeof(UNCHAR)*width);
	}	
	yuv->u=(char**)malloc(sizeof(char*)*height);
	for(row=0;row<height;row++){
		yuv->u[row]=(char*)malloc(sizeof(char)*width);
	}
		yuv->v=(char**)malloc(sizeof(char*)*height);
	for(row=0;row<height;row++){
		yuv->v[row]=(char*)malloc(sizeof(char)*width);
	}	
	//用公式将rgb信息转换为yuv 
	for(row=0;row<height;row++){
		for(col=0;col<width;col++){
			yuv->y[row][col]=UNCHAR(0.299*rgb->r[row][col]+0.587*rgb->g[row][col]+0.144*rgb->b[row][col]);
			yuv->u[row][col]=char(-0.147*rgb->r[row][col]-0.289*rgb->g[row][col]+0.435*rgb->b[row][col]);
			yuv->v[row][col]=char(0.615*rgb->r[row][col]-0.515*rgb->g[row][col]-0.100*rgb->b[row][col]);						
		}
	}
	return yuv;		
}

UNCHAR findmaxorminnum(UNCHAR **a,int row,int col,int choice){
	UNCHAR max=0,min=0;
	int i,j;
	switch(choice){
		case 1:
			for(i=0;i<row;i++){
				for(j=0;j<col;j++){
					if(a[i][j]>max){
						max=a[i][j];
					}
				}
			}
			return max;		
		case 2:
			for(i=0;i<row;i++){
				for(j=0;j<col;j++){
					if(a[i][j]<min){
						min=a[i][j];
					}
				}
			}
			return min;			
	}

}

UNCHAR **rearrange(UNCHAR **a,int row,int col){
	UNCHAR **rea=(UNCHAR**)malloc(sizeof(UNCHAR*)*row);
	int i,j;
	UNCHAR max,min,scope;
	for(i=0;i<row;i++){
		rea[i]=(UNCHAR*)malloc(sizeof(UNCHAR)*col);
	}	
	max=findmaxorminnum(a,row,col,1);
	min=findmaxorminnum(a,row,col,2);
	scope=max-min;
	for(i=0;i<row;i++){
		for(j=0;j<col;j++){
			rea[i][j]=UNCHAR(255*(a[i][j]-min)/scope);
		}
	}
	return rea;
}

void showBmpHead(BITMAPFILEHEADER* pBmpHead)  
{  
printf("文件大小:%d\n",pBmpHead->bfSize);  
printf("保留字:%d\n",pBmpHead->bfReserved1);  
printf("保留字:%d\n",pBmpHead->bfReserved2);  
printf("实际位图数据的偏移字节数:%d\n",pBmpHead->bfOffBits);  
}  
  
void showBmpInfoHead(tagBITMAPINFOHEADER* pBmpInforHead)  
{  
printf("位图信息头:\n");  
printf("结构体的长度:%d\n",pBmpInforHead->biSize);  
printf("位图宽:%d\n",pBmpInforHead->biWidth);  
printf("位图高:%d\n",pBmpInforHead->biHeight);  
printf("biPlanes平面数:%d\n",pBmpInforHead->biPlanes);  
printf("biBitCount采用颜色位数:%d\n",pBmpInforHead->biBitCount);  
printf("压缩方式:%d\n",pBmpInforHead->biCompression);  
printf("biSizeImage实际位图数据占用的字节数:%d\n",pBmpInforHead->biSizeImage);  
printf("X方向分辨率:%d\n",pBmpInforHead->biXPelsPerMeter);  
printf("Y方向分辨率:%d\n",pBmpInforHead->biYPelsPerMeter);  
printf("使用的颜色数:%d\n",pBmpInforHead->biClrUsed);  
printf("重要颜色数:%d\n",pBmpInforHead->biClrImportant);  
}  

图像信息处理:bmp文件、颜色空间转化、灰度图_第12张图片

你可能感兴趣的:(图像信息处理)