一、概念
什么是白平衡呢?白平衡就是针对不同色温条件下,通过调整摄像机内部的色彩电路使拍摄出来的影像抵消偏色,更接近人眼的视觉习惯。白平衡可以简单地理解为在任意色温条件下,摄像机镜头所拍摄的标准白色经过电路的调整,使之成像后仍然为白色。这是一种经常出现的情况,但不是全部,白平衡其实是通过摄像机内部的电路调整(改变蓝、绿、红三个CCD电平的平衡关系)使反射到镜头里的光线都呈现为消色。
通俗的来说就是:是图片中最亮的部分为白色,最暗的部分为黑色。其余部分进行拉伸。效果如下:
原图:
robust color balance:
简单的说就是:在rgb三通道上分别统计每个像素值的出现次数。将1%的最大值和最小值设置为255和0。其余值映射到(0,255),这样使得每个值通道的值在rgb中分布较均匀。达到颜色平衡的结果。。
opencv实现了简单白平衡。使用多层直方图,比单个直方图的优点,应该是速度更快。实际上并不一定要这么实现。且算法的实现应该有问题。以下是修改后代码,中文部分是我加的注释。主要加入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;
//基本上等同于对每个元素进行统计
//这种双层hist的方法实际是有问题的。这种方法设计来对加速,0,16作为一个统计阶段统计,而后面的每个像素则是具体的次数
//例如一个像素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);
}
评论