1. 程式人生 > >HDR檔案格式簡介

HDR檔案格式簡介

1、HDR簡介
    HDR的全稱是High-Dynamic Range(高動態範圍)。在此,我們先解釋一下什麼是Dynamic Range(動態範圍),動態範圍是指影象中所包含的從“最亮”至“最暗”的比值,也就是影象從“最亮”到“最暗”之間灰度劃分的等級數;動態範圍越大,所能表示的層次越豐富,所包含的色彩空間也越廣。那高動態範圍(HDR)顧名思義就是從“最亮”到“最暗”可以達到非常高的比值。   
    在日常生活中我們經常遇到這樣的情況:突然從黑暗的房間中走到陽光下,眼睛會無法睜開;清晨陽光會穿透窗簾像光柱般照射入房間;反光度較高的物體在強光下會在周圍產生光暈。以上這些生活中隨處可見的現象在有HDR以前無法在3D世界中呈現!最大的原因就在於我們使用8~16bit的整數資料,使用8~16bit的整數資料是整個圖象處理失真的關鍵點,所以我們對以往的運算方法做了以下二方面的重大改進:
    1、使用16bit、32bit的資料來提高畫素資料的精度。既然繼續使用8bit的資料來記錄畫素的特徵不能滿足HDR資料所需要的高精度運算的要求,在這種情況下,我們考慮使用16bit、32bit的資料記錄來提高畫素資料的精度都是可以的。使用了更多的資料來儲存畫素特徵之後,無論是畫素的對比度還是畫素可以體現的色彩數目都有了巨大的提高。
    2、圖象資料採用浮點資料。HDR真正的巨大變革來自於浮點資料的引入。我們可以採用浮點方式來處理和存放亮度資料,拋棄不準確的整數資料;同時計算機在引入浮點資料來儲存象素的各個引數並且在運算的全過程都使用浮點資料,這樣就可以有效的提高據的精確度。
    那麼採用HDR後動態範圍最大可以有多大呢?我們看如下的公式,就可以知道我們到底使用了HDR後動態值可以有多大,而動態值的大小直接表現了動態範圍的大小:Dynamic Range=log10(Max Intensity / Min Intensity)。公式中intensity是指強度,我們對最大亮度除以最低亮度的結果取對數,得到的結果就是動態範圍的相對數值。根據公式計算,當我們在亮度通道使用8bit的的情況下,最高亮度255,最低亮度1。那麼計算得出的動態範圍就是數值約為2.4,加上單位就是24dB。同理可以計算得出16bit 的亮度通道的動態範圍是數值約是4.8,是使用8bit亮度通道的一倍。理論上在HDR模式下,動態範圍的數值最高可以到達76.8。在NVIDIA所使用的OpenEXR中表現出來的HDR動態範圍的數值最大值約有12.0,遠遠高出單純使用16bit亮度通道的所帶來的亮度體驗,這是採用了優秀演算法的結果。OpenEXR所能實現的最大動態範圍已經超過了人眼的9,帶來了更加真實的視覺體驗。

2、HDRI檔案格式介紹(OpenEXR、Radiance RGBE、Float TIFF)


     HDRI(High-Dynamic Range Image)就是記錄採用了HDR技術的圖象資料檔案。常用的HDRI檔案有OpenEXR、Radiance RGBE、FloatTIFF三種格式。
     2.1   OpenEXR檔案格式
            OpenEXR是由工業光魔(Industrial Light & Magic)開發的一種HDR標準。OpenEXR檔案的副檔名為.exr,常見的OpenEXR檔案是FP16(16bit Float Point,也被稱為half Float Point)資料影象檔案,每個通道的資料型別是FP16,一共四個通道64bpp,每個通道1個bit位用來標誌“指數”,5個bit用來存放指數的值,10個bit存放色度座標(u,v)的尾數,其動態範圍從6.14 × 10 ^ -5到6.41 × 10 ^ 4。
           在OpenEXR的演算法裡面共使用16bit來表示光照資料。雖然看起來和使用16bit亮度通道運算位數相同,但是OpenEXR巧妙的採用了1個bit位用來標誌“指數”,5個bit用來存放指數的值,10個bit存放色度座標的尾數。這樣就輕易的解決了浮點數值由於位數少而精度不高的問題。大大的拓寬的在FP16下的動態範圍。根據實際的計算結果:在正規化的情況下OpenEXR可以提供和人眼基本相同的動態範圍,最暗到最亮是0.00006103515625(6.14 × 10 ^ -5)到65504(6.41 × 10 ^ 4),動態範圍是9.03;非正規化條件下,OpenEXR可以提供從最暗到最亮的數值從0.000000059604644775390625(5.96 × 10 ^ -8 )到65504(6.41 × 10 ^ 4),化為動態範圍表示就是12。
          下面是Still寫的OpenEXR讀寫程式碼,儲存的.exr檔案採用Zips壓縮編碼。

