カラー量子化用に提供されている Java コードが、特に 256 色を超える画像を 256 色に減色する場合に効果的に減色するのに苦労し、次のような顕著なエラーが発生するのはなぜですか?

Susan Sarandon
リリース: 2024-11-25 14:47:12
オリジナル
859 人が閲覧しました

Why does the provided Java code for color quantization struggle to effectively reduce colors, particularly when reducing images with more than 256 colors to 256, resulting in noticeable errors like reds turning blue?

効果的な GIF/画像のカラー量子化

Java プログラミングでは、カラーの量子化は画像または GIF ファイルのカラー パレットを最適化する際に重要な役割を果たします。このプロセスには、元の画像の視覚的に受け入れられる表現を維持しながら色数を減らすことが含まれます。

問題点:

提供されたコードは、色を減らすのに非効率的であるようです。効果的に。 256 色を超える画像を 256 色に減色すると、赤が青に変わるなど、顕著なエラーが発生します。これは、アルゴリズムが画像内の重要な色を識別して保持するのに苦労していることを示唆しています。

推奨アルゴリズム:

  • メディアン カット:このアルゴリズムは、カラー値の中央値に基づいて色空間を再帰的に 2 つに分割し、バイナリ ツリーを作成します。次に、色の変化が最も小さいサブツリーをリーフ ノードとして選択し、最終的なカラー パレットを表します。
  • 人口ベース: このアルゴリズムは、色をその人口 (頻度) に基づいて並べ替えます。画像を作成し、最も頻繁に使用される上位「n」個を選択してパレットを作成しますColors.
  • k-Means: このアルゴリズムは、色空間を「k」個のクラスターに分割し、各クラスターは平均カラー値で表されます。次に、クラスターの重心を使用してカラー パレットが形成されます。

実装例:

Java でのメディアン カット アルゴリズムの実装例を次に示します。

import java.util.Arrays;
import java.util.Comparator;
import java.awt.image.BufferedImage;

public class MedianCutQuantizer {

    public static void quantize(BufferedImage image, int colors) {
        int[] pixels = image.getRGB(0, 0, image.getWidth(), image.getHeight(), null, 0, image.getWidth());
        Arrays.sort(pixels); // Sort pixels by red, green, and blue channel values

        // Create a binary tree representation of the color space
        TreeNode root = new TreeNode(pixels);

        // Recursively divide the color space and create the palette
        TreeNode[] palette = new TreeNode[colors];
        for (int i = 0; i < colors; i++) {
            palette[i] = root;
            root = divide(root);
        }

        // Replace pixels with their corresponding palette colors
        for (int i = 0; i < pixels.length; i++) {
            pixels[i] = getClosestColor(pixels[i], palette);
        }

        image.setRGB(0, 0, image.getWidth(), image.getHeight(), pixels, 0, image.getWidth());
    }

    private static TreeNode divide(TreeNode node) {
        // Find the median color value
        int median = node.getMedianValue();

        // Create two new nodes, one for each half of the color range
        TreeNode left = new TreeNode();
        TreeNode right = new TreeNode();

        // Divide the pixels into two halves
        for (int i = node.start; i < node.end; i++) {
            if (node.pixels[i] <= median) {
                left.addPixel(node.pixels[i]);
            } else {
                right.addPixel(node.pixels[i]);
            }
        }

        return left.count > right.count ? left : right;
    }

    private static int getClosestColor(int pixel, TreeNode[] palette) {
        int minDistance = Integer.MAX_VALUE;
        int closestColor = 0;

        for (TreeNode node : palette) {
            int distance = getDistance(pixel, node.getAverageValue());
            if (distance < minDistance) {
                minDistance = distance;
                closestColor = node.getAverageValue();
            }
        }

        return closestColor;
    }

    // Utility methods

    private static int getDistance(int color1, int color2) {
        int r1 = (color1 >> 16) & 0xFF;
        int g1 = (color1 >> 8) & 0xFF;
        int b1 = color1 & 0xFF;

        int r2 = (color2 >> 16) & 0xFF;
        int g2 = (color2 >> 8) & 0xFF;
        int b2 = color2 & 0xFF;

        return (r1 - r2) * (r1 - r2) + (g1 - g2) * (g1 - g2) + (b1 - b2) * (b1 - b2);
    }

    private static class TreeNode {
        int start;
        int end;
        int count;
        int[] pixels;
        Integer averageValue;

        public TreeNode() {
            this(new int[0], 0, 0);
        }

        public TreeNode(int[] pixels, int start, int end) {
            this.pixels = pixels;
            this.start = start;
            this.end = end;

            count = end - start;
        }

        public int getMedianValue() {
            return pixels[(start + end) / 2];
        }

        public int getAverageValue() {
            if (averageValue == null) {
                int r = 0;
                int g = 0;
                int b = 0;

                for (int i = start; i < end; i++) {
                    int pixel = pixels[i];

                    r += (pixel >> 16) & 0xFF;
                    g += (pixel >> 8) & 0xFF;
                    b += pixel & 0xFF;
                }

                averageValue = (r / count) << 16 | (g / count) << 8 | b / count;
            }

            return averageValue;
        }

        public void addPixel(int pixel) {
            int[] newPixels = new int[pixels.length + 1];

            System.arraycopy(pixels, start, newPixels, start, end);
            newPixels[end] = pixel;

            pixels = newPixels;
            end++;
            count = end - start;

            averageValue = null;
        }
    }
}
ログイン後にコピー

この実装または他の同様のアルゴリズムを使用すると、色の量子化を大幅に改善できますJava アプリケーションでプロセスを実行し、画像の色を 256 以下に減色しても、視覚的に許容できる結果が得られます。

以上がカラー量子化用に提供されている Java コードが、特に 256 色を超える画像を 256 色に減色する場合に効果的に減色するのに苦労し、次のような顕著なエラーが発生するのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート