opencv识别模糊图片

Java依赖       

 <dependency>
            <groupId>org.openpnp</groupId>
            <artifactId>opencv</artifactId>
            <version>4.7.0-0</version>
        </dependency>

Util代码实现:
import org.opencv.core.*;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

import java.util.ArrayList;
import java.util.List;

public class ImageQualityUtil {

    static {
        // 加载 OpenCV 库
        nu.pattern.OpenCV.loadLocally();
    }

    /**
     * 检测图片是否模糊
     * @param imagePath 图片路径
     * @return 拉普拉斯方差值,一般小于100认为模糊
     */
    public static double detectBlur(String imagePath) {
        // 读取图片
        Mat image = Imgcodecs.imread(imagePath);
        if (image.empty()) {
            throw new RuntimeException("无法读取图片");
        }

        // 转换为灰度图
        Mat gray = new Mat();
        Imgproc.cvtColor(image, gray, Imgproc.COLOR_BGR2GRAY);

        // 使用拉普拉斯算子
        Mat laplacian = new Mat();
        Imgproc.Laplacian(gray, laplacian, CvType.CV_64F);

        // 计算标准差
        MatOfDouble mean = new MatOfDouble();
        MatOfDouble std = new MatOfDouble();
        Core.meanStdDev(laplacian, mean, std);

        double variance = Math.pow(std.get(0, 0)[0], 2);

        // 释放资源
        image.release();
        gray.release();
        laplacian.release();

        return variance;
    }

    /**
     * 判断图片是否模糊
     * @param variance 拉普拉斯方差值
     * @param threshold 阈值,默认100
     * @return true表示模糊
     */
    public static boolean isBlurred(double variance, double threshold) {
        return variance < threshold;
    }

    /**
            * 检测图片倾斜角度
            * @param imagePath 图片路径
            * @return 倾斜角度(度)
     * */
    public static double detectSkewAngle(String imagePath) {
        // 读取图片
        Mat image = Imgcodecs.imread(imagePath);
        if (image.empty()) {
            throw new RuntimeException("无法读取图片");
        }

        // 转换为灰度图
        Mat gray = new Mat();
        Imgproc.cvtColor(image, gray, Imgproc.COLOR_BGR2GRAY);

        // 边缘检测
        Mat edges = new Mat();
        Imgproc.Canny(gray, edges, 50, 150);

        // 霍夫直线检测
        Mat lines = new Mat();
        Imgproc.HoughLines(edges, lines, 1, Math.PI / 180, 100);

        // 收集角度
        List<Double> angles = new ArrayList<>();
        for (int i = 0; i < lines.rows(); i++) {
            double[] line = lines.get(i, 0);
            double theta = line[1];
            double angle = Math.toDegrees(theta);

            // 只考虑接近水平或垂直的线
            if ((angle < 45 || angle > 135)) {
                if (angle > 90) {
                    angle = angle - 180;
                }
                angles.add(angle);
            }
        }

        // 计算中位数角度
        double skewAngle = calculateMedianAngle(angles);

        // 释放资源
        image.release();
        gray.release();
        edges.release();
        lines.release();

        return skewAngle;
    }

    /**
     * 计算角度中位数
     */
    private static double calculateMedianAngle(List<Double> angles) {
        if (angles.isEmpty()) {
            return 0.0;
        }

        angles.sort(Double::compareTo);
        int size = angles.size();

        if (size % 2 == 0) {
            return (angles.get(size / 2 - 1) + angles.get(size / 2)) / 2.0;
        } else {
            return angles.get(size / 2);
        }
    }

    /**
     * 判断图片是否倾斜
     * @param angle 倾斜角度
     * @param threshold 阈值,默认2度
     * @return true表示倾斜
     */
    public static boolean isSkewed(double angle, double threshold) {
        return Math.abs(angle) > threshold;
    }

    public static void main(String[] args) {
        String imagePath = "D:\\a3.jpg";
        // 检测模糊
        double blurVariance = ImageQualityUtil.detectBlur(imagePath);
        System.out.println("拉普拉斯方差: " + blurVariance);

        if (ImageQualityUtil.isBlurred(blurVariance, 100)) {
            System.out.println("图片模糊");
        } else {
            System.out.println("图片清晰");
        }

        // 检测倾斜
        double skewAngle = ImageQualityUtil.detectSkewAngle(imagePath);
        System.out.println("倾斜角度: " + skewAngle + "度");

        if (ImageQualityUtil.isSkewed(skewAngle, 10.0)) {
            System.out.println("图片倾斜");
        } else {
            System.out.println("图片正常");
        }
    }
}

在springboot中使用:

@Override    public OcrParamsDTO qualityImages(User user, OcrParamsDTO images) {
        List<OcrParamsDTO.OcrDetailDTO> result = new ArrayList<>();
        for (var temp : images.getParams()) {
            try {
                boolean correct = true;
                String desc = "";
                String fileName = new ObjectId().toHexString() + ".jpg";
                String path = "/tmp/" + fileName;
                DownLoadUtil.downloadFile(temp.getImageUrl(), "/tmp", fileName);
                double blurVariance = ImageQualityUtil.detectBlur(path);
                if (ImageQualityUtil.isBlurred(blurVariance, 100)) {
                    correct = false;
                    desc = desc + "图片过于模糊;";
                }
                // 检测倾斜
                double skewAngle = ImageQualityUtil.detectSkewAngle(path);
                if (ImageQualityUtil.isSkewed(skewAngle, 10.0)) {  // 大于10 算倾斜严重
                    correct = false;
                    desc = desc + "图片过于倾斜;";
                }
                temp.setCorrect(correct);
                temp.setDesc(desc);
            } catch (Exception exception) {
                log.error(exception.getMessage());
            }
            result.add(temp);
        }
        images.setParams(result);
        return images;
    }

Entity:

@Data
public class OcrParamsDTO {

    private List<OcrDetailDTO> params;

    @Data
    public static class OcrDetailDTO {
        private String imageUrl;
        private boolean correct;  //是否倾斜
        private String desc; // 错误信息
    }

}

Controller:

public Result qualityImage(@CurrentUser User user, @RequestBody OcrParamsDTO params) {
      return Result.success(ocrService.qualityImages(user, params));
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值