增加计算层高正态分布等算法

普洱算法
LAPTOP-S9HJSOEB\昊天 2 months ago
parent df0eae62a6
commit ea7cff14b5

@ -0,0 +1,205 @@
package com.example.lxcameraapi.controller;
import ai.onnxruntime.OrtException;
import com.example.lxcameraapi.conf.AppConfig;
import com.example.lxcameraapi.service.IndustrialCamera.algorithm.ONNXServiceNew;
import com.example.lxcameraapi.service.IndustrialCamera.camera.lx.LxPointCloudSaveImage;
import com.example.lxcameraapi.service.IndustrialCamera.algorithm.BoxPositionConf;
import com.example.lxcameraapi.service.IndustrialCamera.algorithm.PcdPojo;
import com.example.lxcameraapi.service.IndustrialCamera.algorithm.PointCloudProcessor;
import com.example.lxcameraapi.service.IndustrialCamera.pojo.Pojo;
import com.example.lxcameraapi.yolo.BoundingBox;
import com.example.lxcameraapi.yolo.ClassifyEntity;
import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import static com.example.lxcameraapi.controller.HikController.DATE_FORMATTER;
import static com.example.lxcameraapi.controller.HikController.TIME_FORMATTER;
@Slf4j
@RestController
@RequestMapping("/yolo")
public class YoloController {
@Resource
AppConfig appConfig;
@Resource
ONNXServiceNew onnxServiceNew;
@GetMapping("/detect")
public Pojo detect(String pic,String type) throws IOException {
Pojo pojo = new Pojo();
try {
List<BoundingBox> list = onnxServiceNew.detect(pic,type);
Integer index = ONNXServiceNew.getMaxClassIndex(list);
if (appConfig.getYoloModelConfig().getModelMap().containsKey(type)){
pojo.setCode(appConfig.getYoloModelConfig().getModelMap().get(type).getNames()[index]);
}else {
pojo.setCode(appConfig.getYoloModelConfig().getNames()[index]);
}
} catch (OrtException e) {
throw new RuntimeException(e);
}
return pojo;
}
@GetMapping("/detect")
public ClassifyEntity classifyOne(String pic,String type) throws IOException {
ClassifyEntity classifyEntity = null;
try {
classifyEntity = onnxServiceNew.classifyOne(pic,type);
} catch (OrtException e) {
throw new RuntimeException(e);
}
return classifyEntity;
}
@GetMapping("/getBoxCountByCategory")
public int getBoxCountByCategory(String streetId,String category) throws IOException {
if(category.equals("20")){
return 1;
}
String path =streetId+"\\"
+ LocalDate.now().format(DATE_FORMATTER)
+"\\"+category+"_"+ LocalDateTime.now().format(TIME_FORMATTER) +"_";
List<AppConfig.Camera> cameras = appConfig.getLxCamera();
int i = 0;
Map<Integer, String> map = new HashMap<>();
System.out.println(appConfig.getSpecialBox().toString());
for (AppConfig.SpecialBox specialBox:appConfig.getSpecialBox()){
System.out.println(category.equals(specialBox.getCategory()));
if (category.equals(specialBox.getCategory())){
map.put(specialBox.getCameraId(),specialBox.getComputeConfPath());
System.out.println(specialBox.getCameraId()+" "+specialBox.getComputeConfPath());
}
}
if (!map.isEmpty()){
log.info("map: {}", map);
System.out.println("map: "+map);
for (Integer cameraId:map.keySet()) {
for (AppConfig.Camera c : cameras) {
if (Objects.equals(c.getId(), cameraId)) {
log.info("cameraId: {}, path: {}", cameraId, path +"_"+c.getId()+ ".pcd");
LxPointCloudSaveImage.saveImage(c.getIp(), path +"_"+c.getId()+ ".pcd");
PcdPojo pojo = new PcdPojo();
pojo.setPcd1(path + "_"+c.getId()+ ".pcd");
pojo.setConfigPath(c.getConvertConfPath());
try {
pojo.setPCDInfo(pojo);
} catch (IOException e) {
throw new RuntimeException(e);
}
PointCloudProcessor pointCloudProcessor = new PointCloudProcessor();
List<BoxPositionConf> confs = pointCloudProcessor.getBoxPositionConf(map.get(c.getId()));
i += pointCloudProcessor.slicing(pojo, confs);
}
}
}
}else {
for (AppConfig.Camera c : cameras) {
if (streetId.equals(c.getStreetId())) {
log.info("cameraId: {}, path: {}", c.getId(), path +"_"+c.getId()+ ".pcd");
LxPointCloudSaveImage.saveImage(c.getIp(), path +"_"+c.getId()+ ".pcd");
PcdPojo pojo = new PcdPojo();
pojo.setPcd1(path + "_"+c.getId()+ ".pcd");
pojo.setConfigPath(c.getConvertConfPath());
try {
pojo.setPCDInfo(pojo);
} catch (IOException e) {
throw new RuntimeException(e);
}
PointCloudProcessor pointCloudProcessor = new PointCloudProcessor();
List<BoxPositionConf> confs = pointCloudProcessor.getBoxPositionConf(c.getComputeConfPath());
i += pointCloudProcessor.slicing(pojo, confs);
}
}
}
return i;
}
@GetMapping("/getBoxCountByCategoryTest")
public int getBoxCountByCategoryTest(String streetId,String category,String path1,String path2) throws IOException {
if(category.equals("20")){
return 1;
}
List<AppConfig.Camera> cameras = appConfig.getLxCamera();
int i = 0;
Map<Integer, String> map = new HashMap();
for (AppConfig.SpecialBox specialBox:appConfig.getSpecialBox()){
if (category.equals(specialBox.getCategory())){
map.put(specialBox.getCameraId(),specialBox.getComputeConfPath());
}
}
if (!map.isEmpty()){
for (Integer cameraId:map.keySet()) {
for (AppConfig.Camera c : cameras) {
if (Objects.equals(c.getId(), cameraId)) {
// LxPointCloudSaveImage.saveImage(c.getIp(), path1);
PcdPojo pojo = new PcdPojo();
if (c.getId()==1) {
pojo.setPcd1(path1);
}else {
pojo.setPcd1(path2);
}
pojo.setConfigPath(c.getConvertConfPath());
try {
pojo.setPCDInfo(pojo);
} catch (IOException e) {
throw new RuntimeException(e);
}
PointCloudProcessor pointCloudProcessor = new PointCloudProcessor();
List<BoxPositionConf> confs = pointCloudProcessor.getBoxPositionConf(map.get(c.getId()));
i += pointCloudProcessor.slicing(pojo, confs);
}
}
}
}else {
for (AppConfig.Camera c : cameras) {
if (streetId.equals(c.getStreetId())) {
String sn = UUID.randomUUID().toString();
PcdPojo pojo = new PcdPojo();
if (c.getId()==1) {
pojo.setPcd1(path1);
}else {
pojo.setPcd1(path2);
}
pojo.setConfigPath(c.getConvertConfPath());
try {
pojo.setPCDInfo(pojo);
} catch (IOException e) {
throw new RuntimeException(e);
}
PointCloudProcessor pointCloudProcessor = new PointCloudProcessor();
List<BoxPositionConf> confs = pointCloudProcessor.getBoxPositionConf(c.getComputeConfPath());
i += pointCloudProcessor.slicing(pojo, confs);
}
}
}
return i;
}
}

