opencv 白平衡算法

编程实验

72人已加入

描述

一、概念

什么是白平衡呢?白平衡就是针对不同色温条件下,通过调整摄像机内部的色彩电路使拍摄出来的影像抵消偏色,更接近人眼的视觉习惯。白平衡可以简单地理解为在任意色温条件下,摄像机镜头所拍摄的标准白色经过电路的调整,使之成像后仍然为白色。这是一种经常出现的情况,但不是全部,白平衡其实是通过摄像机内部的电路调整(改变蓝、绿、红三个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);

}

二、方法

1、灰度世界算法

灰度世界算法以灰度世界假设为基础,该假设认为:对于一幅有着大量色彩变化的图像,R、G、B,三个分量的平均值趋于同一灰度值。从物理意义上讲,灰色世界法假设自然界景物对于光线的平均反射的均值在总体上是个定值Gray,这个定值近似地为“灰色”。颜色平衡算法将这一假设强制应用于待处理图像,可以从图像中消除环境光的影响,获得原始场景图像。

算法执行步骤:

(1)确定灰度均值:Gray

(2)计算三个通道的增益:Kr,Kg,Kb;

(3)调整R、G、B分量;

这种算法简单快速,但是当图像场景颜色并不丰富时,尤其出现大块单色物体时,该算法常会失效。

以下是OpenCV实现的灰度世界算法代码:

#include 《highgui/highgui.hpp》

#include 《imgproc/imgproc.hpp》

using namespace cv;

int main()

{

Mat imageSource = imread(“02.jpg”);

imshow(“原始图像”, imageSource);

vector《Mat》 imageRGB;

//RGB三通道分离

split(imageSource, imageRGB);

//求原始图像的RGB分量的均值

double R, G, B;

B = mean(imageRGB[0])[0];

G = mean(imageRGB[1])[0];

R = mean(imageRGB[2])[0];

//需要调整的RGB分量的增益

double KR, KG, KB;

KB = (R + G + B) / (3 * B);

KG = (R + G + B) / (3 * G);

KR = (R + G + B) / (3 * R);

//调整RGB三个通道各自的值

imageRGB[0] = imageRGB[0] * KB;

imageRGB[1] = imageRGB[1] * KG;

imageRGB[2] = imageRGB[2] * KR;

//RGB三通道图像合并

merge(imageRGB, imageSource);

imshow(“白平衡调整后”, imageSource);

waitKey();

return 0;

}

原始图像一,整体图像偏绿色:

 

白平衡校正后,天空的蓝色和树叶的绿色都得到了很好的还原:

 

原始图像二,整体偏黄色:

 

白平衡校正后效果:

 

2、完美全反射理论

完美全反射理论(perfect Reflector)假设图像上最亮点就是白点,并以此白点为参考对图像进行自动白平衡,最亮点定义为R+G+B的最大值。

3、动态阈值算法

参考论文:A Novel Automatic White Balance Method For Digital Still Cameras

算法分为两个步骤:白点检测和白点调整。

三、验证

通过测试效果表明:动态阈值法,1、该算法效果非常好;2、对块大小不太敏感,因此非常适合于自动化操作。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分