【问题标题】:How to find different shades of a color in Java?如何在 Java 中找到不同颜色的深浅?
【发布时间】:2013-09-22 08:21:02
【问题描述】:

如果我有一个数字的 RBG 代码,例如 -16777216(黑色),如何使用此颜色代码找到其他类似的黑色阴影?

我正在尝试通过将所有不是-16777216 的像素标记为白色来将图像转换为单色。但是,通常会发现不同深浅的黑色,但由于不完全匹配而丢失了。

编辑:我遇到了一些麻烦。当我尝试使用这种颜色来查找黑色阴影时,我可以在将其他像素转换为白色时忽略它们,这是我的结果:

来源:

结果:

代码:

package test;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.net.URL;
import javax.imageio.ImageIO;

public class Test
{       
    public static void main(String[] args)
    {
        try
        {
            BufferedImage source = ImageIO.read( new URL("http://i.imgur.com/UgdqfUY.png"));
            //-16777216 = black:
            BufferedImage dest = makeMonoChromeFast(source, -16777216);
            File result = new File("D:/result.png");
            ImageIO.write(dest, "png", result);
        }
        catch (Exception e)
        {
            e.printStackTrace();;
        }
    }

    public static BufferedImage makeMonoChromeFast(BufferedImage source, int foreground)
    {        
        int background = -1; //white;

        Color fg = new Color(foreground);

        int color = 0;
        for (int y = 0; y < source.getHeight(); y++)
        {
            for (int x = 0; x < source.getWidth(); x++)
            {
                color = source.getRGB(x, y);
                if ( color == foreground )
                    continue;
                if (! isIncluded(fg, color, 50))
                    source.setRGB(x, y, background);;
            }
        }

        return source;
    }

    public static boolean isIncluded(Color target, int pixelColor, int tolerance)
    {
        Color pixel = new Color(pixelColor);
        int rT = target.getRed();
        int gT = target.getGreen();
        int bT = target.getBlue();
        int rP = pixel.getRed();
        int gP = pixel.getGreen();
        int bP = pixel.getBlue();
        return(
            (rP-tolerance<=rT) && (rT<=rP+tolerance) &&
            (gP-tolerance<=gT) && (gT<=gP+tolerance) &&
            (bP-tolerance<=bT) && (bT<=bP+tolerance) );
    }
}

