親測有效!一種完美動態閾值白平衡算法 Java實現。

幾年沒發文了,從新拿起技術!html

最近作圖像處理,要自動處理顏色平衡問題,不少什麼直方圖優化之類的,都不完美。因此在博客園找到了這個前輩的文章。算法

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

基於灰度世界、完美反射、動態閾值等圖像自動白平衡算法的原理、實現及效果post

 

很惋惜,這篇文章,首先沒有源碼,其次給出的一些計算過程有問題。因此我直接查看論文原文,以及一些映射公式,如今分享Java實現的版本:優化

 

核心算法:url

        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 = new Color(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, new Color(r, g, b).getRGB());
            }
        }

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

 

其中計算YCrCb的算法以下:spa

    // https://mathematica.stackexchange.com/questions/29786/how-to-convert-rgb-to-ycbcr
    private double[] toYCbCr(int color) {

        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 };
    }

 

最後還有一個像素範圍檢測:3d

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

 

實際效果:code

 
   

 

效果很是好。我也看了下原做者的問題,應該是計算YCrCb出錯了。orm

 本次分享完畢啦!好幾年沒有在博客園發文了,說下近況了。第一次進博客園是10多年前,在上海交大讀研究生的一個窮小孩。研究生畢業以後一直磕磕碰碰在創業,到了如今36了,仍然在創業。也許未來創業成功了,這些博客都能成爲勵志經歷。不成功,那就繼續努力。

最近正在投身微信公衆號,也小有成就,作了全國最大的樂高公衆號。但願未來有一天能有所成。

 

感謝各位園友的閱讀,但願這篇文章有幫助!

相關文章
相關標籤/搜索