几年没发文了,重新拿起技术!

最近做图像处理,要自动处理颜色平衡问题,很多什么直方图优化之类的,都不完美。所以在博客园找到了这个前辈的文章。

http://www.cnblogs.com/Imageshop/archive/2013/04/20/3032062.html#commentform

基于灰度世界、完美反射、动态阈值等图像自动白平衡算法的原理、实现及效果

很可惜,这篇文章,首先没有源码,其次给出的一些计算过程有问题。所以我直接查看论文原文,以及一些映射公式,现在分享Java实现的版本:

核心算法:

  1. BufferedImage img = ImageIO.read(new File("model3.jpg"));
  2. int pixelsize = img.getWidth() * img.getHeight();
  3.  
  4. double[][][] YCbCr = new double[img.getWidth()][img.getHeight()][3];
  5. double Mr = 0, Mb = 0, Ymax = 0;
  6. for (int i = 0; i < img.getWidth(); i++) {
  7. for (int j = 0; j < img.getHeight(); j++) {
  8. YCbCr[i][j] = toYCbCr(img.getRGB(i, j));
  9. Mr += YCbCr[i][j][2];
  10. Mb += YCbCr[i][j][1];
  11. Ymax = Math.max(Ymax, YCbCr[i][j][0]);
  12. }
  13. }
  14.  
  15. Mr /= pixelsize;
  16. Mb /= pixelsize;
  17.  
  18. double Dr = 0, Db = 0;
  19. for (int i = 0; i < YCbCr.length; i++) {
  20. for (int j = 0; j < YCbCr[i].length; j++) {
  21. Db += Math.abs(YCbCr[i][j][1] - Mb);
  22. Dr += Math.abs(YCbCr[i][j][2] - Mr);
  23. }
  24. }
  25. Dr /= pixelsize;
  26. Db /= pixelsize;
  27.  
  28. double[][] Y = new double[img.getWidth()][img.getHeight()];
  29. double[] Yhistogram = new double[256];
  30. double Ysum = 0;
  31. for (int i = 0; i < Y.length; i++) {
  32. for (int j = 0; j < Y[i].length; j++) {
  33. int value = (Math.abs(YCbCr[i][j][1] - (Mb + Db * Math.signum(Mb))) < 1.5 * Db) & //
  34. (Math.abs(YCbCr[i][j][2]) - (1.5 * Mr + Dr * Math.signum(Mr))) < 1.5 * Dr ? 1 : 0;
  35. if (value <= 0)
  36. continue;
  37. double y = YCbCr[i][j][0];
  38. Y[i][j] = y;
  39. Yhistogram[(int) Y[i][j]]++;
  40. Ysum++;
  41. }
  42. }
  43.  
  44. double Yhistogramsum = 0;
  45. double Ymin = 0;
  46. for (int i = Yhistogram.length - 1; i >= 0; i--) {
  47. Yhistogramsum += Yhistogram[i];
  48. if (Yhistogramsum > 0.1 * Ysum) {
  49. Ymin = i;
  50. break;
  51. }
  52. }
  53.  
  54. double Raver = 0, Gaver = 0, Baver = 0;
  55. double averSum = 0;
  56. for (int i = 0; i < Y.length; i++) {
  57. for (int j = 0; j < Y[i].length; j++) {
  58. if (Y[i][j] > Ymin) {
  59.  
  60. int color = img.getRGB(i, j);
  61. int r = (color >> 16) & 0xFF;
  62. int g = (color >> 8) & 0xFF;
  63. int b = color & 0xFF;
  64. Raver += r;
  65. Gaver += g;
  66. Baver += b;
  67. averSum++;
  68. }
  69. }
  70. }
  71. Raver /= averSum;
  72. Gaver /= averSum;
  73. Baver /= averSum;
  74.  
  75. double Rgain = Ymax / Raver, Ggain = Ymax / Gaver, Bgain = Ymax / Baver;
  76. for (int i = 0; i < img.getWidth(); i++) {
  77. for (int j = 0; j < img.getHeight(); j++) {
  78. Color color = new Color(img.getRGB(i, j));
  79. int r = ensureColor((int) Math.floor(color.getRed() * Rgain));
  80. int g = ensureColor((int) Math.floor(color.getGreen() * Ggain));
  81. int b = ensureColor((int) Math.floor(color.getBlue() * Bgain));
  82. img.setRGB(i, j, new Color(r, g, b).getRGB());
  83. }
  84. }
  85.  
  86. ImageIO.write(img, "jpg", new File("xxx.jpg"));

