从零开发短视频电商 PaddleOCR Java推理 (一)飞桨引擎推理

文章目录

    • 简介
      • 方式一:DJL + 飞浆引擎 + 飞桨模型
      • 方式二:ONNXRuntime + 飞桨转换后的ONNX模型(Paddle2ONNX)
    • 添加依赖
    • 文字识别
    • OCR过程分析
      • 文字区域检测
      • 文字角度检测
      • 文字识别(裁减旋转后的文字区域)
    • 高级
      • 替换模型(离线)

简介

Github:https://github.com/PaddlePaddle/PaddleOCR

DJL:https://docs.djl.ai/docs/paddlepaddle/how_to_create_paddlepaddle_model_zh.html

在Java中,我发现两种主要的方式可以使用PaddleOCR。在此,我们不考虑通过Java进行本地部署服务的方式,而专注于两种更具可行性的方法。

方式一:DJL + 飞浆引擎 + 飞桨模型

通过采用DJL(Deep Java Library)结合飞浆引擎和飞桨模型的方式,我们能够实现高效的OCR推理。DJL作为一个深度学习框架无关的Java库,为我们提供了灵活性和简便性,同时能够与飞浆引擎协同工作,使得OCR模型的部署和推理变得更加便捷。

方式二:ONNXRuntime + 飞桨转换后的ONNX模型(Paddle2ONNX)

另一种方式是使用ONNXRuntime,结合经过Paddle2ONNX工具转换的飞桨模型。这种方法使得我们能够在Java环境中轻松地使用ONNXRuntime进行推理。通过将飞桨模型转换为ONNX格式,我们能够获得更大的灵活性,使得模型在不同平台上的部署更加简单。

参考:https://github.com/mymagicpower/AIAS/tree/main/1_image_sdks/ocr_v4_sdk

PaddleOCR 具有如下功能

  • OCR

    • 通用OCR
      • 流程为:区域检测+方向分类+识别
      • 检测模型+方向分类模型+识别模型
      • 都是小模型。
    • 文档场景专用OCR
    • 场景应用
      • 数码管识别
      • 通用表单识别
      • 票据识别
      • 电表读数识别
      • 车牌识别 轻量级车牌识别 推理模型下载链接
      • 手写体识别
      • 公私识别
      • 化验单识别
      • 更多制造、金融、交通行业的主要OCR垂类应用模型(如电表、液晶屏、高精度SVTR模型等),可参考场景应用模型下载
  • 文档分析

    • 版面复原:PDF转Word
    • 版面分析
    • 表格识别
    • 关键信息抽取
  • 通用信息提取

    • 基于LLMS的信息抽取
    • 通用信息提取

每种模型提供瘦身版和server版。

添加依赖

<dependency><groupId>ai.djl.paddlepaddle</groupId><artifactId>paddlepaddle-model-zoo</artifactId><version>0.25.0</version>
</dependency>
<!-- paddlepaddle 无NDArray ,需要借用pytorch-->
<dependency><groupId>ai.djl.pytorch</groupId><artifactId>pytorch-engine</artifactId><version>0.25.0</version>
</dependency>

文字识别

原图

在这里插入图片描述

结果

在这里插入图片描述

先介绍了一个整理过的OCR识别工具类,该工具类已经实现了强大的OCR功能。通过这个工具类,用户能够轻松地进行文字识别操作。

import ai.djl.inference.Predictor;
import ai.djl.modality.Classifications;
import ai.djl.modality.cv.Image;
import ai.djl.modality.cv.ImageFactory;
import ai.djl.modality.cv.output.BoundingBox;
import ai.djl.modality.cv.output.DetectedObjects;
import ai.djl.modality.cv.output.Rectangle;
import ai.djl.modality.cv.util.NDImageUtils;
import ai.djl.ndarray.NDArray;
import ai.djl.ndarray.NDManager;
import ai.djl.paddlepaddle.zoo.cv.imageclassification.PpWordRotateTranslator;
import ai.djl.paddlepaddle.zoo.cv.objectdetection.PpWordDetectionTranslator;
import ai.djl.paddlepaddle.zoo.cv.wordrecognition.PpWordRecognitionTranslator;
import ai.djl.repository.zoo.Criteria;
import ai.djl.repository.zoo.ZooModel;
import lombok.SneakyThrows;import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;public class PPOCR {static ZooModel<Image, DetectedObjects> detectionModel = null;static ZooModel<Image, Classifications> rotateModel = null;static ZooModel<Image, String> recognitionModel;static {try {Criteria<Image, DetectedObjects> detectionCriteria = Criteria.builder()// 指定使用飞桨引擎执行推理.optEngine("PaddlePaddle").setTypes(Image.class, DetectedObjects.class)// 可以替换模型版本.optModelUrls("https://resources.djl.ai/test-models/paddleOCR/mobile/det_db.zip").optTranslator(new PpWordDetectionTranslator(new ConcurrentHashMap<String, String>())).build();detectionModel = detectionCriteria.loadModel();Criteria<Image, Classifications> rotateCriteria = Criteria.builder().optEngine("PaddlePaddle").setTypes(Image.class, Classifications.class)// 可以替换模型版本.optModelUrls("https://resources.djl.ai/test-models/paddleOCR/mobile/cls.zip").optTranslator(new PpWordRotateTranslator()).build();rotateModel = rotateCriteria.loadModel();Criteria<Image, String> recognitionCriteria = Criteria.builder().optEngine("PaddlePaddle").setTypes(Image.class, String.class)// 可以替换模型版本.optModelUrls("https://resources.djl.ai/test-models/paddleOCR/mobile/rec_crnn.zip").optTranslator(new PpWordRecognitionTranslator()).build();recognitionModel = recognitionCriteria.loadModel();} catch (Exception e) {throw new RuntimeException(e);}}public static void main(String[] args) {// 识别本地图片doOCRFromFile("C:\\laker\\demo3\\1.png");// 识别网络图片doOCRFromUrl("https://img-blog.csdnimg.cn/direct/96de53d999c64c2589d0ab6a630e59d6.png");}@SneakyThrowspublic static String doOCRFromUrl(String url) {Image img = ImageFactory.getInstance().fromUrl(url);return doOCR(img);}@SneakyThrowspublic static String doOCRFromFile(String path) {Image img = ImageFactory.getInstance().fromFile(Path.of(path));return doOCR(img);}@SneakyThrowspublic static String doOCR(Image img) {List<DetectedObjects.DetectedObject> boxes = detection(img);List<String> names = new ArrayList<>();List<Double> prob = new ArrayList<>();List<BoundingBox> rect = new ArrayList<>();for (int i = 0; i < boxes.size(); i++) {System.out.println(boxes.get(i).getBoundingBox());Image subImg = getSubImage(img, boxes.get(i).getBoundingBox());if (subImg.getHeight() * 1.0 / subImg.getWidth() > 1.5) {subImg = rotateImg(subImg);}Classifications.Classification result = getRotateResult(subImg);if ("Rotate".equals(result.getClassName()) && result.getProbability() > 0.8) {subImg = rotateImg(subImg);}String name = recognizer(subImg);names.add(name);prob.add(-1.0);rect.add(boxes.get(i).getBoundingBox());}Image newImage = img.duplicate();newImage.drawBoundingBoxes(new DetectedObjects(names, prob, rect));newImage.getWrappedImage();newImage.save(Files.newOutputStream(Paths.get("C:\\laker\\demo3\\1-1-1.png")), "png");return "";}@SneakyThrowsprivate static List<DetectedObjects.DetectedObject> detection(Image img) {Predictor<Image, DetectedObjects> detector = detectionModel.newPredictor();DetectedObjects detectedObj = detector.predict(img);System.out.println(detectedObj);return detectedObj.items();}@SneakyThrowsprivate static Classifications.Classification getRotateResult(Image img) {Predictor<Image, Classifications> rotateClassifier = rotateModel.newPredictor();Classifications predict = rotateClassifier.predict(img);System.out.println(predict);return predict.best();}@SneakyThrowsprivate static String recognizer(Image img) {Predictor<Image, String> recognizer = recognitionModel.newPredictor();String text = recognizer.predict(img);System.out.println(text);return text;}static Image getSubImage(Image img, BoundingBox box) {Rectangle rect = box.getBounds();double[] extended = extendRect(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());int width = img.getWidth();int height = img.getHeight();int[] recovered = {(int) (extended[0] * width),(int) (extended[1] * height),(int) (extended[2] * width),(int) (extended[3] * height)};return img.getSubImage(recovered[0], recovered[1], recovered[2], recovered[3]);}static double[] extendRect(double xmin, double ymin, double width, double height) {double centerx = xmin + width / 2;double centery = ymin + height / 2;if (width > height) {width += height * 2.0;height *= 3.0;} else {height += width * 2.0;width *= 3.0;}double newX = centerx - width / 2 < 0 ? 0 : centerx - width / 2;double newY = centery - height / 2 < 0 ? 0 : centery - height / 2;double newWidth = newX + width > 1 ? 1 - newX : width;double newHeight = newY + height > 1 ? 1 - newY : height;return new double[]{newX, newY, newWidth, newHeight};}private static Image rotateImg(Image image) {try (NDManager manager = NDManager.newBaseManager()) {NDArray rotated = NDImageUtils.rotate90(image.toNDArray(manager), 1);return ImageFactory.getInstance().fromNDArray(rotated);}}
}

第一次执行时会从网络上下载对应的模型包并解压,后面可以复用

区域检测模型

C:\Users\xxx.djl.ai\cache\repo\model\undefined\ai\djl\localmodelzoo\0fe77cae3367aab58bd7bec22e93d818c35706c6\det_db

/det_db/├── inference.pdiparams         # inference模型的参数文件├── inference.pdiparams.info    # inference模型的参数信息,可忽略└── inference.pdmodel           # inference模型的program文件

文字识别模型

C:\Users\xxx.djl.ai\cache\repo\model\undefined\ai\djl\localmodelzoo\f78cb59b6d66764eb68a5c1fb92b4ba132dbbcfe\rec_crnn

/rec_crnn/├── inference.pdiparams         # inference模型的参数文件├── inference.pdiparams.info    # inference模型的参数信息,可忽略└── inference.pdmodel           # inference模型的program文件└── ppocr_keys_v1.txt           # OCR识别字典

角度识别模型

C:\Users\xxx.djl.ai\cache\repo\model\undefined\ai\djl\localmodelzoo\33f7a81bc13304d4b5da850898d51c94697b71a9\cls

/cls/├── inference.pdiparams         # inference模型的参数文件├── inference.pdiparams.info    # inference模型的参数信息,可忽略└── inference.pdmodel           # inference模型的program文件

OCR过程分析

文字区域检测

文字区域检测是OCR过程中的关键步骤,旨在定位并标识待识别图片中的文字区域。以下是详细的步骤分析:

  1. 加载待识别图片
    • 用户提供待识别的图片,该图片可能包含一个或多个文本区域。
  2. 加载检测模型
    • OCR系统使用预训练的文字区域检测模型,确保该模型能够准确地定位图像中的文字。
  3. 推理与文本区域检测
    • 通过对待识别图片进行推理,文字区域检测模型会生成一个包含所有文字区域的二进制位图(Bitmap)。
    • 使用 PpWordDetectionTranslator 函数将原始输出转换为包含每个文字区域位置的矩形框。
  4. 优化文本区域框
    • 对于由模型标注的文字区域框,进行优化以确保完整包含文字内容。
    • 利用 extendRect 函数,可以将文字框的宽度和高度扩展到所需的大小。
    • 使用 getSubImage 函数裁剪并提取出每个文本区域。
  5. 保存区域到本地
    • 将优化后的文本区域保存到本地,以备后续文字识别步骤使用或进行进一步的分析。
        // 加载图像String url = "https://resources.djl.ai/images/flight_ticket.jpg";Image img = ImageFactory.getInstance().fromUrl(url);// 保存原始图像img.save(new FileOutputStream("C:\\laker\\demo3\\1.jpg"), "jpg");// 加载目标检测模型Criteria<Image, DetectedObjects> criteria1 = Criteria.builder().optEngine("PaddlePaddle").setTypes(Image.class, DetectedObjects.class).optModelUrls("https://resources.djl.ai/test-models/paddleOCR/mobile/det_db.zip").optTranslator(new PpWordDetectionTranslator(new ConcurrentHashMap<String, String>())).build();ZooModel<Image, DetectedObjects> detectionModel = criteria1.loadModel();Predictor<Image, DetectedObjects> detector = detectionModel.newPredictor();// 进行目标检测DetectedObjects detectedObj = detector.predict(img);System.out.println(detectedObj);// 在新图像上绘制边界框并保存Image newImage = img.duplicate();newImage.drawBoundingBoxes(detectedObj);newImage.save(Files.newOutputStream(Paths.get("C:\\laker\\demo3\\1.png")), "png");// 提取检测到的对象并保存为单独的图像文件List<DetectedObjects.DetectedObject> boxes = detectedObj.items();for (int i = 0; i < boxes.size(); i++) {Image sample = getSubImage(img, boxes.get(i).getBoundingBox());// 保存单独的对象图像sample.save(Files.newOutputStream(Paths.get("C:\\laker\\demo3\\1-" + i + ".png")), "png");}
...// 提取目标框内的子图像static Image getSubImage(Image img, BoundingBox box) {Rectangle rect = box.getBounds();double[] extended = extendRect(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());int width = img.getWidth();int height = img.getHeight();int[] recovered = {(int) (extended[0] * width),(int) (extended[1] * height),(int) (extended[2] * width),(int) (extended[3] * height)};return img.getSubImage(recovered[0], recovered[1], recovered[2], recovered[3]);}// 扩展目标框static double[] extendRect(double xmin, double ymin, double width, double height) {double centerx = xmin + width / 2;double centery = ymin + height / 2;if (width > height) {width += height * 2.0;height *= 3.0;} else {height += width * 2.0;width *= 3.0;}double newX = centerx - width / 2 < 0 ? 0 : centerx - width / 2;double newY = centery - height / 2 < 0 ? 0 : centery - height / 2;double newWidth = newX + width > 1 ? 1 - newX : width;double newHeight = newY + height > 1 ? 1 - newY : height;return new double[]{newX, newY, newWidth, newHeight};}
}

以下为日志和结果

ai.djl.paddlepaddle.jni.LibUtils -- Downloading https://publish.djl.ai/paddlepaddle-2.3.2/cpu/win/native/lib/paddle_inference.dll.gz ...
ai.djl.paddlepaddle.jni.LibUtils -- Downloading https://publish.djl.ai/paddlepaddle-2.3.2/cpu/win/native/lib/openblas.dll.gz ...
ai.djl.paddlepaddle.jni.LibUtils -- Downloading https://publish.djl.ai/paddlepaddle-2.3.2/cpu/win/native/lib/onnxruntime.dll.gz ...
INFO ai.djl.paddlepaddle.jni.LibUtils -- Downloading https://publish.djl.ai/paddlepaddle-2.3.2/cpu/win/native/lib/paddle2onnx.dll.gz ...
ai.djl.paddlepaddle.jni.LibUtils -- Extracting jnilib/win-x86_64/cpu/djl_paddle.dll to cache ...
ai.djl.pytorch.engine.PtEngine -- PyTorch graph executor optimizer is enabled, this may impact your inference latency and throughput. See: https://docs.djl.ai/docs/development/inference_performance_optimization.html#graph-executor-optimization
ai.djl.pytorch.engine.PtEngine -- Number of inter-op threads is 4
ai.djl.pytorch.engine.PtEngine -- Number of intra-op threads is 4
WARNING: Logging before InitGoogleLogging() is written to STDERR
W0110 22:31:36.663225 34380 analysis_predictor.cc:1736] Deprecated. Please use CreatePredictor instead.
e[1me[35m--- Running analysis [ir_graph_build_pass]e[0m
I0110 22:31:36.928385 34380 analysis_predictor.cc:1035] ======= optimize end =======
I0110 22:31:36.928385 34380 naive_executor.cc:102] ---  skip [feed], feed -> x
I0110 22:31:36.931370 34380 naive_executor.cc:102] ---  skip [save_infer_model/scale_0.tmp_1], fetch -> fetch
I0110 22:31:36.935369 34380 naive_executor.cc:102] ---  skip [feed], feed -> x
I0110 22:31:36.938895 34380 naive_executor.cc:102] ---  skip [save_infer_model/scale_0.tmp_1], fetch -> fetch[{"class": "word", "probability": 1.00000, "bounds": {"x"=0.071, "y"=0.033, "width"=0.067, "height"=0.008}}{"class": "word", "probability": 1.00000, "bounds": {"x"=0.797, "y"=0.055, "width"=0.107, "height"=0.031}}{"class": "word", "probability": 1.00000, "bounds": {"x"=0.485, "y"=0.063, "width"=0.238, "height"=0.029}}
]
有用的只有bounds这个字段

文字角度检测

文字角度检测也是OCR过程中的一个关键环节,其主要目的是确认图片中的文字是否需要旋转,以确保后续的文字识别能够准确进行。

String url = "https://resources.djl.ai/images/flight_ticket.jpg";Image img = ImageFactory.getInstance().fromUrl(url);img.getWrappedImage();Criteria<Image, Classifications> criteria2 = Criteria.builder().optEngine("PaddlePaddle").setTypes(Image.class, Classifications.class).optModelUrls("https://resources.djl.ai/test-models/paddleOCR/mobile/cls.zip").optTranslator(new PpWordRotateTranslator()).build();ZooModel<Image, Classifications> rotateModel = criteria2.loadModel();Predictor<Image, Classifications> predictor = rotateModel.newPredictor();Classifications classifications = predictor.predict(img);System.out.println(classifications);System.out.println(classifications.best());}

结果

[{"class": "Rotate", "probability": 0.60876}{"class": "No Rotate", "probability": 0.39123}
]{"class": "Rotate", "probability": 0.60876}
这里旋转的可能性为0.60876,可以设置个阈值,如果大于阈值则需要旋转
// 获取图像的旋转分类结果
Classifications.Classification result = getRotateResult(subImg);// 判断是否需要旋转,并且置信度大于 0.8
if ("Rotate".equals(result.getClassName()) && result.getProbability() > 0.8) {// 如果需要旋转,则调用 rotateImg 方法进行图像旋转subImg = rotateImg(subImg);
}// 图像旋转方法
private static Image rotateImg(Image image) {try (NDManager manager = NDManager.newBaseManager()) {// 利用 NDImageUtils.rotate90 进行图像旋转,参数 1 表示顺时针旋转 90 度NDArray rotated = NDImageUtils.rotate90(image.toNDArray(manager), 1);// 将旋转后的 NDArray 转换回 Image 对象并返回return ImageFactory.getInstance().fromNDArray(rotated);}
}

文字识别(裁减旋转后的文字区域)

在文字识别的过程中,我们注意到处理大图片时可能导致效果较差。为了优化识别效果,建议将输入的 img 替换为经过前面两部处理后文字区域检测出来的仅包含文字的图片,以获得更好的效果。

  String url = "https://resources.djl.ai/images/flight_ticket.jpg";Image img = ImageFactory.getInstance().fromUrl(url);img.getWrappedImage();Criteria<Image, String> criteria3 =  Criteria.builder().optEngine("PaddlePaddle").setTypes(Image.class, String.class).optModelUrls("https://resources.djl.ai/test-models/paddleOCR/mobile/rec_crnn.zip").optTranslator(new PpWordRecognitionTranslator()).build();ZooModel<Image, String> recognitionModel = criteria3.loadModel();Predictor<Image, String> recognizer = recognitionModel.newPredictor();String predict = recognizer.predict(img);System.out.println(predict); // 输出示例:laker

高级

替换模型(离线)

在模型的选择方面,建议考虑替换paddlepaddle-model-zoo中自带的模型,因为这些模型可能相对较老。为了提高推理效果,我们可以选择更先进、性能更好的模型。

以文字识别模型示例,区域检测和角度检测更简单。

获取推理模型文件:https://github.com/PaddlePaddle/PaddleOCR

  • 模型列表,注意跟随版本号(当前2.7)变更地址:
  • https://github.com/PaddlePaddle/PaddleOCR/blob/release/2.7/doc/doc_ch/models_list.md

获取字典文件wget https://gitee.com/paddlepaddle/PaddleOCR/raw/release/2.7/ppocr/utils/ppocr_keys_v1.txt

  • ppocr_keys_v1.txt是中文字典文件,如果使用的模型是英文数字或其他语言的模型,需要更换为对应语言的字典.

  • 其他语言的字典文件,可从 PaddleOCR 仓库下载:https://github.com/PaddlePaddle/PaddleOCR/tree/release/2.7/ppocr/utils/dict

中文识别模型

模型名称模型简介配置文件推理模型大小下载地址
ch_PP-OCRv4_rec【最新】超轻量模型,支持中英文、数字识别ch_PP-OCRv4_rec_distill.yml10M推理模型 / 训练模型
ch_PP-OCRv4_server_rec【最新】高精度模型,支持中英文、数字识别ch_PP-OCRv4_rec_hgnet.yml88M推理模型 / 训练模型
ch_PP-OCRv3_rec_slimslim量化版超轻量模型,支持中英文、数字识别ch_PP-OCRv3_rec_distillation.yml4.9M推理模型 / 训练模型 / nb模型
ch_PP-OCRv3_rec原始超轻量模型,支持中英文、数字识别ch_PP-OCRv3_rec_distillation.yml12.4M推理模型 / 训练模型

我们以ch_PP-OCRv4_rec为例,下载推理模型ppocr_keys_v1.txt文件,然后放到如下目录中:

字典文件名称必须为ppocr_keys_v1.txt,选择其他语言模型,也要把文件名改成这个。

在这里插入图片描述

示例代码如下

        Image img = ImageFactory.getInstance().fromFile(Path.of("C:\\laker\\demo3\\1-26.png"));img.getWrappedImage();Criteria<Image, String> criteria3 =  Criteria.builder().optEngine("PaddlePaddle").setTypes(Image.class, String.class).optModelPath(Paths.get("C:\\laker-1")) // 这里指定模型.optTranslator(new PpWordRecognitionTranslator()).build();ZooModel<Image, String> recognitionModel = criteria3.loadModel();Predictor<Image, String> recognizer = recognitionModel.newPredictor();String predict = recognizer.predict(img);System.out.println(predict);

还有其他方式可以替换,例如:

// 其他方式一 把zip包上传到 s3 指定其urlCriteria<Image, String> criteria3 =  Criteria.builder().optEngine("PaddlePaddle").setTypes(Image.class, String.class).optModelUrls("https://xxx.com/models/xxx_det_infer.zip").optTranslator(new PpWordRecognitionTranslator()).build();// 其他方式二 加载本地zip文件Criteria<Image, String> criteria3 =  Criteria.builder().optEngine("PaddlePaddle").setTypes(Image.class, String.class).optModelPath(Paths.get("/laker/xxx_det_infer.zip")).optTranslator(new PpWordRecognitionTranslator()).build();
// 其他方式三 加载位于JAR文件中模型Criteria<Image, String> criteria3 =  Criteria.builder().optEngine("PaddlePaddle").setTypes(Image.class, String.class).optModelUrls("jar:///xxx_det_infer.zip").optTranslator(new PpWordRecognitionTranslator()).build();

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/619707.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL 和 Redis 如何保证数据一致性,通过MySQL的binlog实现

1、简介 MySQL 和 Redis 如何保证数据一致性&#xff0c;目前大多讨论的是先更新Redis后更新MySQL&#xff0c;还是先更新MySQL 后更新Redis&#xff0c;这两种方式在实际的应用场景中都不能确保数据的完全一致性&#xff0c;在某些情况下会出现问题&#xff0c;本文介绍使用 C…

遥感影像-语义分割数据集:高分卫星-云数据集详细介绍及训练样本处理流程

原始数据集详情 简介&#xff1a;该云数据集包括RGB三通道的高分辨率图像&#xff0c;包含高分一、高分二及宽幅数据集。 KeyValue卫星类型高分系列覆盖区域未知场景未知分辨率1m、2m、8m数量12000单张尺寸1024*1024原始影像位深8位标签图片位深8位原始影像通道数三通道标签图…

vivado 使用源文件

使用源文件 概述 源文件包括从AMD IP添加的设计源、知识产权&#xff08;IP&#xff09;源目录、RTL设计源、从系统添加的数字信号处理&#xff08;DSP&#xff09;源生成器工具和IP子系统&#xff0c;也称为块设计&#xff0c;由IP集成商创建AMD Vivado的功能™ 设计套件。源…

C++11 14 17内存管理

智能指针 unique_ptr 初始化 访问和移动赋值 重置和移动内存资源 自定义删除器 shared_ptr 原理 自定义删除器 分配器allocator和new重载 new表达式原理 operator new delete placement new new (buf) 是一种 "placement new" 的使用方式&#xff0c;它允许在已…

Qt/QML编程学习之心得:Grid、GridLayout、GridView、Repeater(33)

GRID网格用处非常大,不仅在excel中,在GUI中,也是非常重要的一种控件。 Grid 网格是一种以网格形式定位其子项的类型。网格创建一个足够大的单元格网格,以容纳其所有子项,并将这些项从左到右、从上到下放置在单元格中。每个项目都位于其单元格的左上角,位置为(0,0)。…

uniapp 开发小程序的时候使用自定义 tabbar 时出现切换页面闪烁的情况

问题&#xff1a;在使用自定义组件的时候可以看到页面切换明显的闪烁, 这种体验是很不好的, 当然最好的方式就是使用原生导航栏, 不要搞花里胡哨的东西。 来看下体验不好的效果 优化调整 先说思路&#xff0c;就是仍然设置原生 tabbar, 在应用启动的时候主动隐藏原生 tabba…

VS QT 创建新的QT类后,编译报错无法解析的外部符号 “public: virtual struct QMetaObject const *

问题描述&#xff1a; 新建QT的 Widgets 类&#xff0c;创建新的窗口 在编译的时候出现以下报错信息&#xff1a; 1>vfhclassifydialog.obj : error LNK2001: 无法解析的外部符号 "public: virtual struct QMetaObject const * __cdecl VfhClassifyDialog::metaObject…

vivado 指定顶部模块和重新排序源

指定顶部模块和重新排序源 文件夹默认情况下&#xff0c;Vivado Design Suite会自动确定设计的顶层添加到的源文件的层次结构和细化、合成和模拟的顺序项目这可以通过右键单击中的“层次更新”设置进行控制“源”窗口的菜单。请参阅中的“源”窗口中的“层次更新”命令Vivado …

Ceph入门到精通-通过 CloudBerry Explorer 管理对象bucket

简介 CloudBerry Explorer 是一款可用于管理对象存储&#xff08;Cloud Object Storage&#xff0c;COS&#xff09;的客户端工具。通过 CloudBerry Explorer 可实现将 COS 挂载在 Windows 等操作系统上&#xff0c;方便用户访问、移动和管理 COS 文件。 支持系统 支持 Wind…

uniapp微信小程序投票系统实战 (SpringBoot2+vue3.2+element plus ) -投票帖子管理实现

锋哥原创的uniapp微信小程序投票系统实战&#xff1a; uniapp微信小程序投票系统实战课程 (SpringBoot2vue3.2element plus ) ( 火爆连载更新中... )_哔哩哔哩_bilibiliuniapp微信小程序投票系统实战课程 (SpringBoot2vue3.2element plus ) ( 火爆连载更新中... )共计21条视频…

Java项目:05 停车管理系统

作者主页&#xff1a;舒克日记 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 课题意义&#xff1a; 随着时代和科技的进步&#xff0c;人们的生活水平越来越高&#xff0c;私家车的数量不断上涨&#xff0c;随之产生了一些问题&…

POI-tl 知识整理:整理1 -> 利用模板向word中写入数据

1 文本传值 Testpublic void testText() throws Exception {XWPFTemplate template XWPFTemplate.compile("D:\\Idea-projects\\POI_word\\templates.docx");Map<String, Object> map new HashMap<>();map.put("title", "Hi, girl"…

PyCharm连接服务器 - 1

文章目录 利用PyCharm实现远程开发使用认证代理连接服务器 利用PyCharm实现远程开发 【注】该连接服务器的方法适用于代码在服务器&#xff0c;我们是通过 GateWay 打开远程服务器的代码进行操作。 该功能只有在PyCharm专业版下才可以使用&#xff0c;并且必须是官方的正版许…

谷歌最新医学领域LLM大模型:AMIE

2024年1月11日Google 研究院发布最新医疗大模型AMIE&#xff1a;用于诊断医学推理和对话的研究人工智能系统。 文章链接&#xff1a;Articulate Medical Intelligence Explorer (AMIE) giuthub&#xff1a;目前代码未开源 关于大模型之前有过一篇总结&#xff1a;大语言模型(L…

Jmeter接口测试必会技能:jmeter_HTTP Cookie管理器

HTTP Cookie管理器 HTTP Cookie管理器可以像浏览器一样自动存储和发送cookie&#xff0c;以这种自 动收集的方式收集到的cookie不会在cookie manager中进行展示&#xff0c;但是运行后&#xff0c; 可以通过 查看结果树&#xff08;监听器&#xff09;可以查看到cookie信息 除…

详解矩阵变换:伸缩,旋转,反射和投影

目录 一. 矩阵子空间 二. 矩阵变换 2.1 伸缩矩阵 2.2 旋转矩阵 2.3 反射矩阵 2.4 投影矩阵 2.5 小结 三. 矩阵变换与函数 3.1 原点 3.2 常数倍性质 3.3 加法性质 3.4 小结 四. 空间变换 五. 小结 一. 矩阵子空间 矩阵与向量相乘Ax可以看成子空间的变换。 零空间…

Linux 系统编程:文件系统的底层逻辑 - inode

《Linux 程序设计》的第三章讲文件操作。在提到 目录 时有这么一段文字&#xff1a; 文件&#xff0c;除了本身包含的 内容 以外&#xff0c;它还会有一个 名字 和一些 属性&#xff0c;即“管理信息”&#xff0c;包括文件的创建 / 修改日期和它的访问权限。这些属性被保存在文…

ActiveMQ反序列化RCE漏洞复现(CVE-2023-46604)

漏洞名称 Apache ActiveMQ OpenWire 协议反序列化命令执行漏洞 漏洞描述 Apache ActiveMQ 是美国阿帕奇&#xff08;Apache&#xff09;软件基金会所研发的一套开源的消息中间件&#xff0c;它支持Java消息服务、集群、Spring Framework等。 OpenWire协议在ActiveMQ中被用于…

在虚拟机中安装OpenEuler操作系统

目录 OpenEuler操作系统安装步骤&#xff08;详细&#xff09; 一、首先要做好安装前的准备工作&#xff1a; 二、进行虚拟机的创建&#xff1a; 三、OpenEuler 23.09操作系统的安装部署&#xff1a; OpenEuler操作系统安装步骤&#xff08;详细&#xff09; 一、首先要做好…

C#基于ScottPlot进行可视化

前言 上一篇文章跟大家分享了用NumSharp实现简单的线性回归&#xff0c;但是没有进行可视化&#xff0c;可能对拟合的过程没有直观的感受&#xff0c;因此今天跟大家介绍一下使用C#基于Scottplot进行可视化&#xff0c;当然Python的代码&#xff0c;我也会同步进行可视化。 P…