Browse Source

feat:图像分析

master
白凤吉 2 weeks ago
parent
commit
cbe63190cb
  1. 37
      src/main/java/com/iflytop/colortitration/app/common/utils/ImageAnalysisUtil.java

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