From c7f948288306dda99f055fdbc8b30e1b8c126606 Mon Sep 17 00:00:00 2001 From: Bingkun Li Date: Sun, 1 Mar 2026 17:21:17 +0800 Subject: [PATCH] Test for image enhancement --- .../skyeye/jm/controller/JmJobController.java | 5 + .../skyeye/publics/utils/ImageUtil.java | 2 +- .../sar/service/impl/SarImageServiceImpl.java | 24 ++-- .../skyeye/sar/util/SarImageToneAdjuster.java | 115 ++++++++++++++++++ 4 files changed, 134 insertions(+), 12 deletions(-) diff --git a/backend/Skyeye-sys-dev/skyeye-service-manager/src/main/java/com/zhangy/skyeye/jm/controller/JmJobController.java b/backend/Skyeye-sys-dev/skyeye-service-manager/src/main/java/com/zhangy/skyeye/jm/controller/JmJobController.java index 56e04b9..baa4c02 100644 --- a/backend/Skyeye-sys-dev/skyeye-service-manager/src/main/java/com/zhangy/skyeye/jm/controller/JmJobController.java +++ b/backend/Skyeye-sys-dev/skyeye-service-manager/src/main/java/com/zhangy/skyeye/jm/controller/JmJobController.java @@ -5,6 +5,7 @@ import com.zhangy.skyeye.common.extend.anno.IgnoreAuth; import com.zhangy.skyeye.common.extend.enums.EnumUtil; import com.zhangy.skyeye.common.extend.exception.ServiceException; import com.zhangy.skyeye.common.extend.util.DateUtil; +import com.zhangy.skyeye.common.extend.util.ObjectUtil; import com.zhangy.skyeye.common.pojo.result.Result; import com.zhangy.skyeye.jm.consts.JmJobModeEnum; import com.zhangy.skyeye.jm.dto.JmJobDTO; @@ -77,6 +78,10 @@ public class JmJobController { @PostMapping("/save") public Object insert(@Valid @RequestBody JmJobDTO e) { JmJobModeEnum mode = EnumUtil.parseEx(JmJobModeEnum.class, e.getMode()); + if (mode != JmJobModeEnum.CRUISE && ObjectUtil.isEmpty(e.getPointList())) { + throw ServiceException.noLog("任务点不能为空"); + } + clearId(e); // 默认执行一次性任务 if (e.getType() == null) { diff --git a/backend/Skyeye-sys-dev/skyeye-service-manager/src/main/java/com/zhangy/skyeye/publics/utils/ImageUtil.java b/backend/Skyeye-sys-dev/skyeye-service-manager/src/main/java/com/zhangy/skyeye/publics/utils/ImageUtil.java index 2374539..03b9f1c 100644 --- a/backend/Skyeye-sys-dev/skyeye-service-manager/src/main/java/com/zhangy/skyeye/publics/utils/ImageUtil.java +++ b/backend/Skyeye-sys-dev/skyeye-service-manager/src/main/java/com/zhangy/skyeye/publics/utils/ImageUtil.java @@ -45,7 +45,7 @@ public class ImageUtil { int lightRate = rotateDTO.getLightRate(); if (lightRate != 0) { //OpenCVUtil.multiply(image, lightRate); - OpenCVUtil.enhanceContrast(image, lightRate, 0); + // OpenCVUtil.enhanceContrast(image, lightRate, 0); } return image; } diff --git a/backend/Skyeye-sys-dev/skyeye-service-manager/src/main/java/com/zhangy/skyeye/sar/service/impl/SarImageServiceImpl.java b/backend/Skyeye-sys-dev/skyeye-service-manager/src/main/java/com/zhangy/skyeye/sar/service/impl/SarImageServiceImpl.java index b08d0ea..939fd01 100644 --- a/backend/Skyeye-sys-dev/skyeye-service-manager/src/main/java/com/zhangy/skyeye/sar/service/impl/SarImageServiceImpl.java +++ b/backend/Skyeye-sys-dev/skyeye-service-manager/src/main/java/com/zhangy/skyeye/sar/service/impl/SarImageServiceImpl.java @@ -211,15 +211,17 @@ public class SarImageServiceImpl implements ISarImageService { redisUtil.hset("jmImgJoin-" + airlineExecId, CACHE_FIELD_CURR_FRAME_NO, frameNo, CACHE_EXPIRE_SECOND);// 更新帧号 // ### 亮度调整,用于可靠udp版本图像,固定使用系数0.5 // 拆分多张图片,去掉自适应调整 - if (IMG_MAX_WITH > 20000) { + // if (IMG_MAX_WITH > 20000) { SarImageToneAdjuster.autoToneWithClipping(baseMat, 0.5f); + // Mat enhancedImage = SarImageToneAdjuster.enhanceSarImage(baseMat); // RadarDisplayOptions options = new RadarDisplayOptions(); // SarImageToneAdjuster.processForDisplayMat(baseMat, options); // SarImageToneAdjuster.applyPseudoColorMat(baseMat, options); - } + //} // 5.保存后处理图(异步),用于前端显示 generateAfterMat(currAirline, baseMat, currPath, uav.getSarImageLight()); + // generateAfterMat(currAirline, enhancedImage, currPath, uav.getSarImageLight()); // 6.更新基准图坐标和帧号 JmImage imageInfo = saveImage(uav, airlineExecId, base, imagePath, imageFrame, frameNo, lostImage); @@ -275,15 +277,15 @@ public class SarImageServiceImpl implements ISarImageService { private Mat generateBaseMat(JmImage base, Mat currImage, int currNo, float currMax, String imagePath, Integer baseNo) { Mat baseImage = OpenCVUtil.read(imagePath); // 从硬盘加载基准图 // 归一化调整 - if (base.getId() != null) { - float baseMax = base.getMax(); - //System.out.println("基准图:" + baseMax + ",当前图:" + currMax); - if (baseMax < currMax) { - OpenCVUtil.multiply(baseImage, baseMax / currMax); - } else if (baseMax > currMax) { - OpenCVUtil.multiply(currImage , currMax / baseMax); - } - } +// if (base.getId() != null) { +// float baseMax = base.getMax(); +// //System.out.println("基准图:" + baseMax + ",当前图:" + currMax); +// if (baseMax < currMax) { +// OpenCVUtil.multiply(baseImage, baseMax / currMax); +// } else if (baseMax > currMax) { +// OpenCVUtil.multiply(currImage , currMax / baseMax); +// } +// } Mat baseMat = ImageUtil.join(baseImage, baseNo, currImage, currNo); // 会释放 currImage baseImage 资源 if (baseMat != null) { // 若拼接成功则回写硬盘,拼接失败按丢图处理,不改动基准图 OpenCVUtil.write(imagePath, baseMat, false); 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 a7f19eb..096f80f 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 @@ -2,11 +2,14 @@ package com.zhangy.skyeye.sar.util; import org.opencv.core.*; import org.opencv.imgcodecs.Imgcodecs; +import org.opencv.imgproc.CLAHE; import org.opencv.imgproc.Imgproc; import org.opencv.core.Core; import org.opencv.core.CvType; import org.opencv.core.Mat; +import org.opencv.photo.Photo; +import org.opencv.photo.Tonemap; import java.util.ArrayList; import java.util.List; @@ -643,4 +646,116 @@ public class SarImageToneAdjuster { image.put(0, 0, data); } + + /** + * Reinhard 局部色调映射 + */ + public static Mat reinhardToneMapping(Mat src, + float gamma, + float intensity, + float lightAdapt, + float colorAdapt) { + + Mat srcFloat = new Mat(); + src.convertTo(srcFloat, CvType.CV_32FC3, 1.0 / 255.0); + + // 注意这里的类型 + Tonemap tonemap = Photo.createTonemapReinhard( + gamma, + intensity, + lightAdapt, + colorAdapt + ); + + Mat dstFloat = new Mat(); + tonemap.process(srcFloat, dstFloat); + + Mat dst = new Mat(); + dstFloat.convertTo(dst, CvType.CV_8UC3, 255.0); + + return dst; + } + + /** + * 对输入图像做 CLAHE (在 LAB 空间) + */ + public static Mat applyCLAHEGray(Mat src, + double clipLimit, + Size tileGridSize) { + + CLAHE clahe = Imgproc.createCLAHE(); + clahe.setClipLimit(clipLimit); + clahe.setTilesGridSize(tileGridSize); + + Mat dst = new Mat(); + clahe.apply(src, dst); + + return dst; + } + + public static Mat enhanceSarImage(Mat src) { + + if (src.channels() != 1) { + throw new IllegalArgumentException("Only single channel supported"); + } + + Mat floatMat = new Mat(); + + // ========================= + // 转 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"); + } + + // ========================= + // log 压缩 + // ========================= + Core.add(floatMat, Scalar.all(1e-6), floatMat); + Core.log(floatMat, floatMat); + + // ========================= + // 固定裁剪 + // ========================= + double low = -8; // 根据你的数据调 + double high = 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); + // Core.normalize(floatMat, floatMat, 0.0, 1.0, Core.NORM_MINMAX); + + // ========================= + // 转 8bit + // ========================= + Mat img8 = new Mat(); + floatMat.convertTo(img8, CvType.CV_8U, 255.0); + + // ========================= + // CLAHE + // ========================= + CLAHE clahe = Imgproc.createCLAHE(); + clahe.setClipLimit(3.0); + clahe.setTilesGridSize(new Size(8, 8)); + + Mat claheOut = new Mat(); + clahe.apply(img8, claheOut); + + // ========================= + // Unsharp Mask + // ========================= + Mat blur = new Mat(); + Imgproc.GaussianBlur(claheOut, blur, new Size(0,0), 1.0); + + Mat sharpened = new Mat(); + Core.addWeighted(claheOut, 1.3, blur, -0.3, 0, sharpened); + + return sharpened; + } } \ No newline at end of file