color balance (白平衡)

opencv3.0 xphoto模块包含了简单白平衡算法。没有注明算法原理,出自哪篇论文,很不方便。搜索之后,发现一篇博客不错,介绍了该原理。同时实现了robust color balance。


白平衡的意思就是:是图片中最亮的部分为白色,最暗的部分为黑色。其余部分进行拉伸。博客效果如下:

原图:

color balance (白平衡)_第1张图片

robust color balance:

color balance (白平衡)_第2张图片



This is the color balancing technique used in Adobe Photoshop's "auto levels" command. The idea is that in a well balanced photo, the brightest color should be white and the darkest black. Thus, we can remove the color cast from an image by scaling the histograms of each of the R, G, and B channels so that they span the complete 0-255 scale. In contrast to the other color balancing algorithms, this method does not separate the estimation and adaptation steps.
In order to deal with outliers, Simplest Color Balance saturates a certain percentage of the image's bright pixels to white and dark pixels to black. The saturation level is an adjustable parameter that affects the quality of the output. Values around 0.01 are typical.


简单的说就是:在rgb三通道上分别统计每个像素值的出现次数。将1%的最大值和最小值设置为255和0。其余值映射到(0,255),这样使得每个值通道的值在rgb中分布较均匀。达到颜色平衡的结果。. 


opencv实现了简单白平衡。使用多层直方图,比单个直方图的优点,应该是速度更快。实际上并不一定要这么实现。且算法的实现应该有问题。以下是修改后代码,中文部分是我加的注释。主要加入offset来标识每层的偏移量。opencv结果:

color balance (白平衡)_第3张图片


/*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);
    }


你可能感兴趣的:(color balance (白平衡))