c++安装OpenEXR库(windows下)-CSDN博客
在配置完OpenEXR库后,就能读取、写入EXR数据。
目录
以下是读取和写入多通道EXR(非默认RGB通道)的方式:
读取多通道EXR并转成数组:
#pragma once
#include <ImfArray.h>
#include <iostream>
#include <ImfFrameBuffer.h>
#include <ImfHeader.h>
#include <algorithm>
#include <cmath>
#include <ImathColor.h>
#include <ImathColorAlgo.h>
#include <ImfChannelList.h>
#include <ImfOutputFile.h>
#include <ImfInputFile.h>
#include <half.h>
#include <string>
#include <vector>
#include <stdio.h>
#include <stdlib.h>
#include <sstream>
#include <fstream>
#define _CRT_SECURE_NO_WARNINGS
using namespace Imf;
using namespace std;
using namespace IMATH_NAMESPACE;
// 读入exr文件,并保存为allpixel数组
void readpixel(string filename) {
try {
// 不能用rgbainputfile 读出来就是rgb的
InputFile file(filename.c_str());
//读通道到缓冲区
FrameBuffer frameBuffer;
Box2i dw = file.header().dataWindow();
int width = dw.max.x - dw.min.x + 1;
int height = dw.max.y - dw.min.y + 1;
std::cout << width << " " << height << std::endl;
// 通道名称
vector<string> channelnames;
const ChannelList& channels = file.header().channels();
int numChannels = 0;
bool if_float = true;
// 分通道分配每个channel给数组
vector<float*> allpixels; // 最后存入的数组
for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
{
channelnames.push_back(i.name());
const Channel& channel = i.channel();
const PixelType& pixelType = channel.type;
numChannels++;
// 判断是HALF还是float数据类型,如果是HALF就转成float再存储
if (pixelType == Imf::HALF) {
std::cout << "数据类型:half"<<endl;
half* onechannel = new half[width * height];
// 存入channelpixels数组里
frameBuffer.insert(i.name(), Slice(HALF, (char*)(&onechannel[0] -
dw.min.x - dw.min.y * width),
sizeof(half),
width * sizeof(half),
1, 1, // x/y sampling
0.0));
// 将half转成float
float* floatchannelpixels = new float[width*height];
for (size_t i = 0; i < width * height; ++i) {
// f16_to_f32 自定义函数,转成float类型
floatchannelpixels[i] = f16_to_f32(onechannel[i]);
}
allpixels.push_back(floatchannelpixels);
}
else if (pixelType == Imf::FLOAT) {
std::cout << "数据类型:float" << endl;
float* onechannel = new float[width * height];
frameBuffer.insert(i.name(), Slice(FLOAT, (char*)(&onechannel[0] -
dw.min.x - dw.min.y * width),
sizeof(float),
width * sizeof(float),
1, 1, // x/y sampling
0.0));
allpixels.push_back(onechannel);
}
}
// 要在分配之后设置以下两句,才开始读
file.setFrameBuffer(frameBuffer);
file.readPixels(dw.min.y, dw.max.y);
}
catch (const std::exception& e) {
std::cerr << "error reading image file hello.exr:" << e.what() << std::endl;
}
}
int main() {
string filename = "16bitExr.exr";
readpixel(filename);
}
float转half和half转float函数
如下:
float f16_to_f32(half __x) {
unsigned short n = *((unsigned short*)&__x);
unsigned int x = (unsigned int)n;
x = x & 0xffff;
unsigned int sign = x & 0x8000; //符号位
unsigned int exponent_f16 = (x & 0x7c00) >> 10; //half指数位
unsigned int mantissa_f16 = x & 0x03ff; //half小数位
unsigned int y = sign << 16;
unsigned int exponent_f32; //float指数位
unsigned int mantissa_f32; //float小数位
unsigned int first_1_pos = 0; //(half小数位)最高位1的位置
unsigned int mask;
unsigned int hx;
hx = x & 0x7fff;
if (hx == 0) {
return *((float*)&y);
}
if (hx == 0x7c00) {
y |= 0x7f800000;
return *((float*)&y);
}
if (hx > 0x7c00) {
y = 0x7fc00000;
return *((float*)&y);
}
exponent_f32 = 0x70 + exponent_f16;
mantissa_f32 = mantissa_f16 << 13;
for (first_1_pos = 0; first_1_pos < 10; first_1_pos++) {
if ((mantissa_f16 >> (first_1_pos + 1)) == 0) {
break;
}
}
if (exponent_f16 == 0) {
mask = (1 << 23) - 1;
exponent_f32 = exponent_f32 - (10 - first_1_pos) + 1;
mantissa_f32 = mantissa_f32 << (10 - first_1_pos);
mantissa_f32 = mantissa_f32 & mask;
}
y = y | (exponent_f32 << 23) | mantissa_f32;
return *((float*)&y);
}
half f32_to_f16(float __x) {
unsigned int x = *((unsigned int*)&__x);
unsigned int sign = x & 0x80000000;
unsigned int exponent_f32 = (x & 0x7f800000) >> 23;
unsigned int mantissa_f32 = x & 0x007fffff;
unsigned short y = (unsigned short)(sign >> 16);
unsigned int exponent_f16;
unsigned int mantissa_f16;
unsigned int hx;
hx = x & 0x7fffffff;
if (hx < 0x33800000) {
return *((half*)&y);
}
if (hx > 0x7f800000) {
y = 0x7e00;
return *((half*)&y);
}
if (hx >= 0x477fffff) {
y |= 0x7c00;
return *((half*)&y);
}
mantissa_f16 = mantissa_f32 >> 13;
if (exponent_f32 > 0x70) {
exponent_f16 = exponent_f32 - 0x70;
}
else {
exponent_f16 = 0;
mantissa_f16 |= 0x400;
mantissa_f16 = mantissa_f16 >> (0x71 - exponent_f32);
}
y = y | (unsigned short)(exponent_f16 << 10) | (unsigned short)mantissa_f16;
return *((half*)&y);
}
将float数组写入EXR文件
如下:
void float2exr(float* floatdata,int round) {
// floatdata按通道顺序保存了多通道的数据
int height = 720;
int width = 1280;
string filename = "out.exr";
// 设置通道
string* channelnames = new string[3]{ "R","G","B" }; // 通道名称
int channelnum = 3; // 通道数
Header header(width, height);
Box2i data_window(V2i(0, 0),
V2i(width - 1, height - 1));
header.dataWindow() = data_window; //beuark.
for (int i = 0; i < channelnum; i++) {
header.channels().insert(channelnames[i], Channel(HALF));
}
// float 转half保存到halfdata中
vector<half*> halfdata;
for (int i = 0; i < channelnum; i++) {
half* onechannel = new half[width * height];
halfdata.push_back(onechannel);
}
//half* halfdata = new half[channelnum * height * width];
for (int i = 0; i < channelnum; i++) {
int offset = 0;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
{
halfdata[i][offset] = f32_to_f16(floatdata[i*width*height+offset]);
offset++;
}
}
}
}
//offset = 0;
//halfdata -= channelnum * offset;
// halfdata输入buffer里
FrameBuffer fb;
for (int i = 0; i < channelnum; i++) {
fb.insert(channelnames[i], Slice(HALF, (char*)(&halfdata[i][0]-data_window.min.x-data_window.min.y*width), sizeof(half),
width * sizeof(half)));
}
// 写文件
try {
OutputFile outfile(filename.c_str(), header);
outfile.setFrameBuffer(fb);
//y_count() rows to write
outfile.writePixels(height);
}
catch (const std::exception& e) {
std::cerr << "Unable to write image file " << filename << " : " << e.what() << std::endl;
}
//release the memory, but come back to the real address before.
//delete[](halfdata + channelnum * offset);
}
将EXR文件按通道写入txt文件:
void exr2txt(string filename) {
try {
// 不能用rgbainputfile 读出来就是rgb的
InputFile file(filename.c_str());
Box2i dw = file.header().dataWindow();
int width = dw.max.x - dw.min.x + 1;
int height = dw.max.y - dw.min.y + 1;
std::cout << width << " " << height << std::endl;
// 通道名称
vector<string> channelnames;
const ChannelList& channels = file.header().channels();
int numChannels = 0;
bool if_float = true;
for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
{
channelnames.push_back(i.name());
const Channel& channel = i.channel();
const PixelType& pixelType = channel.type;
numChannels++;
std::cout << "数据类型:";
if (pixelType == Imf::HALF) {
if_float = false;
}
else if (pixelType == Imf::FLOAT) {
if_float = true;
}
}
//std::cout << numChannels << std::endl;
// 为通道分配缓冲区
vector<half*> allpixels;
for (int i = 0; i < numChannels; i++) {
half* onechannel = new half[width * height];
allpixels.push_back(onechannel);
}
//读通道到缓冲区
FrameBuffer frameBuffer;
// 每个通道是buffer里的一个切片
for (int i = 0; i < numChannels; i++) {
frameBuffer.insert(channelnames[i], Slice(HALF, (char*)(&allpixels[i][0] -
dw.min.x - dw.min.y * width),
sizeof(half),
width * sizeof(half),
1, 1, // x/y sampling
0.0));
}
file.setFrameBuffer(frameBuffer);
file.readPixels(dw.min.y, dw.max.y);
for (int c = 0; c < numChannels; c++) {
FILE* fp;
string filename = "../channeldata/" + channelnames[c] + ".txt";
cout << filename << endl;
if ((fp = fopen(filename.c_str(), "wb")) == NULL) {
printf("cant open the file");
exit(0);
}
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
float p = f16_to_f32(allpixels[c][i * width + j]);
p = clamp(p, 0, 1);
//cout << p << ",";
fprintf(fp, "%f,", p);
}fprintf(fp, "\n");
}
fclose(fp);
}
}
catch (const std::exception& e) {
std::cerr << "error reading image file hello.exr:" << e.what() << std::endl;
}
}
将txt文件写入EXR:
void txt2exr(int round) {
string path = "D:\\DataSets\\Save\\result16\\" + to_string(round);
float* datar, * datag, * datab;
int height = 720;
int width = 1280;
datar = new float[height * width];
datag = new float[height * width];
datab = new float[height * width];
ifstream infiler(path + "r.txt");
int k = 0;
int offset = 0;
while (infiler)
{
//cout << k++ << endl;
string s;
if (!getline(infiler, s)) break;
istringstream ss(s);
vector <string> record;
while (ss)
{
string s;
if (!getline(ss, s, ',')) break;
datar[offset] = (atof(s.c_str()));
offset++;
//cout << atof(s.c_str()) << endl;
}
}
ifstream infileg(path + "g.txt");
k = 0;
offset = 0;
while (infileg)
{
//cout << k++ << endl;
string s;
if (!getline(infileg, s)) break;
istringstream ss(s);
vector <string> record;
while (ss)
{
string s;
if (!getline(ss, s, ',')) break;
datag[offset] = (atof(s.c_str()));
offset++;
}
}
offset = 0;
ifstream infileb(path + "b.txt");
k = 0;
while (infileb)
{
//cout << k++ << endl;
string s;
if (!getline(infileb, s)) break;
istringstream ss(s);
vector <string> record;
while (ss)
{
string s;
if (!getline(ss, s, ',')) break;
datab[offset] = (atof(s.c_str()));
offset++;
}
}
float* floatdata = new float[3 * height * width];
int os = 0;
for (int i = 0; i < offset; i++) {
floatdata[os] = datar[i];
os++;
}
for (int i = 0; i < offset; i++) {
//cout << data[i] << endl;
floatdata[os] = datag[i];
os++;
}
for (int i = 0; i < offset; i++) {
//cout << data[i] << endl;
floatdata[os] = datab[i];
os++;
}
float2exr(floatdata, round);
}