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));
}
863

被折叠的 条评论
为什么被折叠?