bool COpenExr::Load(const char fileName[], int& width, int& height, float** pixels)
{
    std::vector<float> vecpixels;
    if(!Load(fileName, width, height, vecpixels))
        return false;
 
    int num = width * height * 3;
    *pixels = new float[num];
    if(NULL == *pixels)
        return false;
   
    std::vector<float>::pointer ptr = &vecpixels[0];
    memcpy(*pixels, ptr, num * 4); 

    return true;
}

bool COpenExr::Load(const char fileName[],   int& width,   int& height,   std::vector<float> &pixels)
{
    Imf::Array<Imf::Rgba> pixelsdata;
    bool bLoad = loadImage(fileName, width, height, pixelsdata);
    if(!bLoad) return false;
    for(int y = 0; y < height; y++)
    {
        int i = y * width;
        for(int x = 0; x < width; x++)
        {
            int j = i + x;
            const Imf::Rgba &rp = pixelsdata[j];
 
            pixels.push_back( float(rp.r));
            pixels.push_back( float(rp.g));
            pixels.push_back( float(rp.b));   
        }
    }

    return true;
}

bool  COpenExr::loadImage (const char fileName[],  int& width, int& height,  Imf::Array<Imf::Rgba>& pixels)
{
    Imf::RgbaInputFile in (fileName);
    Imath::Box2i dataWindow = in.dataWindow();
    int dw, dh, dx, dy;
    width = dw = dataWindow.max.x - dataWindow.min.x + 1;
    height = dh = dataWindow.max.y - dataWindow.min.y + 1;
    dx = dataWindow.min.x;
    dy = dataWindow.min.y;

    pixels.resizeErase (dw * dh);
    in.setFrameBuffer (pixels - dx - dy * dw, 1, dw);
    try
    {
        in.readPixels (dataWindow.min.y, dataWindow.max.y);
    }catch (const exception &e)
    {
       std::cerr << e.what() << std::endl;
       return false;
    }

      return true;
}

bool COpenExr::Save(const char fileName[], int width, int height, const float* pixels)
{
    std::vector<float> vecpixels(pixels, pixels + width * height * 3);
    return Save(fileName, width, height, vecpixels);
}

bool COpenExr::Save(const char fileName[], int width, int height, const std::vector<float> pixels)
{
    Imf::Array<Imf::Rgba> pixelsdata;
    pixelsdata.resizeErase(width * height);
    for(int y = 0; y < height; y++)
    {
        int i = y * width;
        for(int x = 0; x < width; x++)
        {
            int j = i + x;
  
            half r = pixels[j * 3 ];
            half g = pixels[j * 3 + 1];
            half b = pixels[j * 3 + 2];
            pixelsdata[j] = Imf::Rgba(r, g, b);
        }
    }

    return SaveImage(fileName, width, height, pixelsdata);
}

