├── README.md ├── img ├── prediction.jpg └── test.webp ├── pom.xml ├── requirements.txt ├── src └── main │ ├── java │ ├── sy │ │ ├── Detection.java │ │ ├── ImageUtil.java │ │ ├── MainTest.java │ │ └── ModelDet.java │ └── utils │ │ ├── CollectionUtil.java │ │ └── PropertiesReader.java │ └── resources │ ├── model │ ├── label.names │ └── model.onnx │ └── properties.properties └── target └── classes ├── META-INF └── layout_analysis4j.kotlin_module ├── model ├── label.names └── model.onnx ├── properties.properties ├── sy ├── Detection.class ├── ImageUtil.class ├── MainTest.class └── ModelDet.class └── utils ├── CollectionUtil.class └── PropertiesReader.class /README.md: -------------------------------------------------------------------------------- 1 | ### 利用java-yolov8实现版面检测 2 | 利用java加载yolov8模型,进行推理,以及前后处理均以java实现。 3 | 4 | java-yolov8 is used to detect the layout of Chinese document images 5 | 6 | #### 模型下载、推理 7 | 本项目根据开源中文版面数据[CDLA](https://github.com/buptlihang/CDLA) ,利用yolov8进行训练 8 | 9 | CDLA是一个中文文档版面分析数据集,面向中文文献类(论文)场景。包含以下10个label: 10 | 11 | |正文|标题|图片|图片标题|表格|表格标题|页眉|页脚|注释|公式| 12 | |---|---|---|---|---|---|---|---|---|---| 13 | |Text|Title|Figure|Figure caption|Table|Table caption|Header|Footer|Reference|Equation| 14 | 15 | 模型下载: 16 | 17 | 链接:https://pan.baidu.com/s/1cqMLPKcIOatXmCxmR3QnVQ 18 | 19 | 提取码:g39u 20 | 21 | 推理:src/main/java/sy 22 | ``` 23 | public static void main(String...args) { 24 | String modelPath = MainTest.class.getClassLoader().getResource(PropertiesReader.get("model_path")).getPath().replaceFirst("/", ""); 25 | String labelPath = MainTest.class.getClassLoader().getResource(PropertiesReader.get("table_det_labels_path")).getPath().replaceFirst("/", ""); 26 | String imgPath = "D:\\project\\idea_workspace\\layout_analysis4j\\img\\test.webp"; 27 | 28 | try { 29 | ModelDet modelDet = new ModelDet(modelPath, labelPath); 30 | Mat img = Imgcodecs.imread(imgPath); 31 | if (img.dataAddr() == 0) { 32 | System.out.println("Could not open image: " + imgPath); 33 | System.exit(1); 34 | } 35 | // run detection 36 | try { 37 | List detectionList = modelDet.detectObjects(img); 38 | 39 | ImageUtil.drawPredictions(img, detectionList); 40 | System.out.println(JSON.toJSONString(detectionList)); 41 | Imgcodecs.imwrite("D:\\project\\idea_workspace\\layout_analysis4j\\img\\prediction.jpg", img); 42 | } catch (OrtException ortException) { 43 | ortException.printStackTrace(); 44 | } 45 | 46 | } catch (OrtException e) { 47 | e.printStackTrace(); 48 | } 49 | } 50 | ``` 51 | 52 |
53 |

54 | 55 | 56 | 57 |

