【问题标题】:Color blending per pixel每像素颜色混合
【发布时间】:2015-12-16 17:41:48
【问题描述】:

我正在尝试理解图形。现在我被困在颜色混合上。我尝试使用一些基本算法来合并 rgb 中的颜色。现在我想像在现实生活中一样合并它们,即黄色 + 蓝色 = 绿色。我有这样的方法。

package com.boxonix.light.utils;

public class Utils {

   public static int rgbToHex(int r, int g, int b) {
      return (1048576 * r) + (255 * g) + b;
   }

   public static int blendPixels(int r, int g, int b, double alpha, int bgPixel){   
      return 0;
   }

   public static int getRed(int color) {
      int red = Math.floorDiv(color, 1048576);
      return red;
   }

   public static int getGreen(int color) {
      int green = Math.floorDiv(color % 65536, 256);
      return green;
   }

   public static int getBlue(int color) {
      int blue = Math.floorDiv(color % 1048576, 256);
      return blue;
   }
}

r,g,b 是颜色,表示越过背景像素 (bgPix) 的像素,alpha 是透明度 (0.0 - 1.0)。我可以将 bgPix 转换为 r1、g1、b1。现在我需要混合它们,救命! :D

【问题讨论】:

  • "Blending" two colors really means taking the weighted average of them :错了。平均会给出糟糕的、非常丑陋的结果。如果你想像现实生活一样混合两种颜色,请使用公式sqrt(ColA^2 + ColB^2)/2
  • 给你的分钟物理:youtube.com/watch?v=LKnqECcg6Gw
  • 这让我注意到上面公式中的一个错误,正确的是sqrt((ColA^2 + ColB^2)/2),如视频所示。
  • sqrt(((AlphaA*ColA)^2 + (AlphaB*ColB)^2)/(AlphaA + AlphaB))
  • 附注:这些计算看起来很奇怪。你不应该使用这些“魔法”常量。十六进制代码具有“视觉”显示哪些字节被输出的好特性。或者,您可以将相关部分转移到相关字节中。例如。要从 RGB 值中获取绿色分量(作为 0...255 中的值),您可以使用 int g = (rgb >> 8) & 0xFF

标签: java


【解决方案1】:

听起来您正试图在某些背景颜色之上混合前景色。令人高兴的是,它很简单:

alpha * foregroundColor + (1 - alpha) * backgroundColor

这个想法是只有部分颜色来自前景色,其余(1 - alpha)来自背景。仔细想想就可以直观的看到:如果alpha为0,那么所有的颜色都来自背景;如果 alpha 为 1,则全部来自前台。

使用上述方法定义的示例代码:

public static int blendPixels(int r, int g, int b, double alpha, int bgPixel) {   
   int blendedRed = (int)Math.round(alpha * r + (1.0 - alpha) * getRed(bgPixel));
   int blendedGreen = (int)Math.round(alpha * g + (1.0 - alpha) * getGreen(bgPixel));
   int blendedBlue = (int)Math.round(alpha * b + (1.0 - alpha) * getBlue(bgPixel));
   return rgbToHex(blendedRed, blendedGreen, blendedBlue);
}

希望有帮助!

【讨论】:

  • 很确定你必须分别做每个频道。我在评论中给出的示例 0.75*black + 0.25*white... 您的代码显示 0.25*0xFFFFFF 可能是 0x400000(相当深的红色)或 0x3FFFFF(电蓝-青色),具体取决于你怎么圆。不是灰色的。
  • @dcsohl 对不起,你说得对。我回答得太快了。我只是相应地编辑了上面的答案。
【解决方案2】:

实际上不是答案,但这里是根据公式快速实现每个像素的颜色混合

alpha * foregroundColor + (1 - alpha) * backgroundColor

这似乎是错误的 - 查看屏幕截图 - 并随意使用代码进行测试。

截图:

代码:

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.util.Locale;
import java.util.Random;

public class Program {
    static JFrame mainFrame;
    static JPanel view;
    static JLabel fgLabel;
    static JSlider fgTrack;
    static JLabel alphaLabel;
    static JSlider alphaTrack;
    static JLabel bgLabel;
    static JSlider bgTrack;

    static int fg;
    static float alpha;
    static int blend;
    static int bg;