bool COpenExr::SaveImage(const char fileName[], int width, int height, const Imf::Array<Imf::Rgba>  &pixels)
{
    Imf::RgbaOutputFile file (fileName, width, height);
    file.setFrameBuffer(pixels, 1, width);
    try
    {
         file.writePixels(height);
    }catch(const exception &e)
    {
        std::cerr<< e.what() <<std::endl;
        return false;
    }

    return true;
}
     

    2.2  Radiance RGBE檔案格式
         RGBE檔案的副檔名為.hdr,RGBE正式名稱為Radiance RGBE格式。這個本來是BR、FR等作為radiance材質的一種格式,也叫做radiance map,後來成為流行的一種HDR格式。所謂E,就是指數。Radiance RGBE檔案每個通道為8bit BYTE資料型別,4個通道一共是32 bit。RGBE可以使用RLE壓縮編碼壓縮,也可以不壓縮。由檔案頭、RGBE資料組成。
         檔案頭如下:
         型別                                  輸出格式
         char programtype[16];         //#?Radiance/n#Generated by still/n
         float gamma;                      //1.0
         float exposure;                   //1.0
         字串常量                          //FORMAT=32-bit_rle_rgbe/n/n
         int nWidth, int nHeight         //-Y nHeight +X nWidth/n

         RGBE資料與HDR FP32(RGB)相互轉換公式如下:
         1、rgbe->FP32(RGB)
             如果e為0, R = G = B = 0.0,否則:
             R = r * 2^(e – 128 - 8);
             G = g * 2^(e – 128 - 8);
             B = b * 2^(e – 128 - 8);
       
         2、FP32(RGB) -> rgbe
             v = max(R, G, B);
             如果v < 1e-32, r = g = b = e = 0, 否則:
             將v用科學計演算法表示成 v = m * 2 ^ n ( 0 < m < 1):
             r = R * m *  256.0/v;
             g = G * m *  256.0/v;
             b = B * m *  256.0/v;
             e = n + 128;

     Still注:
     1、我們一般說HDR採用FP32,指的是HDR圖象運算時候的記憶體資料型別,而Radiance RGBE檔案採用8bit BYTE型別儲存HDR資料。也就是說開啟Radiance RGBE檔案,要使用上面的公式1將Radiance RGBE檔案的8bit BYTE檔案資料轉換為FP 32的HDR記憶體資料進行運算;儲存為Radiance RGBE檔案時,要使用上面的公式2將HDR的FP32記憶體資料轉換為Radiance RGBE的8bit BYTE檔案資料進行儲存。同理,OpenEXR檔案的讀寫也存在將其FP 16的檔案資料到HDR的 FP32圖象資料的轉換;而下面將要講的Float Tiff是不需要進行資料轉換,直接將HDR的FP 32圖象資料儲存到TIFF檔案中即可。
     2、Radiance有多種檔案格式,其官方庫包含內容比較複雜,所以,實際的讀寫沒有使用其官方庫,而是使用了網路上一個簡單的C語言讀寫類,Still並對其進行了部分修改(在檔案頭寫入“Generated  by Still”)。

    2.3   FloatTiff檔案格式
          Tiff檔案的副檔名為.tif(.tiff),FloatTiff每個通道為FP32(32bit Float Point)型別,一共3個通道96bpp。用Tiff檔案儲存HDR資料,直接將HDR的FP32儲存到TIFF檔案中,有官方庫可以利用。下面是Still寫的程式碼樣例,HDR資料我採用的是LZW壓縮編碼:   
   
bool  CFloatTiff::Load(const char fileName[], int& width, int& height, float** pixels)
{
    TIFF* fp = NULL;
    if((fp = TIFFOpen(fileName, "r")) == NULL)
        return false;
 
    //獲取資訊
    uint16 bps,  spp, datatype, photometric, compression, planarconfig, fillorder;
 
    //每個通道佔據的資料位數
    if( (TIFFGetField(fp, TIFFTAG_BITSPERSAMPLE, &bps) == 0) || (bps != 32))
        return false;

    //每個象素的通道數目
    if((TIFFGetField(fp, TIFFTAG_SAMPLESPERPIXEL, &spp) == 0) || (spp != 3))
        return false;

    //每個通道的資料型別
    if((TIFFGetField(fp, TIFFTAG_SAMPLEFORMAT, &datatype) == 0) || (datatype != AMPLEFORMAT_IEEEFP))
        return false;

    //影象的資料採用的顏色模型
    if((TIFFGetField(fp, TIFFTAG_PHOTOMETRIC, &photometric) == 0) || (photometric != PHOTOMETRIC_RGB))
        return false;

    TIFFGetField(fp, TIFFTAG_IMAGEWIDTH, &width);
    TIFFGetField(fp, TIFFTAG_IMAGELENGTH, &height);

    int num = width * height * 3;
    *pixels = new float[num];
    if(NULL == *pixels)
        return false;
 
    if( TIFFReadEncodedStrip(fp, 0, *pixels, width * height * 3 * 4) == -1)
        return false;
 
    TIFFClose(fp);

    return true;
}

