Comment trouver différentes nuances d'une couleur en Java?


Si j'ai le code RBG d'un nombre, tel que -16777216 (noir), comment puis-je trouver d'autres nuances de noir similaires en utilisant ce code couleur?

J'essaie de convertir une image en monochrome en marquant tous les pixels qui ne sont pas -16777216 pour être blancs. Cependant, il y a souvent différentes nuances de noir qui sont trouvées, mais elles sont perdues parce qu'elles ne correspondent pas exactement.

Edit: J'ai un peu de mal. Quand j'essaie d'utiliser cette couleur pour trouver des nuances de noir, donc je peux ignorez-les lors de la conversion des autres pixels en blanc, voici mon résultat:

Source:

source

Résultat:

résultat

Code:

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) );
    }
}
Author: user2790209, 2013-09-22

2 answers

Vous pouvez utiliser cette méthode 'rechercher la couleur avec une tolérance de différence'.

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

Ici, il est utilisé pour obtenir le contour (motorcycle-03.jpg) de la moto (motorcycle.jpg), tout en effaçant la "superposition gris pâle".

Moto.jpg

Image D'Origine

Moto-03.png

Image Traitée

ImageOutline.java

Ce code nécessite un peu de patience (lors de l'exécution). Voir Lissage d'un chemin dentelé pour le code qui fait la même chose beaucoup plus rapidement.

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

Avec le code vu dans la question, avec une tolérance de 150, je vois cela.

entrez la description de l'image ici

 3
Author: Andrew Thompson, 2020-06-20 09:12:55

En général, je pense que la voie à suivre est d'utiliser les formules de conversion sRGB en échelle de gris décrites sur cette page Wikipedia, puis de choisir une valeur "grise" particulière comme étant la limite entre le noir et le blanc. (Le choix est à vous ...)

Mais disons que vous avez déjà des valeurs RVB qui représentent des points d'échelle de gris, vous devriez constater qu'ils ont tous des valeurs rouges, vertes et bleues égales. Si tel est réellement le cas, il vous suffit de choisir l'une des couleurs composants d'un RVB et comparez-le à la même valeur de couleur de votre "gris"choisi.

Si vous devez distinguer plusieurs nuances de noir, de gris et de blanc, choisissez plusieurs "couleurs"de limite.


Edit: je vais avoir un peu de mal. Lorsque j'essaie d'utiliser cette couleur pour trouver des nuances de noir, afin de pouvoir les ignorer lors de la conversion des autres pixels en blanc, voici mon résultat:

Ce que vous voyez là, ce sont les effets de l'anticrénelage. Il est en fait très peu de noir " pur " dans l'image. Beaucoup de ce qui semble noir à l'œil humain est en fait sombre, ou pas si gris foncé. Vous devez rendre votre couleur de limite (c'est-à-dire la limite entre "noir" et "pas noir") plus grise.

 2
Author: Stephen C, 2013-09-22 10:15:08