色调映射

色调映射是在有限动态范围媒介上近似显示高动态范围图像的一项计算机图形学技术。打印结果、CRT 或者 LCD 显示器以及投影仪等都只有有限的动态范围。

本质上来讲，色调映射是要解决的问题是进行大幅度的对比度衰减将场景亮度变换到可以显示的范围，同时要保持图像细节与颜色等对于表现原始场景非常重要的訊息。

根据应用的不同，色调映射的目标可以有不同的表述。在有些场合，生成“好看”的图像是主要目的，而在其它一些场合可能会强调生成尽可能多的细节或者最大的图像对比度。在实际的渲染应用中可能是要在真实场景与显示图像中达到匹配，尽管显示设备可能并不能够显示整个的亮度范围。

在最近几年中已经开发了各种各样的色调映射算法，其中一个简单的色调映射滤波器例子是 ，这个函数将场景在  域内的 radiance 值  映射到显示输出范围 。

另外一组更加复杂的算法是基于对比度或者梯度域的方法，这些算法的侧重点在于对比度的保持而不是亮度的映射，这种方法的思路起源于人眼对于对比度或者不同亮度区域的亮度比例最为敏感。这种色调映射由于较好地保存了对比度细节，所以通常会产生非常锐利的图像，但是这样做的代价是使得整体的图像对比度变得平缓。这种色调映射方法的例子包括：梯度域高动态范围压缩以及高动态范围图像感知框架（有一种色调映射就是这种框架的一个应用）。

一个有趣的高动态范围图像色调映射实现方法是从anchoring theory of lightness perception 得到的灵感。这个理论全面地解释了人类视觉系统中如 lightness constancy 以及 its spectacular failures 这些对于感知图像非常重要部分的特点。这个色调映射方法（色调重建中的亮度感知）的核心概念是将高动态范围图像分解成照明一致的区域或结构以及计算局部亮度值。根据各个区域亮度的比例进行合并，从而计算图像的纯亮度值。其中尤其重要的是亮度定位（anchoring）——将照明的亮度对应于已知的亮度值，也就是说哪个亮度值在场景中感知为白色。这种色调映射实现方法不影响局部对比度，并且由于对亮度进行线性处理所以也保留了高动态图像的自然颜色。

Photographic 演算法
在此演算法中，主要分為兩個步驟來改變場景中的亮度，第一個步驟為整個場景的亮度改變(global)，就如同在拍攝景物的時候需要調整相機的曝光值；第2個步驟為局部區塊的亮度改變(local)，這個步驟使用到了局部加亮和加深(Dodging & Burning)的概念

步驟一　整個場景的亮度改變
首先，根據照片紅、綠、藍3個顏色可以計算出照片中每個像素的亮度，再來需要算出場景中的關鍵值(key value)，在這裡關鍵值可以代表一個場景整體來說是亮的還是暗的，如果照片是白天拍攝的，就可以說其關鍵值是高的，若是在晚上拍攝的，則關鍵值會較低。在這裡我們可以假設關鍵值會與場景中亮度的對數平均值相關。
我們以來估計場景的關鍵值。

: 一個極小值，避免在算黑色像素的時候會遇到的情況
算出場景中的關鍵值後，我們要將此關鍵值重新調整到中間值，調整方法為

其中為調整後新的關鍵值。

調整完後，會發現此方法尚無法解決場景過亮的地方會超出所能顯示的顏色範圍的問題。所以下一步是要將亮度高的地方壓縮。

其中場景中亮度最高的值。
由上述式子可以發現亮度接近最大亮度的像素會被壓縮成，而亮度較低的地方壓縮倍數則較少，如此即可保留低對比區域的細節，並且將高亮度的區域壓縮至合理範圍。

步驟二 　局部區塊的亮度
在使用完simple operator後，對於動態範圍很高的影像，可以發現有些景物的細節還是無法被保留，所以此演算法又提出了第二個步驟- 局部加亮與加深(Dodging & Burning)的作法。此作法是參考早期沖洗相片時的一個常用技巧。
早期在沖洗底片的時候，為了能讓照片中的某些區域曝光高一點，有些區域低一點，所以使用加亮和加深(Dodging & Burning)的技巧，在沖洗照片的過程中，將一些照片中的區域用紙張或是木頭遮擋住，來調整不同區域的亮暗，此作法可以提升原本暗處的亮度或是讓過曝的地方能夠變暗一點，以看清楚照片中的細節。
通常加亮與加深是使用在一個被高對比度包圍的影像區域上，所以此方法首先要先找到對於每個像素而言，不存在強烈對比的最大區域。
找尋方法為，將兩個不同變異數的高斯函數套在影像上，得出兩個結果 和　，代表了給定某一個像素下，以此像素為圓心，在一個半徑內的亮度平均值，而計算所使用的高斯函數的變異數較大，所以得出的結果為在一個較大半徑內的平均值
算法如下：

並以函數來憑斷套用這兩個不同高斯後的差別。當所計算區域內的亮度變化很小的時候，的差異很小，也就很小；當所計算區域內的亮度有很明顯差異的時候，通常也就是位於物體邊界的時候，會很大。

