color balance (白平衡)

http://blog.csdn.net/vsooda/article/details/38875037


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


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

原图:


robust color balance:




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结果:



[cpp]  view plain copy
  1. /*M/// 
  2. // 
  3. //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. 
  4. // 
  5. //  By downloading, copying, installing or using the software you agree to this license. 
  6. //  If you do not agree to this license, do not download, install, 
  7. //  copy or use the software. 
  8. // 
  9. // 
  10. //                           License Agreement 
  11. //                For Open Source Computer Vision Library 
  12. // 
  13. // Copyright (C) 2000-2008, Intel Corporation, all rights reserved. 
  14. // Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved. 
  15. // Third party copyrights are property of their respective owners. 
  16. // 
  17. //   * Redistribution's of source code must retain the above copyright notice, 
  18. //     this list of conditions and the following disclaimer. 
  19. // 
  20. //   * Redistribution's in binary form must reproduce the above copyright notice, 
  21. //     this list of conditions and the following disclaimer in the documentation 
  22. //     and/or other materials provided with the distribution. 
  23. // 
  24. //   * The name of Intel Corporation may not be used to endorse or promote products 
  25. //     derived from this software without specific prior written permission. 
  26. // 
  27. // This software is provided by the copyright holders and contributors "as is" and 
  28. // any express or implied warranties, including, but not limited to, the implied 
  29. // warranties of merchantability and fitness for a particular purpose are disclaimed. 
  30. // In no event shall the Intel Corporation or contributors be liable for any direct, 
  31. // indirect, incidental, special, exemplary, or consequential damages 
  32. // (including, but not limited to, procurement of substitute goods or services; 
  33. // loss of use, data, or profits; or business interruption) however caused 
  34. // and on any theory of liability, whether in contract, strict liability, 
  35. // or tort (including negligence or otherwise) arising in any way out of 
  36. // the use of this software, even if advised of the possibility of such damage. 
  37. // 
  38. //M*/  
  39.   
  40. #include <vector>  
  41. #include <algorithm>  
  42. #include <iterator>  
  43. #include <iostream>  
  44.   
  45. #include "xphoto.hpp"  
  46.   
  47. #include "opencv2/imgproc.hpp"  
  48.   
  49. #include "opencv2/core.hpp"  
  50. #include "opencv2/core/core_c.h"  
  51.   
  52. #include "opencv2/core/types.hpp"  
  53. #include "opencv2/core/types_c.h"  
  54.   
  55. #define USE_OFFSET 1  
  56.   
  57. namespace cv  
  58. {  
  59. namespace xphoto  
  60. {  
  61.   
  62.     template <typename T>  
  63.     void balanceWhite(std::vector < Mat_<T> > &src, Mat &dst,  
  64.         const float inputMin, const float inputMax,  
  65.         const float outputMin, const float outputMax, const int algorithmType)  
  66.     {  
  67.         switch ( algorithmType )  
  68.         {  
  69.             case WHITE_BALANCE_SIMPLE:  
  70.                 {  
  71.                     /********************* Simple white balance *********************/  
  72.                     float s1 = 2.0f; // low quantile  
  73.                     float s2 = 2.0f; // high quantile  
  74.   
  75.                     int depth = 2; // depth of histogram tree  
  76.                     if (src[0].depth() != CV_8U)  
  77.                         ++depth;  
  78.                     int bins = 16; // number of bins at each histogram level  
  79.   
  80.                     int nElements = int( pow(bins, depth) );  
  81.                      // number of elements in histogram tree  
  82.   
  83.                     //i是通道下标, src[0], src[1], src[3]分别表示三个通道  
  84.                     for (size_t i = 0; i < src.size(); ++i)  
  85.                     {  
  86.                         std::vector <int> hist(2 * nElements, 0);  
  87.   
  88.                         typename Mat_<T>::iterator beginIt = src[i].begin();  
  89.                         typename Mat_<T>::iterator endIt = src[i].end();  
  90.                           
  91.   
  92.                         //对该通道内每个像素进行处理  
  93.                         for (typename Mat_<T>::iterator it = beginIt; it != endIt; ++it)  
  94.                          // histogram filling  
  95.                         {  
  96.                             int pos = 0;  
  97.                             float minValue = inputMin - 0.5f;  
  98.                             float maxValue = inputMax + 0.5f;  
  99.                             T val = *it;  
  100.   
  101.                             float interval = float(maxValue - minValue) / bins;  
  102.   
  103.                             //基本上等同于对每个元素进行统计  
  104.                             //这种双层hist的方法实际是有问题的。这种方法设计来对加速,0,16作为一个统计阶段统计,而后面的每个像素则是具体的次数  
  105.                             //例如一个像素3,则可能使得hist[0],hist[3]各增加一次。hist[0]是对的,但是hist[3]的意义就变了。  
  106.                             //之所以程序写这么麻烦的原因是,输入min,max,输出min,max都有可能变化。  
  107.                             //改正方法应该是对后面的层数加偏移操作。保证正确性。  
  108.                             int offset = 0;  
  109.   
  110.                             for (int j = 0; j < depth; ++j)  
  111.                             {  
  112.                                 int currentBin = int( (val - minValue + 1e-4f) / interval );  
  113.                                 ++hist[pos + currentBin];  
  114.                               
  115. #if USE_OFFSET  
  116.                                 offset = offset + (int)pow(bins, j);  
  117. #endif  
  118.                                 pos = (offset + pos + currentBin)*bins;  
  119.   
  120.                                 minValue = minValue + currentBin*interval;  
  121.                                // maxValue = minValue + interval;    //多余语句  
  122.   
  123.                                 interval /= bins;  
  124.                             }  
  125.                         }  
  126.   
  127.                         int total = int( src[i].total() );  
  128.   
  129.                         int p1 = 0, p2 = bins - 1;  
  130.                         int n1 = 0, n2 = total;  
  131.   
  132.                         float minValue = inputMin - 0.5f;  
  133.                         float maxValue = inputMax + 0.5f;  
  134.   
  135.                         float interval = (maxValue - minValue) / float(bins);  
  136.   
  137.                         int offset = 0;  
  138.                         for (int j = 0; j < depth; ++j)  
  139.                          // searching for s1 and s2  
  140.                         {  
  141.                             while (n1 + hist[p1] < s1 * total / 100.0f)  
  142.                             {  
  143.                                 n1 += hist[p1++];  
  144.                                 minValue += interval;  
  145.                             }  
  146. #if USE_OFFSET  
  147.                             offset = offset + int(pow(bins, j));  
  148. #endif  
  149.                             std::cout << offset << std::endl;  
  150.                             p1 *= bins;  
  151.                             p1 = p1 + offset;  
  152.   
  153.                             while (n2 - hist[p2] > (100.0f - s2) * total / 100.0f)  
  154.                             {  
  155.                                 n2 -= hist[p2--];  
  156.                                 maxValue -= interval;  
  157.                             }  
  158.                             p2 = p2*bins - 1;  
  159.                             p2 = p2 + offset;  
  160.   
  161.                             interval /= bins;  
  162.                         }  
  163.   
  164.                         src[i] = (outputMax - outputMin) * (src[i] - minValue)  
  165.                             / (maxValue - minValue) + outputMin;  
  166.                     }  
  167.                     /****************************************************************/  
  168.                     break;  
  169.                 }  
  170.             default:  
  171.                 CV_Error_( CV_StsNotImplemented,  
  172.                     ("Unsupported algorithm type (=%d)", algorithmType) );  
  173.         }  
  174.   
  175.         dst.create(/**/ src[0].size(), CV_MAKETYPE( src[0].depth(), int( src.size() ) ) /**/);  
  176.         cv::merge(src, dst);  
  177.     }  
自适应白平衡算法是一种可以自动调整图像白平衡的算法,其基本思想是通过对图像中的像素进行分析,找到一种合适的白平衡参数,从而达到消除色偏的效果。以下是一种简单的自适应白平衡算法的代码实现: ```python import cv2 import numpy as np def adaptive_white_balance(img, block_size=16, threshold=0.1): # 将RGB图像转换为LAB颜色空间 lab = cv2.cvtColor(img, cv2.COLOR_RGB2LAB) # 将LAB颜色空间分成三个通道 l, a, b = cv2.split(lab) # 将L通道进行均值滤波,得到背景亮度 blur = cv2.blur(l, (block_size, block_size)) # 计算每个像素的亮度差异 diff = l - blur # 计算亮度差异的标准差和均值 std_dev, avg = cv2.meanStdDev(diff) # 计算阈值 t = threshold * std_dev[0][0] + avg[0][0] # 将阈值应用到亮度差异图像上,得到白平衡参数 mask = diff > t mask = np.uint8(mask) mask = cv2.resize(mask, (img.shape[1], img.shape[0]), interpolation=cv2.INTER_NEAREST) mask = cv2.merge((mask, mask, mask)) # 将白平衡参数应用到LAB颜色空间中的A和B通道上 a = cv2.bitwise_and(a, mask) b = cv2.bitwise_and(b, mask) # 将LAB颜色空间转换回RGB颜色空间 lab = cv2.merge((l, a, b)) rgb = cv2.cvtColor(lab, cv2.COLOR_LAB2RGB) return rgb ``` 以上代码中,首先将RGB图像转换为LAB颜色空间,然后将L、A、B三个通道分开处理,对L通道进行均值滤波,并计算出每个像素的亮度差异。然后计算亮度差异的标准差和均值,并根据设定的阈值来确定白平衡参数。最后将白平衡参数应用到LAB颜色空间中的A和B通道上,再将LAB颜色空间转换回RGB颜色空间,得到最终的白平衡图像。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值