阈值Java_亲测有效!一种完美动态阈值白平衡算法 Java实现。

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

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

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

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

核心算法:

BufferedImage img = ImageIO.read(new File("model3.jpg"));int pixelsize = img.getWidth() *img.getHeight();double[][][] YCbCr = new double[img.getWidth()][img.getHeight()][3];double Mr = 0, Mb = 0, Ymax = 0;for (int i = 0; i < img.getWidth(); i++) {for (int j = 0; j < img.getHeight(); j++) {

YCbCr[i][j]=toYCbCr(img.getRGB(i, j));

Mr+= YCbCr[i][j][2];

Mb+= YCbCr[i][j][1];

Ymax= Math.max(Ymax, YCbCr[i][j][0]);

}

}

Mr/=pixelsize;

Mb/=pixelsize;double Dr = 0, Db = 0;for (int i = 0; i < YCbCr.length; i++) {for (int j = 0; j < YCbCr[i].length; j++) {

Db+= Math.abs(YCbCr[i][j][1] -Mb);

Dr+= Math.abs(YCbCr[i][j][2] -Mr);

}

}

Dr/=pixelsize;

Db/=pixelsize;double[][] Y = new double[img.getWidth()][img.getHeight()];double[] Yhistogram = new double[256];double Ysum = 0;for (int i = 0; i < Y.length; i++) {for (int j = 0; j < Y[i].length; j++) {int value = (Math.abs(YCbCr[i][j][1] - (Mb + Db * Math.signum(Mb))) < 1.5 * Db) & // (Math.abs(YCbCr[i][j][2]) - (1.5 * Mr + Dr * Math.signum(Mr))) < 1.5 * Dr ? 1 : 0;if (value <= 0)continue;double y = YCbCr[i][j][0];

Y[i][j]=y;

Yhistogram[(int) Y[i][j]]++;

Ysum++;

}

}double Yhistogramsum = 0;double Ymin = 0;for (int i = Yhistogram.length - 1; i >= 0; i--) {

Yhistogramsum+=Yhistogram[i];if (Yhistogramsum > 0.1 *Ysum) {

Ymin=i;break;

}

}double Raver = 0, Gaver = 0, Baver = 0;double averSum = 0;for (int i = 0; i < Y.length; i++) {for (int j = 0; j < Y[i].length; j++) {if (Y[i][j] >Ymin) {int color =img.getRGB(i, j);int r = (color >> 16) & 0xFF;int g = (color >> 8) & 0xFF;int b = color & 0xFF;

Raver+=r;

Gaver+=g;

Baver+=b;

averSum++;

}

}

}

Raver/=averSum;

Gaver/=averSum;

Baver/=averSum;double Rgain = Ymax / Raver, Ggain = Ymax / Gaver, Bgain = Ymax /Baver;for (int i = 0; i < img.getWidth(); i++) {for (int j = 0; j < img.getHeight(); j++) {

Color color= newColor(img.getRGB(i, j));int r = ensureColor((int) Math.floor(color.getRed() *Rgain));int g = ensureColor((int) Math.floor(color.getGreen() *Ggain));int b = ensureColor((int) Math.floor(color.getBlue() *Bgain));

img.setRGB(i, j,newColor(r, g, b).getRGB());

}

}

ImageIO.write(img,"jpg", new File("xxx.jpg"));

其中计算YCrCb的算法如下:

// https://mathematica.stackexchange.com/questions/29786/how-to-convert-rgb-to-ycbcr

private double[] toYCbCr(intcolor) {int r = (color >> 16) & 0xFF;int g = (color >> 8) & 0xFF;int b = color & 0xFF;double Y = 16 + (65.481 * r / 255 + 128.553 * g / 255 + 24.966 * b / 255);double Cb = 128 + (-37.797 * r / 255 - 74.203 * g / 255 + 112 * b / 255);double Cr = 128 + (112 * r / 255 - 93.786 * g / 255 - 18.214 * b / 255);return new double[] { Y, Cb, Cr };

}

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

private int ensureColor(doublecolor) {if (color < 0)return 0;if (color > 255)return 255;return (int) color;

}

实际效果:

24a63c7e555d83ee392485ef8d339b0f.png

89746363968f6ffad2362cc217e558fb.png

b71dfe7f87ecb78b6816d97b09e8c7c8.png

4160fb62691bea9444b75dae7b5debc8.png

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

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

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

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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值