diff --git a/src/main/java/com/iflytop/colortitration/app/service/ImageAnalysisService.java b/src/main/java/com/iflytop/colortitration/app/common/utils/ImageAnalysisUtil.java similarity index 88% rename from src/main/java/com/iflytop/colortitration/app/service/ImageAnalysisService.java rename to src/main/java/com/iflytop/colortitration/app/common/utils/ImageAnalysisUtil.java index 1681cc6..409827a 100644 --- a/src/main/java/com/iflytop/colortitration/app/service/ImageAnalysisService.java +++ b/src/main/java/com/iflytop/colortitration/app/common/utils/ImageAnalysisUtil.java @@ -1,8 +1,4 @@ -package com.iflytop.colortitration.app.service; - -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; +package com.iflytop.colortitration.app.common.utils; import javax.imageio.ImageIO; import java.awt.*; @@ -13,22 +9,17 @@ import java.io.File; import java.io.IOException; /** - * 图像分析 + * 工具类:图像分析,可扩展多种图像处理与分析方法,方法均为静态调用 */ -@Slf4j -@Service -@RequiredArgsConstructor -public class ImageAnalysisService { +public class ImageAnalysisUtil { /** * RGB 空间最大距离 */ private static final double MAX_DISTANCE = Math.sqrt(3 * 255 * 255); - /** * 泡沫过滤:亮度与均值偏差倍数 */ private static final double BUBBLE_STD_MULTIPLIER = 1.5; - /** * 默认高斯平滑内核(3x3) */ @@ -38,6 +29,10 @@ public class ImageAnalysisService { 1 / 16f, 2 / 16f, 1 / 16f }; + // 私有构造,避免实例化 + private ImageAnalysisUtil() { + } + /** * 使用百分比容差(0–100%)比较图像文件指定区域的平均颜色与目标颜色是否在容差范围内。 * @@ -48,7 +43,7 @@ public class ImageAnalysisService { * @return 如果区域平均颜色与目标颜色距离 <= 百分比转换后的绝对距离,则返回 true;否则返回 false * @throws IOException 如果读取图像文件失败 */ - public boolean isRegionColorWithinTolerance(File imageFile, Color targetColor, double tolerancePercent, Rectangle region) throws IOException { + public static boolean isRegionColorWithinTolerance(File imageFile, Color targetColor, double tolerancePercent, Rectangle region) throws IOException { BufferedImage image = loadImage(imageFile); Rectangle validRegion = getValidRegion(image, region); @@ -83,7 +78,7 @@ public class ImageAnalysisService { * @return 如果区域平均颜色与目标颜色距离 <= 百分比转换后的绝对距离,则返回 true;否则返回 false * @throws IOException 如果读取图像文件失败 */ - public boolean analyzeRegionColorMatch(File imageFile, Color targetColor, double tolerancePercent, Rectangle region) throws IOException { + public static boolean analyzeRegionColorMatch(File imageFile, Color targetColor, double tolerancePercent, Rectangle region) throws IOException { BufferedImage image = loadImage(imageFile); BufferedImage smoothed = smoothImage(image); Rectangle validRegion = getValidRegion(smoothed, region); @@ -143,7 +138,7 @@ public class ImageAnalysisService { * @return 如果检测到符合特征的区域,返回 true;否则返回 false * @throws IOException 读取图像失败 */ - public boolean isTestTubePresent(File backgroundFile, File currentFile, Rectangle region, double diffThresholdPercent, int minArea, double minAspectRatio) throws IOException { + public static boolean isTestTubePresent(File backgroundFile, File currentFile, Rectangle region, double diffThresholdPercent, int minArea, double minAspectRatio) throws IOException { BufferedImage bg = smoothImage(loadImage(backgroundFile)); BufferedImage curr = smoothImage(loadImage(currentFile)); @@ -187,7 +182,7 @@ public class ImageAnalysisService { return aspect >= minAspectRatio; } - // --------------- 私有 --------------- + // --------------- 私有辅助方法 --------------- /** * 读取图像文件并返回 BufferedImage 对象 @@ -196,7 +191,7 @@ public class ImageAnalysisService { * @return BufferedImage 图像对象 * @throws IOException 如果读取失败抛出异常 */ - private BufferedImage loadImage(File imageFile) throws IOException { + private static BufferedImage loadImage(File imageFile) throws IOException { BufferedImage img = ImageIO.read(imageFile); if (img == null) { throw new IOException("无法从文件读取图像: " + imageFile); @@ -212,7 +207,7 @@ public class ImageAnalysisService { * @return Rectangle 有效区域 * @throws IllegalArgumentException 如果区域超出图像范围 */ - private Rectangle getValidRegion(BufferedImage image, Rectangle region) { + private static Rectangle getValidRegion(BufferedImage image, Rectangle region) { Rectangle bounds = new Rectangle(0, 0, image.getWidth(), image.getHeight()); Rectangle valid = bounds.intersection(region); if (valid.isEmpty()) { @@ -227,7 +222,7 @@ public class ImageAnalysisService { * @param src 源图像 * @return BufferedImage 平滑后的图像 */ - private BufferedImage smoothImage(BufferedImage src) { + private static BufferedImage smoothImage(BufferedImage src) { Kernel kernel = new Kernel(3, 3, GAUSS_KERNEL); return new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null).filter(src, null); } @@ -239,7 +234,7 @@ public class ImageAnalysisService { * @param c2 颜色二 * @return double 欧氏距离 */ - private double computeDistance(Color c1, Color c2) { + private static double computeDistance(Color c1, Color c2) { return Math.sqrt( Math.pow(c1.getRed() - c2.getRed(), 2) + Math.pow(c1.getGreen() - c2.getGreen(), 2) + @@ -254,7 +249,7 @@ public class ImageAnalysisService { * @return double 绝对距离阈值 * @throws IllegalArgumentException 如果百分比不在 0–100 范围内 */ - private double convertTolerance(double percent) { + private static double convertTolerance(double percent) { if (percent < 0 || percent > 100) { throw new IllegalArgumentException("tolerancePercent 范围应在 0–100 之间"); }