自動白平衡

白平衡是電視攝像領域一個非常重要的概念,通過它可以解決色彩還原和色調處理的一系列問題。白平衡是隨着電子影像再現色彩真實而產生的,在專業攝像領域白平衡應用的較早,現在家用電子產品(家用攝像機、數碼照相機)中也廣泛地使用,然而技術的發展使得白平衡調整變得越來越簡單容易,但許多使用者還不甚瞭解白平衡的工作原理,理解上存在諸多誤區。它是實現攝像機圖像能精確反映被攝物的色彩狀況,有手動白平衡和自動白平衡等方式,本文簡要的介紹了幾種自動白平衡算法。

一、原始的灰度世界算法

  灰度世界算法(Gray World)是以灰度世界假設爲基礎的,該假設認爲對於一幅有着大量色彩變化的圖像, R、 G、 B 三個分量的平均值趨於同一個灰度K。一般有兩種方法來確定該灰度。

(1)直接給定爲固定值, 取其各通道最大值的一半,即取爲127或128;

(2)令 K = (Raver+Gaver+Baver)/3,其中Raver,Gaver,Baver分別表示紅、 綠、 藍三個通道的平均值。

算法的第二步是分別計算各通道的增益:

Kr=K/Raver;

      Kg=K/Gaver;

Kb=K/Baver;

算法第三步爲根據Von Kries 對角模型,對於圖像中的每個像素R、G、B,計算其結果值:

Rnew = R * Kr;

       Gnew = G * Kg;

       Bnew = B * Kb;

對於上式,計算中可能會存在溢出(>255,不會出現小於0的)現象,處理方式有兩種。

a、 直接將像素設置爲255,這可能會造成圖像整體偏白。

b、 計算所有Rnew、Gnew、Bnew的最大值,然後利用該最大值將將計算後數據重新線性映射到[0,255]內。實踐證明這種方式將會使圖像整體偏暗,建議採用第一種方案。

一般來說,灰度世界算法的效果還是比較好的呢,並且該算法的執行速度非常之快,目前也存在了不少對該算法進行改進的效果,有時間我在整理一下。

這裏寫圖片描述

二、完美反射算法

當初寫這個代碼的時候的一些參考文獻一下子也找不到了,就從已經寫好的代碼中描述下該算法的過程吧。

原理:完美全反射理論perfect Reflector假設圖像上最亮點就是白點,並以此白點爲參考對圖像進行自動白平衡,最亮點定義爲R+G+B的最大值,具體編碼步驟如下:

(1)計算每個像素的R\G\B之和,並保存到一臨時內存塊中。

    for (Y = 0; Y < Height; Y++)
{
    Pointer = bmp.Pointer + Y * Stride;
    for (X = 0; X < Width; X++)
    {
        Sum = (short)(*(Pointer) + *(Pointer + 1) + *(Pointer + 2));     // R+G+B
        HistRGB[Sum]++;
        *SumP = (short)Sum;
        Pointer += 3;
        SumP++;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
 (2)按R+G+B值的大小計算出其前10%或其他Ratio的白色參考點的的閾值T。
  • 1
    for (Y = 767; Y >= 0; Y--)
{
    Sum += HistRGB[Y];
    if (Sum > Width * Height * Ratio / 100)
    {
        Threshold = Y;
        break;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
(3)遍歷圖像中的每個點,計算其中R+G+B值大於T的所有點的R\G\B分量的累積和的平均值。
  • 1
    for (Y = 0; Y < Height; Y++)
{
    Pointer = bmp.Pointer + Y * Stride;
    for (X = 0; X < Width; X++)
    {
        if (*SumP > Threshold)
        {
            AvgB += *Pointer;
            AvgG += *(Pointer + 1);
            AvgR += *(Pointer + 2);             // 爲獲得增益做準備
            Amount++;
        }
        Pointer += 3;
        SumP++;
    }
}
AvgB /= Amount;
AvgG /= Amount;
AvgR /= Amount;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

   (4)對每個點將像素量化到[0,255]之間。
  

for (Y = 0; Y < Height; Y++)
{
    Pointer = bmp.Pointer + Y * Stride;
    for (X = 0; X < Width; X++)
    {
        Blue = *Pointer * MaxValue / AvgB;                                   // 另外一種算法需要先計算不抑制重新計算的RGB的範圍,然後求RGB的最大值,如果最大值大於255,則所有的結果都要除以最大值在乘以255,但實際表明該算法、   不合適;
        Green = *(Pointer + 1) * MaxValue / AvgG;
        Red = *(Pointer + 2) * MaxValue / AvgR;
        if (Red > 255) Red = 255; else if (Red < 0) Red = 0;                // 這裏需要判斷,因爲RGB空間所有的顏色轉換到YCbCr後,並不是填充滿了0-255的範圍的,反轉過去就會存在一些溢出的點。
        if (Green > 255) Green = 255; else if (Green < 0) Green = 0;        // 編譯後應該比三目運算符的效率高
        if (Blue > 255) Blue = 255; else if (Blue < 0) Blue = 0;
        *Pointer = (byte)Blue;
        *(Pointer + 1) = (byte)Green;
        *(Pointer + 2) = (byte)Red;
        Pointer += 3;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

這裏寫圖片描述
從效果上看,該算法應該比灰度世界的效果要好些,但是也還是受到Ratio這個參數的影像。特別是第二個圖片,過高的Ration導致圖片過於泛白。這個問題可以還是最後量化的哪一步引起的,我會抽空再研究一下其他的量化方式,儘量降低Ration的影響。
針對上述的第二步,看到很多matlab和VC的代碼,有很多人居然先用快速排序對累加後的數據進行排序,然後再取其10%的最大值,對圖像的數據進行排序,可能就是再快速的排序都快不起來吧,看到這,也許全國人民都笑了。
三、動態閾值算法
參考論文:A Novel Automatic White Balance Method For Digital Still Cameras
同經典的一些算法相同,算法分爲兩個步驟:白點檢測和白點調整。
白點檢測:
(1)爲了增強算法的魯棒性,原文將圖像分成12部分,其中寬高比爲4:3,關於這一點,我認爲不合理,對圖像不是通用的,後文再說。
(2)計算每個區域的Cb\Cr分量的平均值Mb/Mr。
(3)按下式計算每個區域的Cb\Cr分量的絕對差的累積值Db/Dr:
這裏寫圖片描述
上式中N爲每個區域的像素數。
(4)如果Db/Dr的值偏小,則我們忽略這一塊,因爲這表明這一塊的顏色分佈比較均勻,而這樣的局部對於白平衡不好。這個偏小的準則我們稍微再談。
(5)統計對於除了符合第四條的的其他區域的Mb/Mr/Db/Dr的平均值作爲整幅圖像的Mb/Mr/Db/Dr值。
        關於這一條,原文的話是:The final Mb、Mr、Db、Dr are obtained by taking the average of those regions that pass this additional step。
       我在實際中做的時候就是分別對每塊進行的,似乎效果也還不錯。
(6)按下述規則初步確定哪些點是屬於白色參考點:
這裏寫圖片描述
這裏寫圖片描述
(7)對於初步判斷已經屬於白色參考點的像素,按大小取其亮度值爲前10%的位最終確定的白色參考點。
白點調整:
     (1)計算白色參考點亮度值的平均值Raver,Gaver,Baver,(各通道分開計算)。
(2)按照以下各式計算每個通道的增益:
     這裏寫圖片描述 
     這裏寫圖片描述  
     這裏寫圖片描述  

          式中,Ymax就是YCbCr顏色空間中Y分量的在整幅圖像中的最大值。
  • 1

(3)按照以下各式計算最終每個通道的顏色值:
這裏寫圖片描述
這裏寫圖片描述
這裏寫圖片描述

      其中R/G/B爲在原始的顏色空間中的值,注意這裏要進行溢出檢測的。
  • 1

   簡單的談下白點檢測的分塊操作吧,原文把圖像分成4*3的12快,這樣做事針對於我們很多數碼照片是這個比例的,如果通用,我覺得應該用每個塊的大小來控制,比如每塊爲 100*100個像素。
這個算法的效果如下:
這裏寫圖片描述
上三圖表明:1、該算法效果非常好;2、對塊大小不太敏感,因此非常適合於自動化操作。
關於RGB到YCbCr的快速轉換,可以參考:顏色空間系列3: RGB和YCbCr顏色空間的轉換及優化算法
由於在上述鏈接的文章中,YCbCr顏色空間已經被轉換到[0,255],因此白色檢測部分的第(6)條中的sign函數就不需要了。
同樣,提供個編譯好的文件給有興趣研究該算法的朋友看看效果:
http://files.cnblogs.com/Imageshop/AutoWhiteBalance.zip
   後記:
  針對動態閾值法,很多朋友反映如果YCbCr的值量化在0到255之間的話會出現所有的像素都會被式(6)初步判斷爲白色參考點。這樣前期的工作就失去了意義,算法就變成了類似於完美反射算法那了,稍微有點不同的地方就是兩者選擇兩點的準則有所不同。雖然這樣做的最終結果還算不錯,但確實和論文的本意像違背了,後面經過實踐,如果把YCbCr的值量化在-127到128之間,式6中的Sgn同樣適用,則初步判斷爲白點的數會大量的減少,對於同一個圖片,同一個參數兩個算法的最終的效果比較如下:
   更新後的下載鏈接依舊如下,以增加了修正後的功能。
這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章