legegecoder
legegecoder
发布于 2023-05-04 / 79 阅读 / 0 评论 / 0 点赞

【工具】取色

UI对阿里云OSS取色的色彩不满意,让后端取色,下面的取色代码1M图片毫秒级,而且效果很好

public class MedianCutColorExtractor {
    public static void main(String[] args) {
        try {
            BufferedImage img = ImageIO.read(new File("someThing/thread_1.jpg"));
            Color dominantColor = getDominantColor(img, 1000);
            System.out.println("Dominant Color: " + dominantColor.toString());
        } catch (IOException e) {
            System.out.println("Image file not found.");
        }
    }

    public static Color getDominantColor(BufferedImage img, int maxPixels) {
        int width = img.getWidth();
        int height = img.getHeight();
        int totalPixels = width * height;

        if (totalPixels > maxPixels) {
            double scaleFactor = Math.sqrt((double) maxPixels / totalPixels);
            width = (int) (width * scaleFactor);
            height = (int) (height * scaleFactor);
            img = resizeImage(img, width, height);
        }

        List<Color> colors = new ArrayList<>();

        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                colors.add(new Color(img.getRGB(x, y)));
            }
        }

        return medianCut(colors, 1).get(0);
    }

    private static BufferedImage resizeImage(BufferedImage img, int width, int height) {
        BufferedImage resizedImage = new BufferedImage(width, height, img.getType());
        Graphics2D g = resizedImage.createGraphics();
        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g.drawImage(img, 0, 0, width, height, null);
        g.dispose();
        return resizedImage;
    }

    private static List<Color> medianCut(List<Color> colors, int level) {
        if (colors.isEmpty()) {
            return Collections.emptyList();
        }

        if (level == 0) {
            return Collections.singletonList(getAverageColor(colors));
        }

        int[] minMax = getMinMax(colors);
        int longestAxis = getLongestAxis(minMax);
        sortColorsByAxis(colors, longestAxis);

        int median = colors.size() / 2;
        List<Color> left = colors.subList(0, median);
        List<Color> right = colors.subList(median, colors.size());

        List<Color> result = new ArrayList<>();
        result.addAll(medianCut(left, level - 1));
        result.addAll(medianCut(right, level - 1));

        return result;
    }

    private static int[] getMinMax(List<Color> colors) {
        int minRed = 255, maxRed = 0;
        int minGreen = 255, maxGreen = 0;
        int minBlue = 255, maxBlue = 0;

        for (Color color : colors) {
            minRed = Math.min(minRed, color.getRed());
            maxRed = Math.max(maxRed, color.getRed());
            minGreen = Math.min(minGreen, color.getGreen());
            maxGreen = Math.max(maxGreen, color.getGreen());
            minBlue = Math.min(minBlue, color.getBlue());
            maxBlue = Math.max(maxBlue, color.getBlue());
        }

        return new int[]{minRed, maxRed, minGreen, maxGreen, minBlue, maxBlue};
    }

    private static int getLongestAxis(int[] minMax) {
        int redRange = minMax[1] - minMax[0];
        int greenRange = minMax[3] - minMax[2];
        int blueRange = minMax[5] - minMax[4];

        if (redRange >= greenRange && redRange >= blueRange) {
            return 0;
        } else if (greenRange >= redRange && greenRange >= blueRange) {
            return 1;
        } else {
            return 2;
        }
    }

    private static void sortColorsByAxis(List<Color> colors, int axis) {
        Comparator<Color> comparator;

        switch (axis) {
            case 0: // Red axis
                comparator = Comparator.comparingInt(Color::getRed);
                break;
            case 1: // Green axis
                comparator = Comparator.comparingInt(Color::getGreen);
                break;
            default: // Blue axis
                comparator = Comparator.comparingInt(Color::getBlue);
                break;
        }

        colors.sort(comparator);
    }

    private static Color getAverageColor(List<Color> colors) {
        int redSum = 0;
        int greenSum = 0;
        int blueSum = 0;
        int count = colors.size();

        for (Color color : colors) {
            redSum += color.getRed();
            greenSum += color.getGreen();
            blueSum += color.getBlue();
        }

        return new Color(redSum / count, greenSum / count, blueSum / count);
    }
}


评论