Unity 3D : 自動白平衡 : 動態閥值

前言 :

簡易動態閥值白平衡,這個範例我沒有做切成區塊來做,亮度是取最大值而不是前 10% 亮度,不過效果還行,湊合看吧

這個範例比較特別的是,最後有做 Y 增益調整,防止過曝,且亮度值與原圖相同 ( 調整後的 Y 與原圖 Y 相同 )

注意 : 輸入的圖片需要減過黑電平才能做白平衡哦 ! 不然不論如何調整都會偏色 !

運行前 :

这里写图片描述

運行後 :

这里写图片描述

C # :

using UnityEngine;
using UnityEngine.UI;

public class NewBehaviourScript : MonoBehaviour
{
    public Texture2D inputTexture;
    public RawImage outputImg;

    void Start()
    {

        Texture2D t = new Texture2D(inputTexture.width, inputTexture.height, TextureFormat.RGB24, false);

        float[] H = new float[256];

        //------------------------------------------------------------------------------
        // 計算 MB, MR

        float Mb = 0, Mr = 0; // Mb, Mr
        float Db = 0, Dr = 0;

        for (int y = 0; y < inputTexture.height; y++)
        {
            for (int x = 0; x < inputTexture.width; x++)
            {
                Color c = inputTexture.GetPixel(x, y);

                float[] YCbCr = ColorToYCbCr(c);

                float Y = YCbCr[0];
                float Cb = YCbCr[1];
                float Cr = YCbCr[2];

                Mb += Cb;
                Mr += Cr;
            }
        }

        Mb = Mb / (inputTexture.height * inputTexture.width);
        Mr = Mr / (inputTexture.height * inputTexture.width);

        //------------------------------------------------------------------------------
        // 計算 Db, Dr

        for (int y = 0; y < inputTexture.height; y++)
        {
            for (int x = 0; x < inputTexture.width; x++)
            {
                Color c = inputTexture.GetPixel(x, y);

                float[] YCbCr = ColorToYCbCr(c);

                float Y = YCbCr[0];
                float Cb = YCbCr[1];
                float Cr = YCbCr[2];

                Db += Mathf.Abs(Cb - Mb);
                Dr += Mathf.Abs(Cr - Mr);
            }
        }

        Db /= inputTexture.height * inputTexture.width;
        Dr /= inputTexture.height * inputTexture.width;

        //------------------------------------------------------------------------------
        // 判斷白點 並 計算白點 RGB 平均值

        float AvgR = 0, AvgG = 0, AvgB = 0;
        float AvgCount = 0;
        float Ymax = 0, Ymax2 = 0; //Ymax: 未調整增益,Ymax2: 調整過增益的

        for (int y = 0; y < inputTexture.height; y++)
        {
            for (int x = 0; x < inputTexture.width; x++)
            {
                Color c = inputTexture.GetPixel(x, y);

                float[] YCbCr = ColorToYCbCr(c);

                float Y = YCbCr[0];
                float Cb = YCbCr[1];
                float Cr = YCbCr[2];

                // 符合條件為白點,並計算 RGB 平均值
                if (Mathf.Abs(Cb - (Mb + Db * Mathf.Sign(Mb))) < 1.5f * Db)
                {
                    if (Mathf.Abs(Cr - (Mr + Dr * Mathf.Sign(Mr))) < 1.5f * Dr)
                    {
                        Color cc = YCbCrToColor(YCbCr);
                        AvgR += cc.r;
                        AvgG += cc.g;
                        AvgB += cc.b;

                        AvgCount++;
                    }
                }

                if (Y > Ymax) Ymax = Y;
            }
        }

        AvgR /= AvgCount;
        AvgG /= AvgCount;
        AvgB /= AvgCount;

        print("Ymax : " + Ymax);

        //------------------------------------------------------------------------------
        // Ymax 增益調整 ( 防止過曝 )

        float _Rgain = Ymax / AvgR;
        float _Ggain = Ymax / AvgG;
        float _Bgain = Ymax / AvgB;

        for (int y = 0; y < inputTexture.height; y++)
        {
            for (int x = 0; x < inputTexture.width; x++)
            {
                Color c = inputTexture.GetPixel(x, y);

                c = new Color(c.r * _Rgain, c.g * _Ggain, c.b * _Bgain);

                float Y = ColorToYCbCr(c)[0];
                if (Y > Ymax2) Ymax2 = Y;
            }
        }

        float dY = Ymax / Ymax2;

        Ymax2 = Ymax * dY;

        print("Ymax2 : " + Ymax2);

        //------------------------------------------------------------------------------
        // 個通道增益套用至原圖中,並輸出顯示

        float Rgain = Ymax2 / AvgR;
        float Ggain = Ymax2 / AvgG;
        float Bgain = Ymax2 / AvgB;

        for (int y = 0; y < inputTexture.height; y++)
        {
            for (int x = 0; x < inputTexture.width; x++)
            {
                Color c = inputTexture.GetPixel(x, y);

                c = new Color(c.r * Rgain, c.g * Ggain, c.b * Bgain);

                t.SetPixel(x, y, c);
            }
        }

        t.Apply();
        outputImg.texture = t;

        print("R-Gain : " + Rgain);
        print("G-Gain : " + Ggain);
        print("B-Gain : " + Bgain);
    }

    float[] ColorToYCbCr(Color color)
    {
        float[] yuv = new float[3];
        yuv[0] = 0.299f * color.r + 0.587f * color.g + 0.114f * color.b;
        yuv[1] = 0.564f * (color.b - yuv[0]);
        yuv[2] = 0.713f * (color.r - yuv[0]);
        return yuv;
    }

    // [Y: 0~1, Cb: -1~1, Cr: -1~1]
    Color YCbCrToColor(float[] yuv)
    {
        float r = yuv[0] + 1.402f * yuv[2];
        float g = yuv[0] - 0.344f * yuv[1] - 0.714f * yuv[2];
        float b = yuv[0] + 1.772f * yuv[1];
        return new Color(r, g, b);
    }
}

參考 :

論文 : https://files.cnblogs.com/files/Imageshop/ANovelAutomaticWhiteBalanceMethodforDigital.pdf
原理 : https://www.cnblogs.com/Imageshop/archive/2013/04/20/3032062.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值