bool  CFloatTiff::Save(const char fileName[], int width, int height, const float* pixels)
{
    if(NULL == pixels)
        return false;
 
    TIFF *fp = NULL;
 
    if((fp = TIFFOpen(fileName, "w")) == NULL)
        return false;

    TIFFSetField(fp, TIFFTAG_IMAGEWIDTH, width);
    TIFFSetField(fp, TIFFTAG_IMAGELENGTH, height);
    TIFFSetField(fp, TIFFTAG_COMPRESSION, COMPRESSION_LZW);//COMPRESSION_DEFLATE;
    TIFFSetField(fp, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
    TIFFSetField(fp, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
    TIFFSetField(fp, TIFFTAG_BITSPERSAMPLE, 32);
    TIFFSetField(fp, TIFFTAG_SAMPLESPERPIXEL, 3);
    TIFFSetField(fp, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP);

    if(TIFFWriteEncodedStrip(fp, 0, const_cast<float*>(pixels), width * height * 3 * 4) == -1)
       return false;

    TIFFClose(fp);

    return true;
}  


Still注:
    1、這篇文章的基礎知識大部分來自:《光與影的魔術棒——HDR技術解析》 
http://www.cqumzh.cn/topic_show.php?tid=200271
    2、這段時間工作比較忙,關於OpenEXR檔案格式的詳細介紹需要翻譯相關文件,而且這部分內容是05年接觸的,重新總結需要一些時間;還有HDR合成、ToneMapping方面的技術下次再奉上。



Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=609464

 

相關推薦

HDR檔案格式簡介

1、HDR簡介    HDR的全稱是High-Dynamic Range(高動態範圍)。在此,我們先解釋一下什麼是Dynamic Range(動態範圍),動態範圍是指影象中所包含的從“最亮”至“最暗”的比值,也就是影象從“最亮”到“最暗”之間灰度劃分的等級數;動態範圍越大,所能表示的層次越豐富,所包含的色彩空

GZIP檔案格式簡介

由於最近用到了gzip格式相關的東西,所以網上找找可用的資料。 本文轉帖自:http://blog.chinaunix.net/u/22878/showart_374215.html GZIP最早由Jean-loup Gailly和Mark Adler建立,用於UNIX系統

sam檔案格式簡介

簡介 檔案字尾名:.sam bwa、Bowtie2是現下最流行的短序列比對軟體,SAM(Sequence Alignment/Map)格式是一種通用的比對格式,用來儲存reads到參考序列的比對資訊。 SAM是一種序列比對格式標準,由sanger制定,是以TAB為分割符的文

支援檔案格式HDR, OpenEXR, 檔案格式轉換

一個在linux 下使用的強大圖形工具 在 Ubuntu 上挺好使。 幾個例子 1. 看當前檔案下的所有hdr檔案 pfsv *.hdr 2. 把所有HDR轉換成OpenEXR for img in *.hdr; do pfsin ${img} | pfso

編碼格式簡介:ASCII碼、ANSI、GBK、GB2312、GB18030和Unicode、UTF-8,BOM頭

family 用兩個 圖片 and 正是 全球化 asc 即使 little 編碼格式簡介:ASCII碼、ANSI、GBK、GB2312、GB18030和Unicode、UTF-8,BOM頭 二進制: 只有0和1。 十進制、十六進制、八進制: 計算機其實挺笨的,它只

py3學習-----編碼格式簡介

兩個 -- ascii 一個 字節 格式 使用 防止亂碼 utf-8 ascii:英文8位一個字節; unicode:英文32位四個字節;中文32位四個字節; utf-8:英文8位一個字節;中文24位三個字節; gbk:英文8位一個字節;中文16位兩個字節; 1.各個編碼之

hive:資料型別及檔案格式

Hive的資料型別     Hive 提供了基本資料型別和複雜資料型別 1.1 原始資料型別 整型 TINYINT — 微整型,只佔用1個位元組,只能儲存0-255的整數。 SMALLINT– 小整型,佔用2個位元組,儲存範圍–327

ini檔案格式

ini檔案定義 https://en.wikipedia.org/wiki/INI_file The INI file format is an informal standard for configuration files for some platforms or software. INI

MATLAB對ply檔案格式的讀取和顯示

轉自:https://blog.csdn.net/lafengxiaoyu/article/details/60574150 在網上搜索這個題目可以找到一些類似的文章,其來源大致都是http://people.sc.fsu.edu/~jburkardt/m_src/ply_io/ply_io.h

如何利用winrar製作自解壓,自動執行檔案格式的壓縮包

操作提前:電腦安裝WinRAR軟體。 將用來製作的資料放在資料夾內,然後用Ctrl+A全選該資料夾下的檔案。 單擊滑鼠右鍵,然後選擇“新增到壓縮檔案”選項。 在開啟的對話方塊“常規”選項卡中,單擊“壓縮方式”下拉框選擇合適的壓縮方式,並將壓縮選項下的“建立自解壓格式壓縮檔案”選項勾選,這時候會發現“

3d列印模型為什麼檔案格式必須是stl和stp的?

https://www.sohu.com/a/197115674_425589   3D列印需要有3D立體圖,3D立體圖有很多格式,不同的軟體做出來的格式是不同的。比如常見的3D列印格式有:STL、STP、IGS、OBJ、BREP、MAX、3DM、3DS、X_T、SKP、SLDPR

pcd,obj,mtl檔案格式解析

pcd,obj,mtl檔案格式解析 pcd檔案解析 PCD檔案格式並非白費力氣地做重複工作,現有的檔案結構因本身組成的原因不支援由PCL庫引進n維點型別機制處理過程中的某些擴充套件,而PCD檔案格式能夠很好地補足這一點。PCD不是第一個支援3D點雲資料的檔案型別,尤其是計算機圖形

PE檔案格式詳解(六)

0x00 前言   前面兩篇講到了輸出表的內容以及涉及如何在hexWorkShop中找到輸出表及輸入DLL,感覺有幾個地方還是沒有理解好,比如由資料目錄表DataDirectory[16]找到輸出表表後以為找到輸入DLL就完了,其實這一流程的最終功能是通過輸入DLL找到輸入DLL呼叫的函

PE檔案格式學習(二):總體結構

1.概述 PE檔案分為幾個部分,分別是: DOS頭 DOS Stub NT頭(PE頭) 檔案頭 可選頭 區段頭(一個數組,每個元素都是一個結構體,稱之為IMAGE_SECTION_HEADER) .text .rdata .data .rs

PE檔案格式學習(三):匯出表

1.回顧 上篇文章中介紹過,可選頭中的資料目錄表是一個大小為0x10的陣列,匯出表就是這個陣列中的第一個元素。 我們再回顧下資料目錄表的結構體: struct _IMAGE_DATA_DIRECTORY {     DWORD VirtualAddress;    

PE檔案格式學習(一):概述

1.PE檔案簡介 PE檔案格式是Windows系統中應用最廣泛的檔案格式之一,我們常見的可執行檔案.exe、動態連結庫.dll以及驅動檔案.sys等都是PE檔案格式的。 可以通過十六進位制工具如010editor檢視PE檔案,可以看到PE檔案都有一個共同的特點,就是它們的最開頭都是4D5A,也就是ASCI

PE檔案格式學習(十三):載入配置表

1.介紹 載入配置表早期是用於描述當PE檔案頭或PE可選頭無法描述或者因為太大而無法描述的各種功能。 後來以XP及以後的系統主要是為了儲存SEH控制代碼,稱為安全結構化異常處理程式列表,如果SEH異常處理沒有經過註冊,在載入配置表中沒有控制代碼,這個異常處理就不會被執行。 具體的例子就不演示了,看起來只要是

PE檔案格式學習(十四):繫結匯入表

1.介紹 繫結匯入表的作用是加快程式的啟動速度,一個PE程式在啟動時會去載入匯入表中的dll檔案,並將匯入表的FirstThunk指向的陣列填入函式的真實地址,這需要耗去時間,繫結匯入表中儲存了匯入函式的真實地址,所以當PE在啟動時系統檢測到有繫結匯入表,就會直接將地址填入FirstThunk裡,這樣就省去

資料基礎---《利用Python進行資料分析·第2版》第6章 資料載入、儲存與檔案格式

之前自己對於numpy和pandas是要用的時候東學一點西一點,直到看到《利用Python進行資料分析·第2版》,覺得只看這一篇就夠了。非常感謝原博主的翻譯和分享。 訪問資料是使用本書所介紹的這些工具的第一步。我會著重介紹pandas的資料輸入與輸出,雖然別的庫中也有不少以此為目的的工具

ini配置檔案格式

 程式沒有任何配置檔案,那麼它對外是全封閉的,一旦程式需要修改一些引數必須要修改程式程式碼本身並重新編譯,為了讓程式出廠後還能根據需要進行必要的配置,所以要用配置檔案;配置檔案有很多種,如INI配置檔案,XML配置檔案,cfg配置檔案,還有就是可以使用系統登錄檔等。  &nb