|
|
|
|
@ -251,12 +251,19 @@ public class AsyncProcessingService {
|
|
|
|
|
try {
|
|
|
|
|
BufferedImage croppedImage = cropBoundingBox(originalImage, box, 30);
|
|
|
|
|
|
|
|
|
|
// 保存裁剪的原始图片用于调试
|
|
|
|
|
String debugPath = path + "_crop_" + i + "_" + j + ".jpg";
|
|
|
|
|
ImageIO.write(croppedImage, "jpg", new File(debugPath));
|
|
|
|
|
log.info("DEBUG: 裁剪图片保存到: {}, 尺寸: {}x{}, 置信度: {}",
|
|
|
|
|
debugPath, croppedImage.getWidth(), croppedImage.getHeight(), box.getConfidence());
|
|
|
|
|
|
|
|
|
|
// 最小尺寸放大
|
|
|
|
|
int minSize = 320;
|
|
|
|
|
if (croppedImage.getWidth() < minSize || croppedImage.getHeight() < minSize) {
|
|
|
|
|
int newWidth = Math.max(croppedImage.getWidth(), minSize);
|
|
|
|
|
int newHeight = Math.max(croppedImage.getHeight(), minSize);
|
|
|
|
|
croppedImage = resizeImage(croppedImage, newWidth, newHeight);
|
|
|
|
|
log.info("DEBUG: 图片已放大到: {}x{}", newWidth, newHeight);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 解码
|
|
|
|
|
@ -265,8 +272,6 @@ public class AsyncProcessingService {
|
|
|
|
|
if (qrCodeContent != null) {
|
|
|
|
|
qrCodeResults.add(qrCodeContent);
|
|
|
|
|
validBoxes.add(box);
|
|
|
|
|
} else {
|
|
|
|
|
ImageIO.write(croppedImage, "jpg", new File(path + "_" + j + ".jpg"));
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
log.error("第{}张图片解码异常,box: {}", i + 1, box, e);
|
|
|
|
|
@ -401,54 +406,65 @@ public class AsyncProcessingService {
|
|
|
|
|
|
|
|
|
|
// 2. 尝试灰度化
|
|
|
|
|
try {
|
|
|
|
|
log.info("DEBUG: 灰度化开始, image类型={}, 尺寸={}x{}", image.getType(), image.getWidth(), image.getHeight());
|
|
|
|
|
Mat mat = opencvService.bufferedImageToMat(image);
|
|
|
|
|
log.info("DEBUG: bufferedImageToMat完成, mat类型={}, channels={}, depth={}",
|
|
|
|
|
mat.type(), mat.channels(), mat.depth());
|
|
|
|
|
Mat gray = opencvService.toGrayscale(mat);
|
|
|
|
|
log.info("DEBUG: toGrayscale完成, gray channels={}, depth={}", gray.channels(), gray.depth());
|
|
|
|
|
BufferedImage grayImage = opencvService.matToBufferedImage(gray);
|
|
|
|
|
log.info("DEBUG: matToBufferedImage完成, grayImage类型={}", grayImage.getType());
|
|
|
|
|
mat.release();
|
|
|
|
|
gray.release();
|
|
|
|
|
result = tryDecode(grayImage, confidence, retryIndex, "灰度");
|
|
|
|
|
if (result != null) return result;
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
log.debug("灰度预处理失败: {}", e.getMessage());
|
|
|
|
|
log.error("灰度预处理失败: type={}, msg={}", e.getClass().getName(), e.getMessage(), e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 3. 尝试CLAHE增强
|
|
|
|
|
try {
|
|
|
|
|
log.info("DEBUG: CLAHE开始");
|
|
|
|
|
Mat mat = opencvService.bufferedImageToMat(image);
|
|
|
|
|
Mat clahe = opencvService.clahe(mat);
|
|
|
|
|
log.info("DEBUG: clahe完成, clahe channels={}, depth={}", clahe.channels(), clahe.depth());
|
|
|
|
|
BufferedImage claheImage = opencvService.matToBufferedImage(clahe);
|
|
|
|
|
mat.release();
|
|
|
|
|
clahe.release();
|
|
|
|
|
result = tryDecode(claheImage, confidence, retryIndex, "CLAHE");
|
|
|
|
|
if (result != null) return result;
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
log.debug("CLAHE预处理失败: {}", e.getMessage());
|
|
|
|
|
log.error("CLAHE预处理失败: type={}, msg={}", e.getClass().getName(), e.getMessage(), e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 4. 尝试二值化
|
|
|
|
|
try {
|
|
|
|
|
log.info("DEBUG: 二值化开始");
|
|
|
|
|
Mat mat = opencvService.bufferedImageToMat(image);
|
|
|
|
|
Mat binary = opencvService.adaptiveThreshold(mat);
|
|
|
|
|
log.info("DEBUG: adaptiveThreshold完成, binary channels={}, depth={}", binary.channels(), binary.depth());
|
|
|
|
|
BufferedImage binaryImage = opencvService.matToBufferedImage(binary);
|
|
|
|
|
mat.release();
|
|
|
|
|
binary.release();
|
|
|
|
|
result = tryDecode(binaryImage, confidence, retryIndex, "二值化");
|
|
|
|
|
if (result != null) return result;
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
log.debug("二值化预处理失败: {}", e.getMessage());
|
|
|
|
|
log.error("二值化预处理失败: type={}, msg={}", e.getClass().getName(), e.getMessage(), e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 5. 尝试组合预处理(去噪+灰度+CLAHE+二值化)
|
|
|
|
|
try {
|
|
|
|
|
log.info("DEBUG: 组合预处理开始");
|
|
|
|
|
Mat mat = opencvService.bufferedImageToMat(image);
|
|
|
|
|
Mat processed = opencvService.preprocessForQrCode(mat);
|
|
|
|
|
log.info("DEBUG: preprocessForQrCode完成, processed channels={}, depth={}", processed.channels(), processed.depth());
|
|
|
|
|
BufferedImage processedImage = opencvService.matToBufferedImage(processed);
|
|
|
|
|
mat.release();
|
|
|
|
|
processed.release();
|
|
|
|
|
result = tryDecode(processedImage, confidence, retryIndex, "组合预处理");
|
|
|
|
|
if (result != null) return result;
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
log.debug("组合预处理失败: {}", e.getMessage());
|
|
|
|
|
log.error("组合预处理失败: type={}, msg={}", e.getClass().getName(), e.getMessage(), e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
@ -509,7 +525,7 @@ public class AsyncProcessingService {
|
|
|
|
|
* 调整图片大小
|
|
|
|
|
*/
|
|
|
|
|
private BufferedImage resizeImage(BufferedImage originalImage, int targetWidth, int targetHeight) {
|
|
|
|
|
BufferedImage resizedImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_RGB);
|
|
|
|
|
BufferedImage resizedImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_3BYTE_BGR);
|
|
|
|
|
Graphics2D g2d = resizedImage.createGraphics();
|
|
|
|
|
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
|
|
|
|
g2d.drawImage(originalImage, 0, 0, targetWidth, targetHeight, null);
|
|
|
|
|
|