其中计算YCrCb的算法如下:

  1. // https://mathematica.stackexchange.com/questions/29786/how-to-convert-rgb-to-ycbcr
  2. private double[] toYCbCr(int color) {
  3.  
  4. int r = (color >> 16) & 0xFF;
  5. int g = (color >> 8) & 0xFF;
  6. int b = color & 0xFF;
  7.  
  8. double Y = 16 + (65.481 * r / 255 + 128.553 * g / 255 + 24.966 * b / 255);
  9. double Cb = 128 + (-37.797 * r / 255 - 74.203 * g / 255 + 112 * b / 255);
  10. double Cr = 128 + (112 * r / 255 - 93.786 * g / 255 - 18.214 * b / 255);
  11.  
  12. return new double[] { Y, Cb, Cr };
  13. }

最后还有一个像素范围检测:

  1. private int ensureColor(double color) {
  2. if (color < 0)
  3. return 0;
  4. if (color > 255)
  5. return 255;
  6. return (int) color;
  7. }

实际效果:

 
   

效果非常好。我也看了下原作者的问题,应该是计算YCrCb出错了。

本次分享完毕啦!好几年没有在博客园发文了,说下近况了。第一次进博客园是10多年前,在上海交大读研究生的一个穷小孩。研究生毕业之后一直磕磕碰碰在创业,到了现在36了,仍然在创业。也许将来创业成功了,这些博客都能成为励志经历。不成功,那就继续努力。

最近正在投身微信公众号,也小有成就,做了全国最大的乐高公众号。希望将来有一天能有所成。

感谢各位园友的阅读,希望这篇文章有帮助!

