|
|
@@ -0,0 +1,183 @@
|
|
|
+package org.springblade.archive.utils;
|
|
|
+
|
|
|
+import org.apache.pdfbox.pdmodel.PDDocument;
|
|
|
+import org.apache.pdfbox.rendering.PDFRenderer;
|
|
|
+import org.bytedeco.javacpp.BytePointer;
|
|
|
+import org.bytedeco.javacv.Frame;
|
|
|
+import org.bytedeco.javacv.Java2DFrameConverter;
|
|
|
+import org.bytedeco.javacv.OpenCVFrameConverter;
|
|
|
+import org.bytedeco.opencv.opencv_core.*;
|
|
|
+import org.bytedeco.opencv.opencv_imgproc.*;
|
|
|
+import static org.bytedeco.opencv.global.opencv_core.*;
|
|
|
+import org.bytedeco.opencv.global.opencv_imgcodecs;
|
|
|
+import org.opencv.core.CvType;
|
|
|
+import org.springblade.common.utils.CommonUtil;
|
|
|
+
|
|
|
+import java.awt.image.BufferedImage;
|
|
|
+import java.io.ByteArrayOutputStream;
|
|
|
+import java.io.File;
|
|
|
+import java.io.IOException;
|
|
|
+
|
|
|
+import static org.bytedeco.opencv.global.opencv_imgcodecs.*;
|
|
|
+import static org.bytedeco.opencv.global.opencv_imgproc.*;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 简单检测图片质量
|
|
|
+ */
|
|
|
+public class ImageQualityDetectorUtils {
|
|
|
+
|
|
|
+// public static void main(String[] args) throws IOException {
|
|
|
+// try (PDDocument document = PDDocument.load(new File("C:\\Users\\泓创02\\Downloads\\73ef17c2f24ea5b83747a1ac5c2c3f0f.pdf"));
|
|
|
+// Java2DFrameConverter converter1 = new Java2DFrameConverter();
|
|
|
+// OpenCVFrameConverter.ToMat converter2 = new OpenCVFrameConverter.ToMat();) {
|
|
|
+// if (document.isEncrypted()) {
|
|
|
+// throw new RuntimeException("PDF文件已加密,请先解密");
|
|
|
+// }
|
|
|
+// // 创建PDF渲染器
|
|
|
+// PDFRenderer pdfRenderer = new PDFRenderer(document);
|
|
|
+// // 获取总页数
|
|
|
+// int pages = document.getNumberOfPages();
|
|
|
+// for (int i = 0; i < pages; i++) {
|
|
|
+// Frame frame = converter1.convert(pdfRenderer.renderImageWithDPI(i, 300));
|
|
|
+// Mat image = converter2.convert(frame);
|
|
|
+// if (image.empty()) {
|
|
|
+// System.out.println("无法加载图像");
|
|
|
+// return;
|
|
|
+// }
|
|
|
+// // 检测各种质量问题
|
|
|
+// boolean hasStains = detectLargeStains(image);
|
|
|
+// boolean isObstructed = detectTextObstruction(image);
|
|
|
+// boolean hasShadows = detectShadows(image);
|
|
|
+//
|
|
|
+// System.out.println("检测结果:");
|
|
|
+// System.out.println("大面积污渍: " + (hasStains ? "是" : "否"));
|
|
|
+// System.out.println("文字遮挡: " + (isObstructed ? "是" : "否"));
|
|
|
+// System.out.println("黑影/阴影: " + (hasShadows ? "是" : "否"));
|
|
|
+//
|
|
|
+// if (hasStains || isObstructed || hasShadows) {
|
|
|
+// System.out.println("图像质量不佳,建议重新扫描");
|
|
|
+// } else {
|
|
|
+// System.out.println("图像质量良好");
|
|
|
+// }
|
|
|
+// }
|
|
|
+// }
|
|
|
+// }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 检测图像中是否存在大面积污渍
|
|
|
+ * @param image 输入图像
|
|
|
+ * @return 污渍检测结果
|
|
|
+ */
|
|
|
+ public static boolean detectLargeStains(Mat image) {
|
|
|
+ // 转换为灰度图
|
|
|
+ Mat gray = new Mat();
|
|
|
+ cvtColor(image, gray, COLOR_BGR2GRAY);
|
|
|
+
|
|
|
+ // 应用阈值处理,突出污渍区域
|
|
|
+ Mat thresh = new Mat();
|
|
|
+ threshold(gray, thresh, 0, 255, THRESH_BINARY_INV + THRESH_OTSU);
|
|
|
+
|
|
|
+ // 形态学操作去除噪声
|
|
|
+ Mat kernel = getStructuringElement(MORPH_ELLIPSE, new Size(5, 5));
|
|
|
+ morphologyEx(thresh, thresh, MORPH_OPEN, kernel);
|
|
|
+
|
|
|
+ // 查找轮廓
|
|
|
+ MatVector contours = new MatVector();
|
|
|
+ findContours(thresh, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
|
|
|
+
|
|
|
+ // 检查是否有大面积的污渍
|
|
|
+ double imageArea = image.rows() * image.cols();
|
|
|
+ for (int i = 0; i < contours.size(); i++) {
|
|
|
+ double area = contourArea(contours.get(i));
|
|
|
+ // 如果污渍面积超过图像面积的5%,则认为存在大面积污渍
|
|
|
+ if (area > imageArea * 0.05) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 检测图像中文字是否被遮挡
|
|
|
+ * @param image 输入图像
|
|
|
+ * @return 遮挡检测结果
|
|
|
+ */
|
|
|
+ public static boolean detectTextObstruction(Mat image) {
|
|
|
+ // 转换为灰度图
|
|
|
+ Mat gray = new Mat();
|
|
|
+ cvtColor(image, gray, COLOR_BGR2GRAY);
|
|
|
+
|
|
|
+ // 边缘检测
|
|
|
+ Mat edges = new Mat();
|
|
|
+ Canny(gray, edges, 50, 150);
|
|
|
+
|
|
|
+ // 形态学操作连接边缘
|
|
|
+ Mat kernel = getStructuringElement(MORPH_RECT, new Size(3, 3));
|
|
|
+ morphologyEx(edges, edges, MORPH_CLOSE, kernel);
|
|
|
+
|
|
|
+ // 查找轮廓
|
|
|
+ MatVector contours = new MatVector();
|
|
|
+ findContours(edges, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
|
|
|
+
|
|
|
+ // 分析轮廓特征判断是否有遮挡
|
|
|
+ for (int i = 0; i < contours.size(); i++) {
|
|
|
+ Mat contour = contours.get(i);
|
|
|
+ double area = contourArea(contour);
|
|
|
+
|
|
|
+ // 计算轮廓的边界矩形
|
|
|
+ Rect boundingRect = boundingRect(contour);
|
|
|
+
|
|
|
+ // 如果区域较大但边缘不规则,可能是遮挡
|
|
|
+ if (area > 1000) {
|
|
|
+ double aspectRatio = (double) boundingRect.width() / boundingRect.height();
|
|
|
+ if (aspectRatio > 5 || aspectRatio < 0.2) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 检测图像中是否存在黑影或阴影
|
|
|
+ * @param image 输入图像
|
|
|
+ * @return 阴影检测结果
|
|
|
+ */
|
|
|
+ public static boolean detectShadows(Mat image) {
|
|
|
+ // 转换为灰度图
|
|
|
+ Mat gray = new Mat();
|
|
|
+ cvtColor(image, gray, COLOR_BGR2GRAY);
|
|
|
+
|
|
|
+ // 应用高斯模糊减少噪声
|
|
|
+ Mat blurred = new Mat();
|
|
|
+ GaussianBlur(gray, blurred, new Size(5, 5), 0);
|
|
|
+
|
|
|
+ // 计算图像的梯度
|
|
|
+ Mat gradX = new Mat();
|
|
|
+ Mat gradY = new Mat();
|
|
|
+ Sobel(blurred, gradX, CV_32F, 1, 0);
|
|
|
+ Sobel(blurred, gradY, CV_32F, 0, 1);
|
|
|
+
|
|
|
+ // 计算梯度幅值
|
|
|
+ Mat gradient = new Mat();
|
|
|
+ magnitude(gradX, gradY, gradient);
|
|
|
+
|
|
|
+ // 转换为8位图像
|
|
|
+ Mat gradient8u = new Mat();
|
|
|
+ convertScaleAbs(gradient, gradient8u);
|
|
|
+
|
|
|
+ // 应用阈值分割
|
|
|
+ Mat binary = new Mat();
|
|
|
+ threshold(gradient8u, binary, 30, 255, THRESH_BINARY);
|
|
|
+
|
|
|
+ // 计算阴影区域占比
|
|
|
+ double totalPixels = binary.rows() * binary.cols();
|
|
|
+ double shadowPixels = totalPixels - countNonZero(binary);
|
|
|
+ double shadowRatio = shadowPixels / totalPixels;
|
|
|
+
|
|
|
+ // 如果阴影区域超过10%,则认为存在明显阴影
|
|
|
+ return shadowRatio > 0.1;
|
|
|
+ }
|
|
|
+
|
|
|
+}
|