好久没记录了,今天找抠图接口实在找的烦,市面上的免费抠图api不好用,收费的又太贵了,甚至还有的给你加水印,要求去水印也要收费一次。
无奈,还是自己写工具类吧。
废话不多说,还是贴代码,好用点个赞
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
-
Author: zzq
-
Time: 2024/12/30 10:32:11
*/
public class AutoImageRemoval {
public static void main(String[] args) {koutu("C:\\Users\\Administrator\\Pictures\\图片7.png", "C:\\Users\\Administrator\\Pictures\\图片71.png"); // 将前景替换为红色 replaceForegroundWithColor("C:\\Users\\Administrator\\Pictures\\图片71.png", "C:\\Users\\Administrator\\Pictures\\图片711.png", "#FFFFFF"); // 红色
}
public static String koutu(String inputPath, String outputPath){
try {
// 加载图片
BufferedImage image = ImageIO.read(new File(inputPath));// 自动检测背景色 int backgroundColor = detectBackgroundColor(image); // 抠图 BufferedImage result = removeBackground(image, backgroundColor); // 保存结果 ImageIO.write(result, "PNG", new File(outputPath)); System.out.println("图片抠图完成,已保存为"+outputPath); return outputPath; } catch (IOException e) { e.printStackTrace(); } return inputPath;
}
// 将前景替换为指定颜色
public static void replaceForegroundWithColor(String inputPath, String outputPath, String hexColor) {
try {
// 加载抠图后的图片
BufferedImage image = ImageIO.read(new File(inputPath));
// 将 HEX 颜色转换为 Color 对象
Color color = Color.decode(hexColor);
// 遍历每个像素
for (int y = 0; y < image.getHeight(); y++) {
for (int x = 0; x < image.getWidth(); x++) {
int pixel = image.getRGB(x, y);
// 如果像素不是透明的(即前景像素),替换为指定颜色
if ((pixel & 0xFF000000) != 0x00) {
image.setRGB(x, y, color.getRGB()); // 保留透明度,替换颜色
}
}
}// 保存结果 ImageIO.write(image, "PNG", new File(outputPath)); System.out.println("前景替换为颜色完成,已保存为: " + outputPath); } catch (IOException e) { e.printStackTrace(); }
}
// 自动检测背景色
private static int detectBackgroundColor(BufferedImage image) {
Map<Integer, Integer> colorCount = new HashMap<>();
int width = image.getWidth();
int height = image.getHeight();// 分析边缘像素 for (int x = 0; x < width; x++) { analyzePixel(image.getRGB(x, 0), colorCount); // 上边缘 analyzePixel(image.getRGB(x, height - 1), colorCount); // 下边缘 } for (int y = 0; y < height; y++) { analyzePixel(image.getRGB(0, y), colorCount); // 左边缘 analyzePixel(image.getRGB(width - 1, y), colorCount); // 右边缘 } // 返回出现次数最多的颜色作为背景色 return colorCount.entrySet().stream() .max(Map.Entry.comparingByValue()) .map(Map.Entry::getKey) .orElse(0xFFFFFF); // 如果未检测到背景色,默认使用白色
}
// 分析像素颜色
private static void analyzePixel(int pixel, Map<Integer, Integer> colorCount) {
colorCount.put(pixel, colorCount.getOrDefault(pixel, 0) + 1);
}// 移除背景
private static BufferedImage removeBackground(BufferedImage image, int backgroundColor) {
BufferedImage result = new BufferedImage(
image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
for (int y = 0; y < image.getHeight(); y++) {
for (int x = 0; x < image.getWidth(); x++) {
int pixel = image.getRGB(x, y);
// 如果像素颜色接近背景色,则设置为透明
if (isCloseToBackground(pixel, backgroundColor)) {
result.setRGB(x, y, 0x00FFFFFF); // 设置为完全透明
} else {
result.setRGB(x, y, pixel); // 保留前景像素
}
}
}
return result;
}// 判断像素是否接近背景色
private static boolean isCloseToBackground(int pixel, int backgroundColor) {
int threshold = 30; // 颜色相似度阈值
int redDiff = Math.abs(((pixel >> 16) & 0xFF) - ((backgroundColor >> 16) & 0xFF));
int greenDiff = Math.abs(((pixel >> 8) & 0xFF) - ((backgroundColor >> 8) & 0xFF));
int blueDiff = Math.abs((pixel & 0xFF) - (backgroundColor & 0xFF));
return redDiff < threshold && greenDiff < threshold && blueDiff < threshold;
}
}