亲测有效!一种完美动态阈值白平衡算法 Java实现。的更多相关文章

  1. matlab 自动阈值白平衡算法 程序可编译实现

    一种效果很好的自动白平衡技术(WhiteBalance) 白平衡是图像处理的一个极重要概念.所谓白平衡(英文名称为White Balance),就是对白色物体的还原.当我们用肉眼观看这大千世界时,在不 ...

  2. 【VS开发】【图像处理】基于灰度世界、完美反射、动态阈值等图像自动白平衡算法的原理、实现及效果

    基于灰度世界.完美反射.动态阈值等图像自动白平衡算法的原理.实现及效果      白平衡是电视摄像领域一个非常重要的概念,通过它可以解决色彩还原和色调处理的一系列问题.白平衡是随着电子影像再现色彩真实 ...

  3. 中兴iptv机顶盒破解教程图文:亲测中兴B760EV3、B860A、B860AV1.1完美安装应用!非ttl破解![转]

    一直以为中兴的这几个盒子只能通过ttl来破解,不过现在再也不用这么麻烦了,有了这个工具,前后破解不超3分钟!理论上支持所有中兴的iptv机顶盒的破解! 亲测中兴B760EV3.B860A.B860AV ...

  4. MyEclipse8.6启动后提示内存不足的解决方案(亲测,完美解决)

    转自:http://www.bubuko.com/infodetail-1625857.html 最近可能由于公司项目大了,启动MyEclipse后经常提示内存不足的警告框,如下: 其实点击close ...

  5. (链接)IDEA 2018 激活 IDEA 2018.3激活教程 最新的(三种)—2018.11.26亲测

    破解不成功的请注意时效性,写于2019/2/8,以下第一种激活方法亲测可用, 不过有时候破解成功了可能过几天突然就打不开了,双击无反应的说,这时候再按顺序 操作一遍就是了: 1)把idea64.exe ...

  6. mac下高效安装 homebrew 及完美避坑姿势 (亲测有效)

    世上无难事,只要找到 Homebrew 的正确安装方式. Homebrew 是什么 Homebrew是 mac的包管理器,仅需执行相应的命令,就能下载安装需要的软件包,可以省掉自己去下载.解压.拖拽( ...

  7. Sublime Text3 最新版本V3.1.1 build3117注册码,亲测可以完美激活~

    Sublime Text 3 最新注册码 官网下载的最新版本V3.1.1 build3117,亲测以下注册码可以正常激活 ----- BEGIN LICENSE ----- sgbteam Singl ...

  8. 获取UIColor中的RGB值(本人亲测多个获取RGB值的方法,这个最有效)

    在自己研发的项目个人项目中,碰到一个从颜色中获取RGB值的需求. 在网上找了许久,也有一些方法可以获取RGB值,但不能获取黑白以及灰色的值(他们是非RGB颜色空间,不清楚什么意思,反正亲测确实获取不了 ...

  9. VS 2013驱动开发 + Windbg + VM双机调试(亲测+详解)

    ------------VS 2013驱动开发 + Windbg + VM双机调试(亲测+详解)------------- WIN10已上线,随之而来的是VS2015:微软在 "WDK760 ...

随机推荐

  1. 【转】MyISAM和InnoDB 区别

    InnoDB和MyISAM是MySQL最常用的两个表类型,这两个表类型各有优劣,视具体应用而定.基本的差别为:MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持.MyISAM类型的表强调 ...

  2. Android studio 打开别人的工程

    Android Studio正确打开项目只需要两步,或者说找到两个文件进行简单的修改就好,最好在打开之前进行修改 (1)gradle-wrapper.properities,在项目下按照如下路径可以找 ...

  3. vim 和grep 正则表达式相似和区别

    正则表达式由两种基本字符类型组成:原义(正常)文本字符和元字符.元字符使正则表达式具有处理能力.所谓元字符就是指那些在正则表达式中具有特殊意义的专用字符,可以用来规定其前导字符(即位于元字符前面的字符 ...

  4. Unity之2D Sprite Outline外轮廓效果

    操作系统:Windows8.1 显卡:Nivida GTX965M 开发工具:Unity5.3.8f1 Unity提供了2D Object Sprite对象,但是没有提供外轮廓Outline效果的支持 ...

  5. (原创)foef注意事项

    原创内容,转载请标明原文地址 我们先来看下下面的代码 //获取文件大小 DWORD Get_File_Size(const char* m_FilePath) { unsigned long size ...

  6. Swift 入门之简单语法(五)

    面向对象 目标 构造函数 构造函数的基本概念 构造函数的执行顺序 KVC 在构造函数中的使用及原理 便利构造函数 析构函数 区分 重载 和 重写 懒加载 只读属性(计算型属性) 设置模型数据(didS ...

  7. 移动前端meta

    <!-- 页面描述 --> <meta name="description" content="不超过150个字符"/> <!-- ...

  8. Windows 修改电脑属性(一)

    修改电脑属性里的注册信息 修改电脑属性的注册信息 运行注册表的方法:开始→运行→regedit→确定 1.CPU型号可以注册表编辑器中定位到下面的位置: HKEY_LOCAL_MACHINE\HARD ...

  9. 小K的H5之旅-实战篇(一)

    一.前言 本K在经过两个星期的html和css学习之后,第一次去尝试完成一个网站主页的制作.在四天之后,本K也终于完成了杰瑞教育主页的html和css部分,至于部分涉及js的部分,因为本K还没有学习过 ...

  10. javaSE_05Java中方法(函数)与重载、递归-练习

    1.使用的递归的方法求5! public class DiGui{ public static void main(String[] args){ //使用的递归的方法求5! System.out.p ...