毕设—高动态范围图像渲染算法之HDR文件的读取(二)

色调映射技术的根本目的是把无法直接在显示器上显示的hdr图像转化成可以直接显示的RGB图像。(hdr图像在一些外网上可以免费下载,不想找的可以直接下载:https://download.csdn.net/download/A_ACM/12449991)如图所示:
在这里插入图片描述明白了要干什么,那我们就要开始干活了。

首先我们用Hex Editor Neo软件打开hdr图像,看看这种文件内都有啥内容。

在这里插入图片描述在文件头部分我们看到:该文件采用的是Radiance RGB编码格式,每个像素点占32位,图像的长宽分别是768、512。数据部分就是每个像素点的数据了。

在读取hdr文件之前,我们要了解一下Radiance RGB编码格式(这里就不进行介绍了)。

因为是32位的,所以每个像素点占32位,每8位的信息如下。每个字节代表的意思就是字面上的意思。
在这里插入图片描述
知道了RGBE的数据大小,知道了是Radiance RGB编码格式,我们就可以计算出HDR图像所代表场景的信息。计算公式如图。
在这里插入图片描述好了,现在知道了场景信息还原函数、每个像素点的位置信息、每个像素点的数据。现在我们开始编写代码。(下面的代码来源于一个外网,并不是自己编写的)。

hdrloader.h文件如下:

class HDRLoaderResult {
public:
	int width, height;
	float *cols;
};

class HDRLoader {
public:
	static int load(const char *fileName, HDRLoaderResult &res);
};

hdrloader.cpp文件如下:


#include "hdrloader.h"

#include <math.h>
#include <memory.h>
#include <stdio.h>

typedef unsigned char RGBE[4];

#define R			0
#define G			1
#define B			2
#define E			3

#define  MINELEN	8				
#define  MAXELEN	0x7fff			

//定义函数
static void workOnRGBE(RGBE *scan, int len, float *cols);
static bool decrunch(RGBE *scanline, int len, FILE *file);
static bool oldDecrunch(RGBE *scanline, int len, FILE *file);

int HDRLoader::load(const char *fileName, HDRLoaderResult &res)
{
	int i;
	char str[200];
	FILE *file;

	//读文件
	file = fopen(fileName, "rb");
	if (!file)
	{
		return 0;
	}
		
	//判断文件编码类型
	fread(str, 10, 1, file);
	if (memcmp(str, "#?RADIANCE", 10)) {
		fclose(file);
		return -1;
	}

	fseek(file, 1, SEEK_CUR);

	char cmd[200];
	i = 0;
	char c = 0, oldc;

	//读取无用信息,并舍弃
	while(true) {
		oldc = c;
		c = fgetc(file);
		if (c == 0xa && oldc == 0xa)
			break;
		cmd[i++] = c;
	}

	char reso[200];
	i = 0;

	//读取图像长宽
	while(true) {
		c = fgetc(file);
		reso[i++] = c;
		printf("%c\n",c);
		if (c == 0xa)
			break;
	}

	int w, h;
	if (!sscanf(reso, "-Y %ld +X %ld", &h, &w)) {
		fclose(file);
		return -2;
	}

	//把图像的长宽赋值给结构体
	res.width = w;
	res.height = h;

	//定义图像数据数组
	float *cols = new float[w * h * 3];
	res.cols = cols;

	RGBE *scanline = new RGBE[w];
	if (!scanline) {
		fclose(file);
		return -3;
	}

	//每次对一行进行处理,一共处理h行
	for (int y = h - 1; y >= 0; y--) {
		if (decrunch(scanline, w, file) == false)
			break;
		workOnRGBE(scanline, w, cols);
		cols += w * 3;
	}

	delete [] scanline;

	//关闭文件
	fclose(file);

	return 1;
}

/*
HDRI文件三分量数据还原成场景三分量
*/
float convertComponent(int expo, int val)
{
	float v = val / 256.0f;
	float d = (float) pow(2.0, expo);
	return v * d;
}

/*
计算得出HDRI文件的RGBE四分量
*/
void workOnRGBE(RGBE *scan, int len, float *cols)
{
	while (len-- > 0) {
		int expo = scan[0][E] - 128;
		cols[0] = convertComponent(expo, scan[0][R]);
		cols[1] = convertComponent(expo, scan[0][G]);
		cols[2] = convertComponent(expo, scan[0][B]);
		cols += 3;
		scan++;
	}
}

/*
对每一行数据进行读取
*/
bool decrunch(RGBE *scanline, int len, FILE *file)
{
	int  i, j;

	//判断是否大于两字节
	if (len < MINELEN || len > MAXELEN)
		return oldDecrunch(scanline, len, file);

	i = fgetc(file);
	if (i != 2) {
		fseek(file, -1, SEEK_CUR);
		return oldDecrunch(scanline, len, file);
	}
	
	//如果就剩俩字节,默认为GB
	scanline[0][G] = fgetc(file);
	scanline[0][B] = fgetc(file);
	i = fgetc(file);

	if (scanline[0][G] != 2 || scanline[0][B] & 128) {
		scanline[0][R] = 2;
		scanline[0][E] = i;
		return oldDecrunch(scanline + 1, len - 1, file);
	}

	//分四次读取
	for (i = 0; i < 4; i++) {
	    for (j = 0; j < len; ) {
			unsigned char code = fgetc(file);
			
			if (code > 128) {
			    code &= 127;
			    unsigned char val = fgetc(file);
			    while (code--)
					scanline[j++][i] = val;
			}
			else  {
			    while(code--)
					scanline[j++][i] = fgetc(file);
			}
		}
    }

	return feof(file) ? false : true;
}

bool oldDecrunch(RGBE *scanline, int len, FILE *file)
{
	int i;
	int rshift = 0;
	
	//读取RGBE四分量数据
	while (len > 0) {
		scanline[0][R] = fgetc(file);
		scanline[0][G] = fgetc(file);
		scanline[0][B] = fgetc(file);
		scanline[0][E] = fgetc(file);
		if (feof(file))
			return false;

		if (scanline[0][R] == 1 &&
			scanline[0][G] == 1 &&
			scanline[0][B] == 1) {
			for (i = scanline[0][E] << rshift; i > 0; i--) {
				memcpy(&scanline[0][0], &scanline[-1][0], 4);
				scanline++;
				len--;
			}
			rshift += 8;
		}
		else {
			scanline++;
			len--;
			rshift = 0;
		}
	}
	return true;
}

使用方式:

	int rows,cols;
	
	//fileName是你的hdr文件的路径
	HDRLoaderResult result;
	int ret = HDRLoader::load(fileName, result);
	
	//图像长宽
	rows=result.height;
	cols=result.width;

	for(int i = 0; i < rows; i++){
		for(int j = 0; j < cols; j++){
				
				//场景的RGB信息
				R=result.cols[i*cols*3+j*3+0];
				G=result.cols[i*cols*3+j*3+1];
				B=result.cols[i*cols*3+j*3+2];
			}
		}

好了,现在场景的RGB三分量和长宽信息都提取出来了,下面进行色调映射。

展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客
应支付0元
点击重新获取
扫码支付

支付成功即可阅读