    public static void main(String[] args) {
        //setup application
        mainFrame = new JFrame() {{
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setContentPane(new JPanel() {{
                setLayout(new BorderLayout());
                setSize(640, 480);
                setPreferredSize(getSize());
                add(new JPanel() {{
                    setLayout(new FlowLayout());
                    add(fgLabel = new JLabel());
                    add(fgTrack = new JSlider(0, 100) {{
                        setOrientation(JSlider.VERTICAL);
                        setMajorTickSpacing(25);
                        setMinorTickSpacing(5);
                        setPaintTrack(true);
                        setPaintTicks(true);
                        addChangeListener(e -> {
                            fg = Color.getHSBColor(getValue() / 100f, 1f, 1f).getRGB();
                            fgLabel.setText("fg=" + rgbToString(fg));
                            view.repaint();
                        });
                    }});
                    add(alphaLabel = new JLabel());
                    add(alphaTrack = new JSlider(0, 100) {{
                        setOrientation(JSlider.VERTICAL);
                        setMajorTickSpacing(25);
                        setMinorTickSpacing(5);
                        setPaintTrack(true);
                        setPaintTicks(true);
                        addChangeListener(e -> {
                            alpha = getValue() / 100f;
                            blend = blendPixels(fg, alpha, bg);
                            alphaLabel.setText("<html>alpha=" + alpha+"<br>blend=" + rgbToString(blend));
                            view.repaint();
                        });
                    }});
                    add(bgLabel = new JLabel());
                    add(bgTrack = new JSlider(0, 100) {{
                        setOrientation(JSlider.VERTICAL);
                        setMajorTickSpacing(25);
                        setMinorTickSpacing(5);
                        setPaintTrack(true);
                        setPaintTicks(true);
                        addChangeListener(e -> {
                            bg = Color.getHSBColor(getValue() / 100f, 1f, 1f).getRGB();
                            bgLabel.setText("bg=" + rgbToString(bg));
                            view.repaint();
                        });
                    }});
                }}, BorderLayout.NORTH);
                add(view = new JPanel() {
                    @Override
                    public void paintComponent(Graphics g) {
                        super.paintComponent(g);

                        Graphics2D g2 = (Graphics2D) g;
                        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

                        //"transparent" background
                        final int m = 8;
                        for (int r = 0, x = 0; x < getWidth(); r++, x += m) {
                            for (int c = 0, y = 0; y < getHeight(); c++, y += m) {
                                g2.setColor((r + c) % 2 == 0 ? Color.WHITE : Color.LIGHT_GRAY);
                                g2.fillRect(x, y, m, m);
                            }
                        }

                        //circles
                        final int d = Math.min(getWidth() / 2, getHeight());
                        g2.setColor(new Color(bg));
                        g2.fillOval(d, 0, d, d);
                        g2.setColor(new Color(blend));
                        g2.fillOval(d / 2, 0, d, d);
                        g2.setColor(new Color(fg));
                        g2.fillOval(0, 0, d, d);
                    }
                }, BorderLayout.CENTER);
            }});
        }};

        //randomize values
        Random rng = new Random();
        fgTrack.setValue(rng.nextInt(100));
        alphaTrack.setValue(rng.nextInt(100));
        bgTrack.setValue(rng.nextInt(100));

        //display
        mainFrame.pack();
        mainFrame.setLocationRelativeTo(null);
        mainFrame.setVisible(true);
    }

    public static String rgbToString(int rgb) {
        return Integer.toHexString(rgb).toUpperCase(Locale.ROOT);
    }

    public static int rgbToHex(int r, int g, int b) {
        return (1 << 16) * r
                + (1 << 8) * g
                + (1 << 0) * b;
    }

    public static int blendPixels(int fgPixel, float alpha, int bgPixel) {
        return rgbToHex(
                blendPixelComponent(getRed(fgPixel), alpha, getRed(bgPixel)),
                blendPixelComponent(getGreen(fgPixel), alpha, getGreen(bgPixel)),
                blendPixelComponent(getBlue(fgPixel), alpha, getBlue(bgPixel))
        );
    }

    public static int blendPixelComponent(int fgComp, float alpha, int bgComp) {
        final float beta = 1 - alpha;
        return Math.round(alpha * fgComp + beta * bgComp);
    }

    public static int getRed(int color) {
        return (color >> 16) & 0xFF;
    }

    public static int getGreen(int color) {
        return (color >> 8) & 0xFF;
    }

    public static int getBlue(int color) {
        return (color >> 0) & 0xFF;
    }
}

【讨论】:

    猜你喜欢
    • 2011-07-06
    • 2015-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-01
    • 2015-08-09
    • 2021-08-31
    相关资源
    最近更新 更多