Test for image enhancement

This commit is contained in:
Bingkun Li 2026-03-01 17:21:17 +08:00
parent 32d8f2e5fb
commit c7f9482883
4 changed files with 134 additions and 12 deletions

View File

@ -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) {

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}
}