其中代表scale，此步驟會重複多次在不同的scale上，每次都會選用更大的變異數值。從最小的scale開始找起，目標是要找到最接近臨界值，但是又小於臨界值的scale。

最後的亮度可以表示為

其中為滿足小於臨界值下的。
值得注意的是，在使用此演算法的時候，如果選擇的scale太大，也就是說每次變異數都變化很大的話或是臨界值選擇太大，都有可能會造成無法選擇到正確的亮度無變化的最大區域，導致演算法估計錯誤，最後影像會有明顯黑邊。

實作Photographic 演算法
以下為使用Matlab所實作的Photographic 演算法之程式碼
function rgb = tonemap_p( hdr )
    % HDR need be double format 
    %步驟1,調整整個場景的亮度  
    a = 0.6;%關鍵值設定 
    epsilon = 0.05; 
 
    %利用rgb計算照片亮度 
    lum_w = 0.27 * hdr(:,:,1) + 0.67 * hdr(:,:,2) + 0.06 * hdr(:,:,3); 
    image_size = size( hdr );
    [height, width, channel] = size(hdr)
    %計算L_w_bar(x,y) 
    sum_all = sum(sum(log(0.00000001+ lum_w)));

    N = height * width;
    lum_white = 1e20; 
    lum_w_bar = double( exp (sum_all / N) ); 
 
    %計算L_d(x,y) 
    lum = a / lum_w_bar * lum_w; 
    
    lum_add1 = 1 + lum;
    luma_d_1 = lum .* (1 + lum ./ lum_white ./ lum_white) ./lum_add1;
    
    %步驟二：加亮與加深(Dodging & Burning) 
    phi = 8; 
    %計算兩個不同變異數大小的高斯函數 
    for i = 1: height 
        for j = 1: width 
            for k = 1: 8 
                s = 1 * 1.6 ^ k; 
                alpha1 = 0.35; 
                R1(i, j, k) = exp( -( i ^ 2 + j ^ 2) / ( alpha1 ) ^ 2 ) / ( pi * ( alpha1 * s ) ^ 2 ); 
                alpha2 = 0.35 * 1.6; 
                R2(i, j, k) = exp( -( i ^ 2 + j ^ 2) / ( alpha2 ) ^ 2 ) / ( pi * ( alpha2 * s ) ^ 2 ); 
            end 
        end 
    end 
    %將亮度與高斯函數做卷積 
    for k = 1: 8 
        V1(:,:,k) = conv2( lum_w, R1(:,:,k)); 
        V2(:,:,k) = conv2( lum_w, R2(:,:,k)); 
    end 
 
    %計算函數V(x, y, s) 
    for i = 1: height 
        for j = 1: width 
            for k = 1:8 
                V(i, j, k) = ( V1(i, j, k) - V2(i, j, k)) / (2 ^ phi * a / (k ^ 2) + V1(i, j, k)); 
            end 
        end 
    end 
 
    %找尋符合V小於臨界值epsilon的scale 
    for i = 1: height 
        for j = 1: width 
            for k = 1:8 
                if abs(V(i, j, k)) < epsilon 
                    V1_new(i, j) = V(i, j, k); 
                end 
            end 
        end 
    end 
 
    %計算新的亮度 
    for i = 1: height 
        for j = 1: width 
            lum_d2(i, j) = lum_w(i, j) / (1 + V1_new(i, j)); 
        end 
    end 
 
    %將rgb影像轉到hsv的系統後,改變亮度大小,最後輸出成色調映射後的結果 
    hsv = rgb2hsv( hdr ); 
    new_img = cat(3,hsv(:,:,1),hsv(:,:,2),lum_d2);    
    rgb = hsv2rgb( new_img); 
end

图库

参考文献
 Kate Devlin, Alan Chalmers, Alexander Wilkie, Werner Purgathofer. "STAR Report on Tone Reproduction and Physically Based Spectral Rendering" in Eurographics 2002. DOI: 10.1145/1073204.1073242
 Raanan Fattal, Dani Lischinski, Michael Werman. "梯度域高动态范围压缩" 
 Rafal Mantiuk, Karol Myszkowski, Hans-Peter Seidel. "高动态范围图像对比度处理的感知架构"
 Alan Gilchrist. "An Anchoring Theory of Lightness Perception".
 Grzegorz Krawczyk, Karol Myszkowski, Hans-Peter Seidel. "高动态范围图像色调重现中的亮度感知" 
 Reinhard, Erik, et al. "Photographic tone reproduction for digital images." ACM transactions on graphics (TOG) 21.3 (2002): 267-276.

外部链接
 pfstmo: 色调映射算子的实现 
 exrtools: OpenEXR 图像处理工具集合 （包括一些色调映射算子）

色调映射算法
 数字图像的摄影色调重现
 高动态范围图像色调重现中的亮度感知 
 高动态范围图像对比度处理 
 高动态范围图像显示的快速双边滤波 
 梯度域高动态范围压缩 
 色调映射算子技术的实现

计算机图形学