再论颜色校正-白平衡之动态阈值 Python和c#实现

理论我就不写了,可以参考<一种动态阈值白平衡算法实现>,公式部分写的还比较详细,我就不赘述了。只是网上我搜到的这个算法的实现只有java和c++版本的,所以就自己写了python版本的,只是对于理论上说的把图像分块计算我还没实现,可能是我理解有问题,分块后的效果很差,所以就没实现。如果有人知道的话还请给我说一声,谢谢!
顺带说一声,直接用cv2的颜色转换函数将bgr转成YCrCb空间的话,在计算白点的判别式的时候总是出现全False的情况,后来改用公式自己计算就好了,可能是cv2的函数内部做过处理,没仔细研究。还有个地方,就是在计算‘参考白色点”中最大的10%的亮度(Y分量)值’的时候,理解这句话费了好大的劲才又仔细参考了c++的代码才实现。最终效果还是很好的!
全部代码:

def auto_whiteBalance(img):    
    b, g, r = cv2.split(img)    
    Y = 0.299 * r + 0.587 * g + 0.114 * b
    Cr = 0.5 * r - 0.419 * g - 0.081 * b
    Cb = -0.169 * r - 0.331 * g + 0.5 * b

    Mr = np.mean(Cr)
    Mb = np.mean(Cb)

    Dr = np.var(Cr)
    Db = np.var(Cb)

    temp_arry = (np.abs(Cb - (Mb + Db * np.sign(Mb))) < 1.5 * Db) & (np.abs(Cr - (1.5 * Mr + Dr * np.sign(Mr))) < 1.5 * Dr)
    RL = Y * temp_arry

    # 选取候选白点数的最亮10%确定为最终白点,并选择其前10%中的最小亮度值
    L_list = list(np.reshape(RL, (RL.shape[0] * RL.shape[1],)).astype(np.int))
    hist_list = np.zeros(256)
    min_val = 0
    sum = 0
    for val in L_list:
        hist_list[val] += 1

    for l_val in range(255,0,-1):
        sum += hist_list[l_val]
        if sum >= len(L_list) * 0.1:
            min_val = l_val
            break
    # 取最亮的前10%为最终的白点
    white_index = RL < min_val
    RL[white_index] = 0

    # 计算选取为白点的每个通道的增益
    b[white_index] = 0
    g[white_index] = 0
    r[white_index] = 0

    Y_max = np.max(RL)
    b_gain = Y_max / (np.sum(b) / np.sum(b>0))
    g_gain = Y_max / (np.sum(g) / np.sum(g>0))
    r_gain = Y_max / (np.sum(r) / np.sum(r>0))

    b, g, r = cv2.split(img)
    b = b * b_gain
    g = g * g_gain
    r = r * r_gain

    # 溢出处理
    b[b > 255] = 255
    g[g > 255] = 255
    r[r > 255] = 255

    res_img = cv2.merge((b,g,r))
    return res_img
    
 img_data = cv2.imread('1.jpg')
 img = auto_whiteBalance(img_data)
 cv2.imwrite('1_auto.jpg', img)

效果:
再论颜色校正-白平衡之动态阈值 Python和c#实现_第1张图片
2019.7.1更新,添加C#版本,python c++ java c#就都有了,一家人嘛就应该整整齐齐 哈哈

        private Bitmap AutoWriteBalance(string img_file)
        {
            Bitmap img = new Bitmap(img_file);
            int pixelsize = img.Width * img.Height;

            double[,,] YCbCr = new double[img.Width,img.Height,3];
            double Mr = 0, Mb = 0, Ymax = 0;
            for (int i = 0; i < img.Width; i++)
            {
                for (int j = 0; j < img.Height; j++)
                {
                    double[] YCbCr_value = toYCbCr(img.GetPixel(i, j));
                    for (int k = 0; k < 3; k++)
                        YCbCr[i, j, k] = YCbCr_value[k];
                    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.GetLength(0); i++)
            {
                for (int j = 0; j < YCbCr.GetLength(1); j++)
                {
                    Db += Math.Pow((YCbCr[i, j, 1] - Mb),2);
                    Dr += Math.Pow((YCbCr[i, j, 2] - Mr),2);
                }
            }
            Dr /= pixelsize;
            Db /= pixelsize;

            
            double[,] Y = new double[img.Width,img.Height];
            double[] Yhistogram = new double[256];
            double Ysum = 0;
            for (int i = 0; i < img.Width; i++)
            {                
                for (int j = 0; j < img.Height; j++)
                {
                    int value = (Math.Abs(YCbCr[i,j,1] - (Mb + Db * Math.Sign(Mb))) < 1.5 * Db) && (Math.Abs(YCbCr[i,j,2]) - (1.5 * Mr + Dr * Math.Sign(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.Count() - 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 < img.Width; i++)
            {
                for (int j = 0; j < img.Height; j++)
                {
                    if (Y[i,j] > Ymin)
                    {

                        Color color = img.GetPixel(i, j);
                        int r = color.R;
                        int g = color.G;
                        int b = color.B;
                        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.Width; i++)
            {
                for (int j = 0; j < img.Height; j++)
                {
                    Color color = img.GetPixel(i, j);
                    int r = ensureColor((int)Math.Floor(color.R * Rgain));
                    int g = ensureColor((int)Math.Floor(color.G * Ggain));
                    int b = ensureColor((int)Math.Floor(color.B * Bgain));
                    img.SetPixel(i, j, Color.FromArgb(r, g, b));
                }
            }
            return img;
        }

        private double[] toYCbCr(System.Drawing.Color color)
        {
            int r = color.R;
            int g = color.G;
            int b = color.B;           

            double Y = 0.299 * r + 0.587 * g + 0.114 * b;
            double Cb = 0.5 * r - 0.419 * g - 0.081 * b;
            double Cr = -0.169 * r - 0.331 * g + 0.5 * b;

            return new double[] { Y, Cb, Cr };
        }

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

你可能感兴趣的:(图像处理)