@ -29,6 +29,9 @@ public class PcdPojo {
//随行路径 configProperties.getSavePath().getMediaPath() + street.getLeft3D()+"000/"+ currentDate.format(formatter)+"/"+transmissionPojo.getRow()+".pcd";
private String pcd1;
private String pcd2;
private Integer functionType = 1;//1 中位数 2 平均值 3 正态分布
private Integer fluctuate= 80;
private String pcd4;
private String cameraSn1;
private String cameraSn2;

@ -3,6 +3,7 @@ package com.example.lxcameraapi.service.IndustrialCamera.algorithm;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
@ -21,6 +22,7 @@ import java.util.*;
import java.util.List;
import java.util.stream.Collectors;
@Slf4j
public class PointCloudProcessor {
//
@ -235,6 +237,66 @@ public class PointCloudProcessor {
return sum / (values.size() - 2 * trimCount);
}
/**
* 根据 functionType 计算点云层高
*
* @param zValues 层匹配范围内所有点的 z 坐标
* @param functionType 1 中位数, 2 平均值, 3 正态分布(直方图峰值)
* @return 计算得到的层高,无数据时返回 NaN
*/
private static double calculateLayerHeight(List<Double> zValues, Integer functionType) {
if (zValues == null || zValues.isEmpty()) {
return Double.NaN;
}
int type = functionType == null ? 1 : functionType;
List<Double> sorted = new ArrayList<>(zValues);
sorted.sort(Comparator.naturalOrder());
switch (type) {
case 2: // 平均值
return sorted.stream().mapToDouble(Double::doubleValue).average().orElse(Double.NaN);
case 3: // 正态分布:直方图峰值
return histogramPeak(sorted);
default: // 中位数
int size = sorted.size();
if (size % 2 == 1) {
return sorted.get(size / 2);
}
return (sorted.get(size / 2 - 1) + sorted.get(size / 2)) / 2.0;
}
}
/**
* 正态分布:将数据分为多个区间,返回点数最多的区间中心值(近似峰值)
*/
private static double histogramPeak(List<Double> values) {
double min = values.get(0);
double max = values.get(values.size() - 1);
if (max - min < 1e-9) {
return min;
}
int bins = 100; // 直方图区间数
double binWidth = (max - min) / bins;
int[] counts = new int[bins];
double[] binCenter = new double[bins];
for (int i = 0; i < bins; i++) {
binCenter[i] = min + (i + 0.5) * binWidth;
}
for (double v : values) {
int idx = (int) ((v - min) / binWidth);
if (idx >= bins) {
idx = bins - 1;
}
counts[idx]++;
}
int maxIdx = 0;
for (int i = 1; i < bins; i++) {
if (counts[i] > counts[maxIdx]) {
maxIdx = i;
}
}
return binCenter[maxIdx];
}
public static List<double[]> readPCD(String filePath) {
try {
if (isBinaryFormat(filePath)) {
@ -439,9 +501,9 @@ public class PointCloudProcessor {
// pojo.setPcd1("D:\\data\\test\\1巷道\\F83C51123126\\3766_173016547__2.pcd");
// pojo.setConfigPath("D:\\data\\test\\1巷道\\F83C51123126\\cj.json");
// String pz = "D:\\data\\test\\1巷道\\F83C51123126\\pz.json";
pojo.setPcd1("D:\\xwechat_files\\wxid_ttkf0xgmyihv22_2388\\msg\\file\\2026-07\\3766_173056141__2.pcd");
pojo.setConfigPath("D:\\xwechat_files\\wxid_ttkf0xgmyihv22_2388\\msg\\file\\2026-07\\cj.json");
String pz = "D:\\xwechat_files\\wxid_ttkf0xgmyihv22_2388\\msg\\file\\2026-07\\pz.json";
pojo.setPcd1("D:\\desktop\\新建文件夹\\673\\0184_082322214__1.pcd");
pojo.setConfigPath("D:\\desktop\\新建文件夹\\670\\cj.json");
String pz = "D:\\desktop\\新建文件夹\\670\\pz.json";
try {
pojo.setPCDInfo(pojo);
@ -616,7 +678,15 @@ public class PointCloudProcessor {
System.out.println(" 第" + i + "层: height=" + conf.getHeight() + ", 盒子数=" + conf.getPosition().size());
}
// 计算每层的 Z 轴匹配范围(相邻层取中间值,首尾层留±300边距)
// 计算pcd1
List<double[]> points = readPCD(pojo.getPcd1());
if (points == null || points.isEmpty()) {
System.out.println("点云数据为空!");
return 0;
}
System.out.println("点云总点数: " + points.size());
// 1. 计算每层的初始 Z 轴匹配范围(相邻层取中间值,首尾层留±300边距)
double[][] zRanges = new double[boxPositionConfs.size()][2];
for (int i = 0; i < boxPositionConfs.size(); i++) {
double currentHeight = boxPositionConfs.get(i).getHeight();
@ -633,16 +703,32 @@ public class PointCloudProcessor {
zRanges[i][0] = (boxPositionConfs.get(i - 1).getHeight() + currentHeight) / 2.0;
zRanges[i][1] = (currentHeight + boxPositionConfs.get(i + 1).getHeight()) / 2.0;
}
System.out.println(" 第" + i + "层 Z范围: [" + zRanges[i][0] + ", " + zRanges[i][1] + "]");
System.out.println(" 第" + i + "层 初始Z范围: [" + zRanges[i][0] + ", " + zRanges[i][1] + "]");
}
// 计算pcd1
List<double[]> points = readPCD(pojo.getPcd1());
if (points == null || points.isEmpty()) {
System.out.println("点云数据为空!");
return 0;
// 2. 根据每层初始匹配范围内的所有点,按 functionType 计算每层实际高度(1 中位数 / 2 平均值 / 3 正态分布)
// 3. 用计算得到的值 ± fluctuate 构成新的 Z 轴匹配范围
int fluctuate = pojo.getFluctuate() == null ? 80 : pojo.getFluctuate();
for (int i = 0; i < boxPositionConfs.size(); i++) {
List<Double> zValues = new ArrayList<>();
for (double[] point : points) {
double[] rotated = rotatePoints(point, pojo.getRotationMatrix());
if (rotated[2] >= zRanges[i][0] && rotated[2] <= zRanges[i][1]) {
zValues.add(rotated[2]);
}
}
double layerHeight = calculateLayerHeight(zValues, pojo.getFunctionType());
if (Double.isNaN(layerHeight)) {
// 该层初始范围内没有点,沿用配置高度
layerHeight = boxPositionConfs.get(i).getHeight();
log.info(" 第" + i + "层 匹配范围内无点,沿用配置高度: " + layerHeight);
} else {
log.info(" 第" + i + "层 匹配点数=" + zValues.size() + ", 计算实际高度=" + layerHeight);
}
zRanges[i][0] = layerHeight - fluctuate;
zRanges[i][1] = layerHeight + fluctuate;
log.info(" 第" + i + "层 新Z范围(±" + fluctuate + "): [" + zRanges[i][0] + ", " + zRanges[i][1] + "]");
}
System.out.println("点云总点数: " + points.size());
Map<Integer, Integer> map = new HashMap <>();
Map<Integer, Double[]> listMap = new HashMap<>();
@ -697,7 +783,7 @@ public class PointCloudProcessor {
count = baseCount;
int currentLayerCount = 0;
System.out.println(">>> 检查第" +i + "层 (height=" + boxPositionConfs.get(i).getHeight()
log.info(">>> 检查第" +i + "层 (height=" + boxPositionConfs.get(i).getHeight()
+ ", Z范围=[" + zRanges[i][0] + "," + zRanges[i][1]
+ "], 盒子数=" + boxPositionConfs.get(i).getPosition().size() + "), baseCount=" + baseCount);
@ -709,11 +795,11 @@ public class PointCloudProcessor {
count += 1;
currentLayerCount++;
}
System.out.println(" 盒子[" + (j+1 )+ "] position=" + position + ", 点数=" + pointCount
log.info(" 盒子[" + (j+1 )+ "] position=" + position + ", 点数=" + pointCount
+ (hasData ? " [有货]" : " [空]"));
}
System.out.println(" 第" + i + "层有货盒子数: " + currentLayerCount + ", 累计count=" + count);
log.info(" 第" + i + "层有货盒子数: " + currentLayerCount + ", 累计count=" + count);
if (count > baseCount) {
System.out.println(">>> 在第" + i + "层发现货物,停止向上查找 <<<");

@ -1,7 +1,10 @@
package com.example.lxcameraapi.service.IndustrialCamera.pojo;
import com.example.lxcameraapi.yolo.BoundingBox;
import lombok.Data;
import java.util.List;
@Data
public class Pojo {
//旋转路径
@ -10,4 +13,11 @@ public class Pojo {
private String determinePath;
//结果
private Boolean result;
private String code;
private String type;
private List<BoundingBox> detects;
private String path;
private String streetId;
private Integer direction;
}

Loading…
Cancel
Save