c++读取EXR数据

c++安装OpenEXR库(windows下)-CSDN博客

在配置完OpenEXR库后,就能读取、写入EXR数据。

目录

读取多通道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);
}

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值