一、概念
什么是白平衡呢?白平衡就是針對不同色溫條件下,通過調整攝像機內部的色彩電路使拍攝出來的影像抵消偏色,更接近人眼的視覺習慣。白平衡可以簡單地理解為在任意色溫條件下,攝像機鏡頭所拍攝的標準白色經過電路的調整,使之成像后仍然為白色。這是一種經常出現(xiàn)的情況,但不是全部,白平衡其實是通過攝像機內部的電路調整(改變藍、綠、紅三個CCD電平的平衡關系)使反射到鏡頭里的光線都呈現(xiàn)為消色。
通俗的來說就是:是圖片中最亮的部分為白色,最暗的部分為黑色。其余部分進行拉伸。效果如下:
原圖:
?
robust color balance:
?
簡單的說就是:在rgb三通道上分別統(tǒng)計每個像素值的出現(xiàn)次數。將1%的最大值和最小值設置為255和0。其余值映射到(0,255),這樣使得每個值通道的值在rgb中分布較均勻。達到顏色平衡的結果。。
opencv實現(xiàn)了簡單白平衡。使用多層直方圖,比單個直方圖的優(yōu)點,應該是速度更快。實際上并不一定要這么實現(xiàn)。且算法的實現(xiàn)應該有問題。以下是修改后代碼,中文部分是我加的注釋。主要加入offset來標識每層的偏移量。opencv結果:
?
? ? ? ?
? ? ? ? /*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// * Redistribution‘s of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution’s in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of Intel Corporation may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors “as is” and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include 《vector》
#include 《algorithm》
#include 《iterator》
#include 《iostream》
#include “xphoto.hpp”
#include “opencv2/imgproc.hpp”
#include “opencv2/core.hpp”
#include “opencv2/core/core_c.h”
#include “opencv2/core/types.hpp”
#include “opencv2/core/types_c.h”
#define USE_OFFSET 1
namespace cv
{
namespace xphoto
{
template 《typename T》
void balanceWhite(std::vector 《 Mat_《T》 》 &src, Mat &dst,
const float inputMin, const float inputMax,
const float outputMin, const float outputMax, const int algorithmType)
{
switch ( algorithmType )
{
case WHITE_BALANCE_SIMPLE:
{
/********************* Simple white balance *********************/
float s1 = 2.0f; // low quantile
float s2 = 2.0f; // high quantile
int depth = 2; // depth of histogram tree
if (src[0].depth() != CV_8U)
++depth;
int bins = 16; // number of bins at each histogram level
int nElements = int( pow(bins, depth) );
// number of elements in histogram tree
//i是通道下標, src[0], src[1], src[3]分別表示三個通道
for (size_t i = 0; i 《 src.size(); ++i)
{
std::vector 《int》 hist(2 * nElements, 0);
typename Mat_《T》::iterator beginIt = src[i].begin();
typename Mat_《T》::iterator endIt = src[i].end();
//對該通道內每個像素進行處理
for (typename Mat_《T》::iterator it = beginIt; it != endIt; ++it)
// histogram filling
{
int pos = 0;
float minValue = inputMin - 0.5f;
float maxValue = inputMax + 0.5f;
T val = *it;
float interval = float(maxValue - minValue) / bins;
//基本上等同于對每個元素進行統(tǒng)計
//這種雙層hist的方法實際是有問題的。這種方法設計來對加速,0,16作為一個統(tǒng)計階段統(tǒng)計,而后面的每個像素則是具體的次數
//例如一個像素3,則可能使得hist[0],hist[3]各增加一次。hist[0]是對的,但是hist[3]的意義就變了。
//之所以程序寫這么麻煩的原因是,輸入min,max,輸出min,max都有可能變化。
//改正方法應該是對后面的層數加偏移操作。保證正確性。
int offset = 0;
for (int j = 0; j 《 depth; ++j)
{
int currentBin = int( (val - minValue + 1e-4f) / interval );
++hist[pos + currentBin];
#if USE_OFFSET
offset = offset + (int)pow(bins, j);
#endif
pos = (offset + pos + currentBin)*bins;
minValue = minValue + currentBin*interval;
// maxValue = minValue + interval; //多余語句
interval /= bins;
}
}
int total = int( src[i].total() );
int p1 = 0, p2 = bins - 1;
int n1 = 0, n2 = total;
float minValue = inputMin - 0.5f;
float maxValue = inputMax + 0.5f;
float interval = (maxValue - minValue) / float(bins);
int offset = 0;
for (int j = 0; j 《 depth; ++j)
// searching for s1 and s2
{
while (n1 + hist[p1] 《 s1 * total / 100.0f)
{
n1 += hist[p1++];
minValue += interval;
}
#if USE_OFFSET
offset = offset + int(pow(bins, j));
#endif
std::cout 《《 offset 《《 std::endl;
p1 *= bins;
p1 = p1 + offset;
while (n2 - hist[p2] 》 (100.0f - s2) * total / 100.0f)
{
n2 -= hist[p2--];
maxValue -= interval;
}
p2 = p2*bins - 1;
p2 = p2 + offset;
interval /= bins;
}
src[i] = (outputMax - outputMin) * (src[i] - minValue)
/ (maxValue - minValue) + outputMin;
}
/****************************************************************/
break;
}
default:
CV_Error_( CV_StsNotImplemented,
(“Unsupported algorithm type (=%d)”, algorithmType) );
}
dst.create(/**/ src[0].size(), CV_MAKETYPE( src[0].depth(), int( src.size() ) ) /**/);
cv::merge(src, dst);
}
評論
查看更多