From 7451b5e60ae4c2045fb60469f52566a33c5154e6 Mon Sep 17 00:00:00 2001 From: Bingkun Li Date: Tue, 3 Mar 2026 10:39:55 +0800 Subject: [PATCH] Add image enhancement without clahe --- .../skyeye/sar/util/SarImageToneAdjuster.java | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/backend/Skyeye-sys-dev/skyeye-service-manager/src/main/java/com/zhangy/skyeye/sar/util/SarImageToneAdjuster.java b/backend/Skyeye-sys-dev/skyeye-service-manager/src/main/java/com/zhangy/skyeye/sar/util/SarImageToneAdjuster.java index e1ff3b7..387ce8f 100644 --- a/backend/Skyeye-sys-dev/skyeye-service-manager/src/main/java/com/zhangy/skyeye/sar/util/SarImageToneAdjuster.java +++ b/backend/Skyeye-sys-dev/skyeye-service-manager/src/main/java/com/zhangy/skyeye/sar/util/SarImageToneAdjuster.java @@ -803,6 +803,90 @@ public class SarImageToneAdjuster { return sharpened; } + public static Mat enhanceSarIndustrialNoClahe(Mat src) { + + if (src.channels() != 1) + throw new IllegalArgumentException("Only single channel supported"); + + Mat floatMat = new Mat(); + + // 1️⃣ 转 float + if (src.type() == CvType.CV_16U) + src.convertTo(floatMat, CvType.CV_32F, 1.0 / 65535.0); + else if (src.type() == CvType.CV_8U) + src.convertTo(floatMat, CvType.CV_32F, 1.0 / 255.0); + else + throw new IllegalArgumentException("Unsupported type"); + + // 2️⃣ log 压缩 + Core.add(floatMat, Scalar.all(1e-6), floatMat); + Core.log(floatMat, floatMat); + + // 3️⃣ 百分位裁剪 + Mat flat = floatMat.reshape(1,1); + Mat sorted = flat.clone(); + Core.sort(sorted, sorted, Core.SORT_ASCENDING); + + int total = sorted.cols(); + double low = sorted.get(0, (int)(total * 0.01))[0]; + double high = sorted.get(0, (int)(total * 0.995))[0]; + + Core.min(floatMat, new Scalar(high), floatMat); + Core.max(floatMat, new Scalar(low), floatMat); + + Core.subtract(floatMat, new Scalar(low), floatMat); + Core.divide(floatMat, new Scalar(high - low), floatMat); + + // ============================== + // 4️⃣ 局部自适应对比增强(替代 CLAHE) + // ============================== + + Mat localMean = new Mat(); + double sigma = src.cols() / 30.0; + Imgproc.GaussianBlur(floatMat, localMean, new Size(0,0), sigma); + + Mat localContrast = new Mat(); + Core.divide(floatMat, localMean, localContrast); + + // 压缩避免过增强 + Core.min(localContrast, new Scalar(3.0), localContrast); + Core.max(localContrast, new Scalar(0.3), localContrast); + + // 再归一 + Core.normalize(localContrast, localContrast, 0, 1, Core.NORM_MINMAX); + + // ============================== + // 5️⃣ 软 gamma 提升 + // ============================== + + Core.pow(localContrast, 0.8, localContrast); + + // ============================== + // 6️⃣ 转 8bit + // ============================== + + Mat img8 = new Mat(); + localContrast.convertTo(img8, CvType.CV_8U, 255.0); + + // ============================== + // 7️⃣ 轻 speckle 抑制 + // ============================== + + Imgproc.medianBlur(img8, img8, 3); + + // ============================== + // 8️⃣ 轻锐化 + // ============================== + + Mat blur = new Mat(); + Imgproc.GaussianBlur(img8, blur, new Size(0,0), 1.0); + + Mat sharpened = new Mat(); + Core.addWeighted(img8, 1.15, blur, -0.15, 0, sharpened); + + return sharpened; + } + static public double computePercentile(Mat mat, double percentile) { if (mat.empty())