【问题讨论】:

    标签: java colors image-manipulation bufferedimage


    【解决方案1】:

    您可以使用这种“寻找具有差异容差的颜色”的方法。

    public static boolean isIncluded(Color target, Color pixel, int tolerance) {
        int rT = target.getRed();
        int gT = target.getGreen();
        int bT = target.getBlue();
        int rP = pixel.getRed();
        int gP = pixel.getGreen();
        int bP = pixel.getBlue();
        return(
            (rP-tolerance<=rT) && (rT<=rP+tolerance) &&
            (gP-tolerance<=gT) && (gT<=gP+tolerance) &&
            (bP-tolerance<=bT) && (bT<=bP+tolerance) );
    }
    

    这里用于获取摩托车 (motorcycle.jpg) 的轮廓 (motorcycle-03.jpg),同时去除“浅灰色覆盖层”。

    摩托车.jpg

    摩托车-03.png

    ImageOutline.java

    此代码需要一些耐心(运行时)。请参阅 Smoothing a jagged path 以获取更快执行相同操作的代码。

    import java.awt.*;
    import java.awt.image.BufferedImage;
    import java.awt.geom.Area;
    import javax.imageio.ImageIO;
    import java.io.File;
    import java.util.Date;
    import javax.swing.*;
    
    /* Motorcycle image courtesy of ShutterStock
    http://www.shutterstock.com/pic-13585165/stock-vector-travel-motorcycle-silhouette.html */
    class ImageOutline {
    
        public static Area getOutline(BufferedImage image, Color color, boolean include, int tolerance) {
            Area area = new Area();
            for (int x=0; x<image.getWidth(); x++) {
                for (int y=0; y<image.getHeight(); y++) {
                    Color pixel = new Color(image.getRGB(x,y));
                    if (include) {
                        if (isIncluded(color, pixel, tolerance)) {
                            Rectangle r = new Rectangle(x,y,1,1);
                            area.add(new Area(r));
                        }
                    } else {
                        if (!isIncluded(color, pixel, tolerance)) {
                            Rectangle r = new Rectangle(x,y,1,1);
                            area.add(new Area(r));
                        }
                    }
                }
            }
            return area;
        }
    
        public static boolean isIncluded(Color target, Color pixel, int tolerance) {
            int rT = target.getRed();
            int gT = target.getGreen();
            int bT = target.getBlue();
            int rP = pixel.getRed();
            int gP = pixel.getGreen();
            int bP = pixel.getBlue();
            return(
                (rP-tolerance<=rT) && (rT<=rP+tolerance) &&
                (gP-tolerance<=gT) && (gT<=gP+tolerance) &&
                (bP-tolerance<=bT) && (bT<=bP+tolerance) );
        }
    
        public static BufferedImage drawOutline(int w, int h, Area area) {
            final BufferedImage result = new BufferedImage(
                w,
                h,
                BufferedImage.TYPE_INT_RGB);
            Graphics2D g = result.createGraphics();
    
            g.setColor(Color.white);
            g.fillRect(0,0,w,h);
    
            g.setClip(area);
            g.setColor(Color.red);
            g.fillRect(0,0,w,h);
    
            g.setClip(null);
            g.setStroke(new BasicStroke(1));
            g.setColor(Color.blue);
            g.draw(area);
    
            return result;
        }
    
        public static BufferedImage createAndWrite(
            BufferedImage image,
            Color color,
            boolean include,
            int tolerance,
            String name)
            throws Exception {
            int w = image.getWidth();
            int h = image.getHeight();
    
            System.out.println("Get Area: " + new Date() + " - " + name);
            Area area = getOutline(image, color, include, tolerance);
            System.out.println("Got Area: " + new Date() + " - " + name);
    
            final BufferedImage result = drawOutline(w,h,area);
            displayAndWriteImage(result, name);
    
            return result;
        }
    
        public static void displayAndWriteImage(BufferedImage image, String fileName) throws Exception {
            ImageIO.write(image, "png", new File(fileName));
            JOptionPane.showMessageDialog(null, new JLabel(new ImageIcon(image)));
        }
    
        public static void main(String[] args) throws Exception {
            final BufferedImage outline = ImageIO.read(new File("motorcycle.jpg"));
            BufferedImage crop = outline.getSubimage(17,35,420,270);
            displayAndWriteImage(crop, "motorcycle-01.png");
    
            BufferedImage crude = createAndWrite(crop, Color.white, false, 60, "motorcycle-02.png");
    
            BufferedImage combo = createAndWrite(crude, Color.red, true, 0, "motorcycle-03.png");
        }
    }
    

    使用问题中看到的代码,容差为 150,我看到了这个。

    【讨论】:

    • 关于将公差设置为什么的任何提示,以捕捉所有黑色阴影,同时忽略灰色?
    • 嗯,对于“黑色”和“灰色”的某些定义,该示例确实如此。这就是使您的评论..含糊不清的原因。通过“灰色”DYM Color(20,20,20) 是“灰色”吗?具有 R/G/B 之一的颜色与其他两个颜色(例如 Color(0,0,1))仍然是“黑色”吗?此处用于确定“黑色”和“灰色”的确切规则是什么?
    • 正是您在视觉上所看到的,并且会考虑黑色与灰色。我不知道 RGB 值是多少。
    • 我遇到了一些麻烦,请参阅我编辑的问题以获取详细信息/代码。
    • 很多代码(和缓慢)是由于试图确定色差的outline。平滑锯齿状路径(上面的链接)上的代码执行速度更快,但您根本不需要在此处执行此操作。只需 1)创建一个新图像 2)为原始图像的宽度 X 高度(例如每个像素),确定它是否“等于黑色范围” 3)对于目标图像,如果是,则绘制一个黑色像素,否则白色。 -- 这应该会更快,尽管我认为它仍然不如 JRE 使用的简单“单色”公式那么快。
    【解决方案2】:

    总的来说,我认为要走的路是使用this Wikipedia page上描述的sRGB到灰度转换公式,然后选择一个特定的“灰度”值作为黑白之间的边界。 (选择权在你...)

    但是假设您已经有表示灰度点的 RGB 值,您应该会发现它们都具有相等的红色、绿色和蓝色值。如果情况确实如此,那么您只需选择 RGB 的颜色分量之一,并将其​​与您选择的“灰色”的相同颜色值进行比较。

    如果您需要区分黑色、灰色和白色的多种色调,请选择多种边界“颜色”。


    编辑:我遇到了一些麻烦。当我尝试使用这种颜色来查找黑色阴影时,我可以在将其他像素转换为白色时忽略它们,这是我的结果:

    您所看到的是抗锯齿的效果。图像中实际上很少有“纯”黑色。很多人眼看起来黑色的东西实际上是黑色的,或者不是那么深灰色。您需要使边界颜色(即“黑色”和“非黑色”之间的边界)更灰。

    【讨论】:

    • 我确信你说的是正确的,但它超出了我的理解能力/知识范围
    • 再读一遍。我不欣赏你的“我很笨”的行为:-)
    • 如何将边界颜色设置为更灰?即 200 的容差可以做到吗?
    • 这是我的问题。此图像作为屏幕截图,复制到 MS Paint 并保存。如果我使用 `awt.Robot.captureScreenRegion 拍摄图像,它是否仍然具有抗锯齿,或者抗锯齿是否来自绘画?
    • “如果我使用 `awt.Robot.captureScreenRegion 拍摄图像,它是否仍然具有抗锯齿功能。” 是的,它肯定会。非抗锯齿文本看起来很糟糕,很少使用。
    猜你喜欢
    • 2015-09-16
    • 2014-10-30
    • 1970-01-01
    • 2022-07-09
    • 2012-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多