58 |
59 | 60 | 61 | #### contact 62 | 63 | 1、github:https://github.com/jiangnanboy 64 | 65 | 2、博客:https://www.cnblogs.com/little-horse/ 66 | 67 | 3、邮件:2229029156@qq.com 68 | 69 | #### reference 70 | https://github.com/jiangnanboy/layout_analysis 71 | 72 | https://github.com/ultralytics/ultralytics 73 | 74 | https://github.com/buptlihang/CDLA 75 | 76 | -------------------------------------------------------------------------------- /img/prediction.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiangnanboy/layout_analysis4j/710bf41c11bc0d26f991aee14e4ea995f246fd19/img/prediction.jpg -------------------------------------------------------------------------------- /img/test.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiangnanboy/layout_analysis4j/710bf41c11bc0d26f991aee14e4ea995f246fd19/img/test.webp -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.example 8 | layout_analysis4j 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 13 | com.microsoft.onnxruntime 14 | onnxruntime 15 | 1.11.0 16 | 17 | 18 | 19 | com.alibaba.fastjson2 20 | fastjson2 21 | 2.0.20 22 | 23 | 24 | 25 | org.bytedeco 26 | javacv-platform 27 | 1.5.7 28 | 29 | 30 | 31 | org.bytedeco 32 | javacpp 33 | 1.5.7 34 | 35 | 36 | 37 | org.bytedeco 38 | openblas 39 | 0.3.19-1.5.7 40 | 41 | 42 | 43 | org.slf4j 44 | slf4j-api 45 | 1.7.25 46 | 47 | 48 | 49 | org.slf4j 50 | slf4j-simple 51 | 1.7.25 52 | 53 | 54 | 55 | org.apache.commons 56 | commons-lang3 57 | 3.7 58 | 59 | 60 | 61 | ai.djl.opencv 62 | opencv 63 | 0.17.0 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | java=11 2 | onnxruntime=1.11.0 3 | javacv-platform=1.5.7 4 | ... 5 | 6 | -------------------------------------------------------------------------------- /src/main/java/sy/Detection.java: -------------------------------------------------------------------------------- 1 | package sy; 2 | 3 | /** 4 | * @author sy 5 | * @date 2023/5/2 14:44 6 | */ 7 | public class Detection { 8 | private String label; 9 | private int labelIndex; 10 | private float[] bbox; 11 | private float confidence; 12 | 13 | public String getLabel() { 14 | return label; 15 | } 16 | 17 | public int getLabelIndex() { 18 | return labelIndex; 19 | } 20 | public float[] getBbox() { 21 | return bbox; 22 | } 23 | 24 | public float getConfidence() { 25 | return confidence; 26 | } 27 | 28 | public Detection(String label, int labelIndex, float[] bbox, float confidence) { 29 | this.label = label; 30 | this.labelIndex = labelIndex; 31 | this.bbox = bbox; 32 | this.confidence = confidence; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/sy/ImageUtil.java: -------------------------------------------------------------------------------- 1 | package sy; 2 | 3 | import org.opencv.core.*; 4 | import org.opencv.imgproc.Imgproc; 5 | import utils.CollectionUtil; 6 | 7 | import java.util.Comparator; 8 | import java.util.List; 9 | import java.util.Map; 10 | import java.util.stream.Collectors; 11 | 12 | /** 13 | * @author sy 14 | * @date 2023/5/2 13:48 15 | */ 16 | public class ImageUtil { 17 | 18 | public static float[] whc2cwh(float[] src) { 19 | float[] chw = new float[src.length]; 20 | int j = 0; 21 | for (int ch = 0; ch < 3; ++ch) { 22 | for (int i = ch; i < src.length; i += 3) { 23 | chw[j] = src[i]; 24 | j++; 25 | } 26 | } 27 | return chw; 28 | } 29 | 30 | private static final Map COLOR_MAP = Map.of( 31 | 0, new Scalar(220, 50, 0), 32 | 1, new Scalar(0, 200, 0), 33 | 2, new Scalar(0, 0, 200), 34 | 3, new Scalar(200, 200, 0), 35 | 4, new Scalar(200, 0, 200), 36 | 5, new Scalar(0, 200, 200), 37 | 6, new Scalar(200, 100, 60), 38 | 7, new Scalar(60, 50, 249), 39 | 8, new Scalar(10, 60, 249), 40 | 9, new Scalar(60, 100, 10) 41 | ); 42 | 43 | public static void drawPredictions(Mat img, List detectionList) { 44 | // debugging image 45 | for (Detection detection : detectionList) { 46 | float[] bbox = detection.getBbox(); 47 | Scalar color = COLOR_MAP.get(detection.getLabelIndex()); 48 | Imgproc.rectangle(img, //Matrix obj of the image 49 | new Point(bbox[0], bbox[1]), //p1 50 | new Point(bbox[2], bbox[3]), //p2 51 | color, //Scalar object for color 52 | 2 //Thickness of the line 53 | ); 54 | Imgproc.putText( 55 | img, 56 | detection.getLabel(), 57 | new Point(bbox[0] - 1, bbox[1] - 5), 58 | Imgproc.FONT_HERSHEY_SIMPLEX, 59 | .5, color, 60 | 1); 61 | } 62 | } 63 | public static void xywh2xyxy(float[] bbox) { 64 | float x = bbox[0]; 65 | float y = bbox[1]; 66 | float w = bbox[2]; 67 | float h = bbox[3]; 68 | bbox[0] = x - w * 0.5f; 69 | bbox[1] = y - h * 0.5f; 70 | bbox[2] = x + w * 0.5f; 71 | bbox[3] = y + h * 0.5f; 72 | } 73 | 74 | public static List nonMaxSuppression(List bboxes, float iouThreshold) { 75 | // output boxes 76 | List bestBboxes = CollectionUtil.newArrayList(); 77 | // confidence 78 | bboxes.sort(Comparator.comparing(a -> a[4])); 79 | // standard nms 80 | while (!bboxes.isEmpty()) { 81 | float[] bestBbox = bboxes.remove(bboxes.size() - 1); 82 | bestBboxes.add(bestBbox); 83 | bboxes = bboxes.stream().filter(a -> computeIOU(a, bestBbox) < iouThreshold).collect(Collectors.toList()); 84 | } 85 | return bestBboxes; 86 | } 87 | 88 | public static float computeIOU(float[] box1, float[] box2) { 89 | float area1 = (box1[2] - box1[0]) * (box1[3] - box1[1]); 90 | float area2 = (box2[2] - box2[0]) * (box2[3] - box2[1]); 91 | 92 | float left = Math.max(box1[0], box2[0]); 93 | float top = Math.max(box1[1], box2[1]); 94 | float right = Math.min(box1[2], box2[2]); 95 | float bottom = Math.min(box1[3], box2[3]); 96 | 97 | float interArea = Math.max(right - left, 0) * Math.max(bottom - top, 0); 98 | float unionArea = area1 + area2 - interArea; 99 | return Math.max(interArea / unionArea, 1e-8f); 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/sy/MainTest.java: -------------------------------------------------------------------------------- 1 | package sy; 2 | 3 | import ai.onnxruntime.OrtException; 4 | import com.alibaba.fastjson2.JSON; 5 | import org.opencv.core.Mat; 6 | import org.opencv.imgcodecs.Imgcodecs; 7 | import utils.PropertiesReader; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * @author sy 13 | * @date 2023/5/2 15:49 14 | */ 15 | public class MainTest { 16 | public static void main(String...args) { 17 | String modelPath = MainTest.class.getClassLoader().getResource(PropertiesReader.get("model_path")).getPath().replaceFirst("/", ""); 18 | String labelPath = MainTest.class.getClassLoader().getResource(PropertiesReader.get("table_det_labels_path")).getPath().replaceFirst("/", ""); 19 | String imgPath = "D:\\project\\idea_workspace\\layout_analysis4j\\img\\test.webp"; 20 | 21 | try { 22 | ModelDet modelDet = new ModelDet(modelPath, labelPath); 23 | Mat img = Imgcodecs.imread(imgPath); 24 | if (img.dataAddr() == 0) { 25 | System.out.println("Could not open image: " + imgPath); 26 | System.exit(1); 27 | } 28 | // run detection 29 | try { 30 | List detectionList = modelDet.detectObjects(img); 31 | 32 | ImageUtil.drawPredictions(img, detectionList); 33 | System.out.println(JSON.toJSONString(detectionList)); 34 | Imgcodecs.imwrite("D:\\project\\idea_workspace\\layout_analysis4j\\img\\prediction.jpg", img); 35 | } catch (OrtException ortException) { 36 | ortException.printStackTrace(); 37 | } 38 | 39 | } catch (OrtException e) { 40 | e.printStackTrace(); 41 | } 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/sy/ModelDet.java: -------------------------------------------------------------------------------- 1 | package sy; 2 | 3 | import ai.onnxruntime.*; 4 | import org.opencv.core.CvType; 5 | import org.opencv.core.Mat; 6 | import org.opencv.core.Size; 7 | import org.opencv.imgproc.Imgproc; 8 | import utils.CollectionUtil; 9 | 10 | import java.io.IOException; 11 | import java.nio.FloatBuffer; 12 | import java.nio.file.Files; 13 | import java.nio.file.Paths; 14 | import java.util.*; 15 | import java.util.stream.Collectors; 16 | import java.util.stream.Stream; 17 | 18 | /** 19 | * @author sy 20 | * @date 2023/5/2 13:48 21 | */ 22 | public class ModelDet { 23 | float confThreshold; 24 | float iouThreshold; 25 | long inputHeight; 26 | long inputWidth; 27 | long[] inputShape; 28 | int numInputElements; 29 | OnnxJavaType inputType; 30 | OrtEnvironment env; 31 | OrtSession session; 32 | String inputName; 33 | String outputName; 34 | 35 | long rawImgHeight; 36 | long rawImgWidth; 37 | 38 | public List labelNames; 39 | 40 | public ModelDet(String path, String labelPath) throws OrtException { 41 | this(path, labelPath, 0.3f, 0.5f); 42 | } 43 | 44 | public ModelDet(String path, String labelPath, float confThres, float iouThres) throws OrtException { 45 | this.confThreshold = confThres; 46 | this.iouThreshold = iouThres; 47 | initializeModel(path); 48 | initializeLabel(labelPath); 49 | } 50 | 51 | private void initializeModel(String path) throws OrtException { 52 | nu.pattern.OpenCV.loadLocally(); 53 | this.initializeModel(path, -1); 54 | } 55 | 56 | private void initializeModel(String path, int gpuDeviceId) throws OrtException { 57 | this.env = OrtEnvironment.getEnvironment(); 58 | var sessionOptions = new OrtSession.SessionOptions(); 59 | sessionOptions.setOptimizationLevel(OrtSession.SessionOptions.OptLevel.ALL_OPT); 60 | if(gpuDeviceId >= 0) { 61 | sessionOptions.addCPU(false); 62 | sessionOptions.addCUDA(gpuDeviceId); 63 | } else { 64 | sessionOptions.addCPU(true); 65 | } 66 | this.session = this.env.createSession(path, sessionOptions); 67 | 68 | Map inputMetaMap = this.session.getInputInfo(); 69 | this.inputName = this.session.getInputNames().iterator().next(); 70 | NodeInfo inputMeta = inputMetaMap.get(this.inputName); 71 | this.inputType = ((TensorInfo)inputMeta.getInfo()).type; 72 | this.inputShape = ((TensorInfo) inputMeta.getInfo()).getShape(); 73 | this.numInputElements = (int) (this.inputShape[1] * this.inputShape[2] * this.inputShape[3]); 74 | this.inputHeight = this.inputShape[2]; 75 | this.inputWidth = this.inputShape[3]; 76 | this.outputName = this.session.getOutputNames().iterator().next(); 77 | } 78 | 79 | private void initializeLabel(String labelPath) { 80 | try(Stream lines = Files.lines(Paths.get(labelPath))) { 81 | labelNames = lines.map(line -> line.strip()).collect(Collectors.toList()); 82 | } catch (IOException e) { 83 | e.printStackTrace(); 84 | } 85 | } 86 | 87 | public List detectObjects(Mat img) throws OrtException { 88 | Map inputMap = this.prepareInput(img); 89 | float[][] predictions = inference(inputMap); 90 | List detectionList = this.processOutput(predictions); 91 | return detectionList; 92 | } 93 | 94 | private float[][] inference(Map inputMap) throws OrtException { ; 95 | OrtSession.Result result = this.session.run(inputMap); 96 | float[][] predicitons = ((float[][][])result.get(0).getValue())[0]; 97 | return predicitons; 98 | } 99 | 100 | private Map prepareInput(Mat img) throws OrtException { 101 | this.rawImgHeight = img.height(); 102 | this.rawImgWidth = img.width(); 103 | Mat inputImg = new Mat(); 104 | Imgproc.cvtColor(img, inputImg, Imgproc.COLOR_BGR2RGB); 105 | Imgproc.resize(inputImg, inputImg, new Size(this.inputWidth, this.inputHeight)); 106 | inputImg.convertTo(inputImg, CvType.CV_32FC3, 1./255); 107 | 108 | Map inputMap = CollectionUtil.newHashMap(); 109 | float[] whc = new float[this.numInputElements]; 110 | inputImg.get(0, 0, whc); 111 | float[] chw = ImageUtil.whc2cwh(whc); 112 | FloatBuffer inputBuffer= FloatBuffer.wrap(chw); 113 | OnnxTensor inputTensor = OnnxTensor.createTensor(this.env, inputBuffer, this.inputShape); 114 | inputMap.put(this.inputName, inputTensor); 115 | return inputMap; 116 | } 117 | 118 | private List processOutput(float[][] predictions) { 119 | // prediction 120 | predictions = transposeMatrix(predictions); 121 | Map> class2Bbox = CollectionUtil.newHashMap(); 122 | for(float[] bbox : predictions) { 123 | float[] condProb = Arrays.copyOfRange(bbox, 4, bbox.length); 124 | int label = predMax(condProb); 125 | float conf = condProb[label]; 126 | if(conf < this.confThreshold) { 127 | continue; 128 | } 129 | bbox[4] = conf; 130 | rescaleBoxes(bbox); // xmin, ymin, xmax, ymax -> (xmin_raw, ymin_raw, xmax_raw, ymax_raw) 131 | ImageUtil.xywh2xyxy(bbox); // xywh -> (x1, y1, x2, y2) 132 | //skip invalid prediction 133 | if(bbox[0] >= bbox[2] || bbox[1] >= bbox[3]) { 134 | continue; 135 | } 136 | class2Bbox.putIfAbsent(label, CollectionUtil.newArrayList()); 137 | class2Bbox.get(label).add(bbox); 138 | } 139 | //apply non-max suppression for each class 140 | List detectionList = CollectionUtil.newArrayList(); 141 | for(Map.Entry> entry : class2Bbox.entrySet()) { 142 | int lable = entry.getKey(); 143 | List bboxList = entry.getValue(); 144 | bboxList = ImageUtil.nonMaxSuppression(bboxList, this.iouThreshold); 145 | for(float[] bbox : bboxList) { 146 | String labelString = labelNames.get(lable); 147 | detectionList.add(new Detection(labelString, lable, Arrays.copyOfRange(bbox, 0, 4), bbox[4])); 148 | } 149 | } 150 | return detectionList; 151 | } 152 | 153 | public float[][] transposeMatrix(float[][] matrix) { 154 | float[][] transMatrix = new float[matrix[0].length][matrix.length]; 155 | for(int i=0; i maxVal) { 172 | maxVal = probabilities[i]; 173 | idx = i; 174 | } 175 | } 176 | return idx; 177 | } 178 | 179 | public void rescaleBoxes(float[] bbox) { 180 | bbox[0] /= this.inputWidth; 181 | bbox[0] *= this.rawImgWidth; 182 | bbox[1] /= this.inputHeight; 183 | bbox[1] *= this.rawImgHeight; 184 | bbox[2] /= this.inputWidth; 185 | bbox[2] *= this.rawImgWidth; 186 | bbox[3] /= this.inputHeight; 187 | bbox[3] *= this.rawImgHeight; 188 | } 189 | 190 | } 191 | 192 | -------------------------------------------------------------------------------- /src/main/java/utils/CollectionUtil.java: -------------------------------------------------------------------------------- 1 | package utils; 2 | 3 | import java.util.*; 4 | 5 | /** 6 | * @author sy 7 | * @date 2022/2/2 19:36 8 | */ 9 | public class CollectionUtil { 10 | 11 | public static List newArrayList(List list) { 12 | return new ArrayList<>(list); 13 | } 14 | 15 | public static List newArrayList() { 16 | return new ArrayList<>(); 17 | } 18 | 19 | public static LinkedList newLinkedList() { 20 | return new LinkedList<>(); 21 | } 22 | 23 | public static List newArrayList(int N) { 24 | return new ArrayList<>(N); 25 | } 26 | 27 | public static List newArrayList(Set entry) { 28 | return new ArrayList<>(entry); 29 | } 30 | 31 | public static Set newHashset() { 32 | return new HashSet<>(); 33 | } 34 | 35 | public static Set newHashset(List entry) { 36 | return new HashSet<>(entry); 37 | } 38 | 39 | public static Map newHashMap() { 40 | return new HashMap<>(); 41 | } 42 | 43 | public static LinkedHashMap newLinkedHashMap() { 44 | return new LinkedHashMap<>(); 45 | } 46 | 47 | public static Map newTreeMap() { 48 | return new TreeMap<>(); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/utils/PropertiesReader.java: -------------------------------------------------------------------------------- 1 | package utils; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStreamReader; 5 | import java.util.Properties; 6 | 7 | /** 8 | * @author sy 9 | * @date 2022/2/2 19:07 10 | */ 11 | public class PropertiesReader { 12 | private static Properties properties = new Properties(); 13 | 14 | static { 15 | try { 16 | properties.load(new InputStreamReader(PropertiesReader.class.getClassLoader().getResourceAsStream("properties.properties"), "UTF-8")); 17 | 18 | } catch (IOException e) { 19 | e.printStackTrace(); 20 | } 21 | } 22 | 23 | public static String get(String keyName) { 24 | return properties.getProperty(keyName); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/resources/model/label.names: -------------------------------------------------------------------------------- 1 | Header 2 | Text 3 | Reference 4 | Figure caption 5 | Figure 6 | Table caption 7 | Table 8 | Title 9 | Footer 10 | Equation -------------------------------------------------------------------------------- /src/main/resources/model/model.onnx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiangnanboy/layout_analysis4j/710bf41c11bc0d26f991aee14e4ea995f246fd19/src/main/resources/model/model.onnx -------------------------------------------------------------------------------- /src/main/resources/properties.properties: -------------------------------------------------------------------------------- 1 | model_path = model/model.onnx 2 | table_det_labels_path = model/label.names -------------------------------------------------------------------------------- /target/classes/META-INF/layout_analysis4j.kotlin_module: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /target/classes/model/label.names: -------------------------------------------------------------------------------- 1 | Header 2 | Text 3 | Reference 4 | Figure caption 5 | Figure 6 | Table caption 7 | Table 8 | Title 9 | Footer 10 | Equation -------------------------------------------------------------------------------- /target/classes/model/model.onnx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiangnanboy/layout_analysis4j/710bf41c11bc0d26f991aee14e4ea995f246fd19/target/classes/model/model.onnx -------------------------------------------------------------------------------- /target/classes/properties.properties: -------------------------------------------------------------------------------- 1 | model_path = model/model.onnx 2 | table_det_labels_path = model/label.names -------------------------------------------------------------------------------- /target/classes/sy/Detection.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiangnanboy/layout_analysis4j/710bf41c11bc0d26f991aee14e4ea995f246fd19/target/classes/sy/Detection.class -------------------------------------------------------------------------------- /target/classes/sy/ImageUtil.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiangnanboy/layout_analysis4j/710bf41c11bc0d26f991aee14e4ea995f246fd19/target/classes/sy/ImageUtil.class -------------------------------------------------------------------------------- /target/classes/sy/MainTest.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiangnanboy/layout_analysis4j/710bf41c11bc0d26f991aee14e4ea995f246fd19/target/classes/sy/MainTest.class -------------------------------------------------------------------------------- /target/classes/sy/ModelDet.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiangnanboy/layout_analysis4j/710bf41c11bc0d26f991aee14e4ea995f246fd19/target/classes/sy/ModelDet.class -------------------------------------------------------------------------------- /target/classes/utils/CollectionUtil.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiangnanboy/layout_analysis4j/710bf41c11bc0d26f991aee14e4ea995f246fd19/target/classes/utils/CollectionUtil.class -------------------------------------------------------------------------------- /target/classes/utils/PropertiesReader.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiangnanboy/layout_analysis4j/710bf41c11bc0d26f991aee14e4ea995f246fd19/target/classes/utils/PropertiesReader.class --------------------------------------------------------------------------------