Greenscreen, funktioniert nicht zu 100%... nicht alle Pixel werden geändert

internet

Top Contributor
Hallo,

ich bin gerade dabei ein Bild mit einem Greenscreen Hintergrund mit einem neuen Hintergrund zu ersetzen.
So wie hier:

Leider schaffe ich es nicht alle grünen Pixel zu ersetzen, es fehlt also noch etwas an der Feinheit...
Was fehlt hier, sodass es 100% ist?
Ich müsstes auch den Schatten betrachten. Wie kann ich das machen?

Hier mal mein Code

Java:
import java.io.*;
import java.awt.image.BufferedImage;
import javax.imageio.*;

public class GreenscreenTest {

    public static void main(String[] args) throws IOException {

        // Info to give to greenscreen
        String output = "/output.jpg";
        String fgName = "/test.jpg";
        String bgName = "/backgroundReplace.jpg";
        int tolerance = 20;
        int x = 0;
        int y = 0;


        // Greenscreen that thing
        BufferedImage screenedImage = GreenscreenFunction.generateGreenscreen(fgName, bgName, tolerance, x, y);

        // Save file
        File outfile = new File(output);
        try {
            ImageIO.write(screenedImage, "jpg", outfile);

            System.out.println("DONE");

        } catch (IOException e) {
            System.out.println("Error saving image.");
        }
    }
}


import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import javax.imageio.*;

/**
 */
public class GreenscreenFunction {

    /**
     * Laden des Images
     *
     * @param file
     * @return
     */
    protected static BufferedImage loadImage(String file) {

        // Loads an image
        BufferedImage image = null;

        try {
            image = ImageIO.read(new File(file));
        } catch (IOException e) {
            System.out.println("Eror opening image: " + file);
            return null;
        }

        // Wait for image to load
        MediaTracker tracker = new MediaTracker(new Component() {
        });
        tracker.addImage(image, 0);
        try {
            tracker.waitForID(0);
        } catch (InterruptedException e) {
        }

        return image;
    }

    /**
     * Mit Files
     *
     * @param originalFilePath
     * @param backgroundFilePath
     * @param tolerance
     * @param xExample
     * @param yExample
     * @return
     */
    public static BufferedImage generateGreenscreen(String originalFilePath, String backgroundFilePath, int tolerance,
            int xExample, int yExample) {

        BufferedImage foreground = loadImage(originalFilePath);
        BufferedImage background = loadImage(backgroundFilePath);

        BufferedImage newBufferedImage = generateGreenscreen(foreground, background, tolerance, xExample, yExample);

        return newBufferedImage;
    }

    /**
     * Return BufferedImage for replaced picture
     *
     * @param originalFilePath
     * @param backgroundFilePath
     * @param tolerance
     * @return
     */
    public static BufferedImage generateGreenscreen(BufferedImage foreground, BufferedImage background, int tolerance,
            int xExample, int yExample) {

        int sampleRGB = foreground.getRGB(xExample, yExample);

        // Will hold RGB values at a particular pixel
        int xyRGB;
        int alpha;
        int red;
        int green;
        int blue;

        // RGB values of our sample
        int sampleAlpha = (sampleRGB >> 24) & 0xFF;
        int sampleRed = (sampleRGB >> 16) & 0xFF;
        int sampleGreen = (sampleRGB >> 8) & 0xFF;
        int sampleBlue = sampleRGB & 0xFF;

        // Total difference between two colors
        int totalDiff = 0;

        // Was the last pixel replaced?
        boolean leftReplaced = false;

        // Iterate through each pixel
        for (int y = 0; y < foreground.getHeight(); y++) {
            for (int x = 0; x < foreground.getWidth(); x++) {
                xyRGB = foreground.getRGB(x, y);
                alpha = (xyRGB >> 24) & 0xFF;
                red = (xyRGB >> 16) & 0xFF;
                green = (xyRGB >> 8) & 0xFF;
                blue = xyRGB & 0xFF;

                // If we just did xyRGB - sampleRGB,
                // Alpha differences would be weighted more than red, etc.
                totalDiff = Math.abs(sampleAlpha - alpha) + Math.abs(sampleRed - red) + Math.abs(sampleGreen - green)
                        + Math.abs(sampleBlue - blue);

                if (leftReplaced) {
                    if (totalDiff < tolerance) {
                        foreground.setRGB(x, y, background.getRGB(x, y));
                        leftReplaced = true;
                    } else {
                        leftReplaced = false;
                    }
                } else {
                    if (1.5 * totalDiff < tolerance) {
                        foreground.setRGB(x, y, background.getRGB(x, y));
                        leftReplaced = true;
                    } else {
                        leftReplaced = false;
                    }
                }
            }
        }

        return foreground;
    }
}

Als Beispiel habe ich die zwei Bilder verwendet...
Der Output ist leider nicht 100%, siehe hier:

1661404769593.png

Kann hier jemand helfen, was bei der Funktion angepasst werden muss?
Die Parameter "Shadow" und "Highlight" fehlen leider auch noch...
 

Anhänge

  • backgroundReplace.jpg
    backgroundReplace.jpg
    325,5 KB · Aufrufe: 1
  • test.jpg
    test.jpg
    192,4 KB · Aufrufe: 1
Naja, 100% gehen bei einem unschaften Bild grundsätzlich nicht, damit hat man seit Anbeginn der Bluescreen-Technik zu kämpfen, selbst als es noch analog war. Hast du schon versucht, die Toleranz zu erhöhen?

Wenn ich in einem Grafikprogramm arbeiten würde, dann würde ich jetzt die Ränder der erkannten Fläche um ein paar Pixel erweitern, mit y (kleiner als x) Pixeln Übergang und experimentieren, bis es passt. Im Zweifelsfall schneidet man lieber einen Pixel zu viel weg als zu wenig.
Dafür bräuchtest du jetzt aber erst mal eine Konturerkennung. Ohne solche bleiben dir eigentlich nur die Toleranzen.

Ich würd mit floats rechnen anstatt mit Integern, da hat man etwas mehr Spielraum bei der Toleranz.
Auch würde ich den Komponenten eine Gewichtung geben. Die dominanten Farbkomponenten des Filters müssen den höchsten Stellenwert haben und müssen auch entsprechend stark im Pixel vertreten sein. Bei anderen Komponenten darf die Toleranz höher sein. Aber das ist nur so eine Idee.

Aber die Jungs oder Mädels, von denen du den Code hast, wissen das sicher besser als ich. Vielleicht solltest du mal bei denen direkt nachfragen?
 
Zuletzt bearbeitet:

Zurück
Oben