学习yolo+Java+opencv简单案例(三)

news2024/11/15 5:38:22

主要内容:车牌检测+识别(什么颜色的车牌,车牌号)

模型作用:车牌检测,车牌识别

文章的最后附上我的源码地址。

学习还可以参考我前两篇博客:

学习yolo+Java+opencv简单案例(一)-CSDN博客

学习yolo+Java+opencv简单案例(二)-CSDN博客

目录

一、模型示例

二、解释流程

1、加载opencv库

2、定义车牌颜色和字符

3、模型路径和图片路径

4、创建目录

5、加载onnx模型

6、车牌检测和识别

7、辅助方法

三、代码实现

1、pom.xml

2、controller

四、测试


一、模型示例

二、解释流程

1、加载opencv库
static {
    // 加载opencv动态库,
    nu.pattern.OpenCV.loadLocally();
}
2、定义车牌颜色和字符
final static String[] PLATE_COLOR = new String[]{"黑牌", "蓝牌", "绿牌", "白牌", "黄牌"};
final static String PLATE_NAME= "#京沪津渝冀晋蒙辽吉黑苏浙皖闽赣鲁豫鄂湘粤桂琼川贵云藏陕甘青宁新学警港澳挂使领民航危0123456789ABCDEFGHJKLMNPQRSTUVWXYZ险品";
3、模型路径和图片路径
// 车牌检测模型
String model_path1 = "./PlateDetection/src/main/resources/model/plate_detect.onnx";

// 车牌识别模型
String model_path2 = "./PlateDetection/src/main/resources/model/plate_rec_color.onnx";

// 要检测的图片所在目录
String imagePath = "./yolo-common/src/main/java/com/bluefoxyu/carImg";

// 定义保存目录
String outputDir = "./PlateDetection/output/";
4、创建目录
File directory = new File(outputDir);
if (!directory.exists()) {
    directory.mkdirs();  // 创建目录
    System.out.println("目录不存在,已创建:" + outputDir);
}

5、加载onnx模型
// 加载ONNX模型
OrtEnvironment environment = OrtEnvironment.getEnvironment();
OrtSession.SessionOptions sessionOptions = new OrtSession.SessionOptions();
OrtSession session = environment.createSession(model_path1, sessionOptions);

// 加载ONNX模型
OrtEnvironment environment2 = OrtEnvironment.getEnvironment();
OrtSession session2 = environment2.createSession(model_path2, sessionOptions);

使用 ONNX Runtime 加载两个模型,一个用于车牌检测,另一个用于车牌识别。

6、车牌检测和识别

(1)处理每一张图片:

Map<String, String> map = getImagePathMap(imagePath);
for(String fileName : map.keySet()){
    // 处理图片逻辑
}

(2)读取和预处理图片:

Mat img = Imgcodecs.imread(imageFilePath);
Mat image = img.clone();
Imgproc.cvtColor(image, image, Imgproc.COLOR_BGR2RGB);

使用 OpenCV 读取图片并进行颜色空间转换(从 BGR 转换为 RGB)。

(3)图像尺寸调整

Letterbox letterbox = new Letterbox();
image = letterbox.letterbox(image);

使用 Letterbox 方法调整图像的尺寸,使其适应模型的输入要求。

(4)模型推理(车牌检测)

float[] chw = ImageUtil.whc2cwh(whc);
OnnxTensor tensor = OnnxTensor.createTensor(environment, FloatBuffer.wrap(chw),shape );
OrtSession.Result output = session.run(stringOnnxTensorHashMap);

将预处理后的图像转换为 ONNX Tensor 格式,并使用车牌检测模型进行推理。

(5)非极大值抑制

List<float[]> bboxes = nonMaxSuppression(bboxes, nmsThreshold);

使用非极大值抑制(NMS)来过滤重叠的检测框,只保留最有可能的车牌位置。

(6)车牌裁剪和识别

Mat image2 = new Mat(img.clone(), rect);
// 车牌识别模型推理
OrtSession.Result output2 = session2.run(stringOnnxTensorHashMap2);
String plateNo = decodePlate(maxScoreIndex(result[0]));

使用检测到的车牌位置,裁剪出车牌区域,再使用车牌识别模型进行识别,得到车牌号码和颜色。

(7)结果展示和保存

BufferedImage bufferedImage = matToBufferedImage(img);
Graphics2D g2d = bufferedImage.createGraphics();
g2d.drawString(PLATE_COLOR[colorRResult[0].intValue()]+"-"+plateNo, (int)((bbox[0]-dw)/ratio), (int)((bbox[1]-dh)/ratio-3));
ImageIO.write(bufferedImage, "jpg", new File(outputPath));
7、辅助方法

xywh2xyxy: 将中心点坐标转换为边框坐标。

nonMaxSuppression: 实现非极大值抑制。

matToBufferedImage: 将 OpenCV 的 Mat 对象转换为 Java 的 BufferedImage,以便进行图像处理。

argmax: 找出最大值的索引,用于推理时的结果处理。

softMax: 实现 softmax 函数,用于将输出转化为概率分布。

decodePlatedecodeColor: 用于解码模型输出的车牌字符和颜色。

三、代码实现

1、pom.xml
yolo-study:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.bluefoxyu</groupId>
    <artifactId>yolo-study</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    <modules>
        <module>predict-test</module>
        <module>CameraDetection</module>
        <module>yolo-common</module>
        <module>CameraDetectionWarn</module>
        <module>PlateDetection</module>
        <module>dp</module>
    </modules>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.microsoft.onnxruntime</groupId>
            <artifactId>onnxruntime</artifactId>
            <version>1.16.1</version>
        </dependency>
        <dependency>
            <groupId>org.openpnp</groupId>
            <artifactId>opencv</artifactId>
            <version>4.7.0-0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.34</version>
            <scope>provided</scope>
        </dependency>

    </dependencies>

</project>
PlateDetection:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.bluefoxyu</groupId>
        <artifactId>yolo-study</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>PlateDetection</artifactId>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.bluefoxyu</groupId>
            <artifactId>yolo-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>3.2.4</version>
        </dependency>
    </dependencies>



</project>
2、controller
@RestController
@RequestMapping("/plate-detect")
public class PlateDetectionController {

    static {
        // 加载opencv动态库,
        //System.load(ClassLoader.getSystemResource("lib/opencv_videoio_ffmpeg470_64.dll").getPath());
        nu.pattern.OpenCV.loadLocally();
    }

    final static String[] PLATE_COLOR = new String[]{"黑牌", "蓝牌", "绿牌", "白牌", "黄牌"};
    final static String PLATE_NAME= "#京沪津渝冀晋蒙辽" +
            "吉黑苏浙皖闽赣鲁豫鄂湘粤桂琼川贵云藏陕甘青宁新学警港澳挂使领民航危0123456789ABCDEFGHJKLMNPQRSTUVWXYZ险品";

    @PostMapping
    public List<String> plateDetection() throws OrtException {

        //记录车牌号返回前端
        List<String>plateNumberList=new ArrayList<>();

        // 车牌检测模型
        String model_path1 = "./PlateDetection/src/main/resources/model/plate_detect.onnx";

        // 车牌识别模型
        String model_path2 = "./PlateDetection/src/main/resources/model/plate_rec_color.onnx";

        // 要检测的图片所在目录
        String imagePath = "./yolo-common/src/main/java/com/bluefoxyu/carImg";

        // 定义保存目录
        String outputDir = "./PlateDetection/output/";

        // 用于区别后续各个图片的标识
        int index=0;

        // 创建目录(如果不存在)
        File directory = new File(outputDir);
        if (!directory.exists()) {
            directory.mkdirs();  // 创建目录
            System.out.println("目录不存在,已创建:" + outputDir);
        }


        float confThreshold = 0.35F;

        float nmsThreshold = 0.45F;

        // 1.单行蓝牌
        // 2.单行黄牌
        // 3.新能源车牌
        // 4.白色警用车牌
        // 5.教练车牌
        // 6.武警车牌
        // 7.双层黄牌
        // 8.双层白牌
        // 9.使馆车牌
        // 10.港澳粤Z牌
        // 11.双层绿牌
        // 12.民航车牌
        String[] labels = {"1", "2", "3", "4", "5", "6", "7","8", "9", "10", "11","12"};

        // 加载ONNX模型
        OrtEnvironment environment = OrtEnvironment.getEnvironment();
        OrtSession.SessionOptions sessionOptions = new OrtSession.SessionOptions();
        OrtSession session = environment.createSession(model_path1, sessionOptions);

        // 加载ONNX模型
        OrtEnvironment environment2 = OrtEnvironment.getEnvironment();
        OrtSession session2 = environment2.createSession(model_path2, sessionOptions);

        // 加载标签及颜色
        ODConfig odConfig = new ODConfig();
        Map<String, String> map = getImagePathMap(imagePath);
        for(String fileName : map.keySet()){

            // 生成输出文件名
            index++;
            String outputFileName = "temp_output_image" + "_" + index + ".jpg";
            String outputPath = outputDir + outputFileName;
            System.out.println("outputPath = " + outputPath);

            String imageFilePath = map.get(fileName);
            System.out.println(imageFilePath);
            // 读取 image
            Mat img = Imgcodecs.imread(imageFilePath);
            Mat image = img.clone();
            Imgproc.cvtColor(image, image, Imgproc.COLOR_BGR2RGB);

            // 在这里先定义下框的粗细、字的大小、字的类型、字的颜色(按比例设置大小粗细比较好一些)
            int minDwDh = Math.min(img.width(), img.height());
            int thickness = minDwDh/ODConfig.lineThicknessRatio;
            long start_time = System.currentTimeMillis();
            // 更改 image 尺寸
            Letterbox letterbox = new Letterbox();
            image = letterbox.letterbox(image);

            double ratio  = letterbox.getRatio();
            double dw = letterbox.getDw();
            double dh = letterbox.getDh();
            int rows  = letterbox.getHeight();
            int cols  = letterbox.getWidth();
            int channels = image.channels();

            image.convertTo(image, CvType.CV_32FC1, 1. / 255);
            float[] whc = new float[3 * 640 * 640];
            image.get(0, 0, whc);
            float[] chw = ImageUtil.whc2cwh(whc);

            // 创建OnnxTensor对象
            long[] shape = { 1L, (long)channels, (long)rows, (long)cols };
            OnnxTensor tensor = OnnxTensor.createTensor(environment, FloatBuffer.wrap(chw),shape );
            HashMap<String, OnnxTensor> stringOnnxTensorHashMap = new HashMap<>();
            stringOnnxTensorHashMap.put(session.getInputInfo().keySet().iterator().next(), tensor);

            // 运行推理
            OrtSession.Result output = session.run(stringOnnxTensorHashMap);
            float[][] outputData = ((float[][][])output.get(0).getValue())[0];
            Map<Integer, List<float[]>> class2Bbox = new HashMap<>();
            for (float[] bbox : outputData) {
                float score = bbox[4];
                if (score < confThreshold) continue;

                float[] conditionalProbabilities = Arrays.copyOfRange(bbox, 5, bbox.length);
                int label = argmax(conditionalProbabilities);

                // xywh to (x1, y1, x2, y2)
                xywh2xyxy(bbox);

                // 去除无效结果
                if (bbox[0] >= bbox[2] || bbox[1] >= bbox[3]) continue;

                class2Bbox.putIfAbsent(label, new ArrayList<>());
                class2Bbox.get(label).add(bbox);
            }

            List<CarDetection> CarDetections = new ArrayList<>();
            for (Map.Entry<Integer, List<float[]>> entry : class2Bbox.entrySet()) {

                List<float[]> bboxes = entry.getValue();
                bboxes = nonMaxSuppression(bboxes, nmsThreshold);
                for (float[] bbox : bboxes) {
                    String labelString = labels[entry.getKey()];
                    CarDetections.add(new CarDetection(labelString,entry.getKey(), Arrays.copyOfRange(bbox, 0, 4), bbox[4],bbox[13] == 0,0.0f,null,null));
                }
            }


            for (CarDetection carDetection : CarDetections) {
                float[] bbox = carDetection.getBbox();

                Rect rect = new Rect(new Point((bbox[0]-dw)/ratio, (bbox[1]-dh)/ratio), new Point((bbox[2]-dw)/ratio, (bbox[3]-dh)/ratio));
                // img.submat(rect)
                Mat image2 = new Mat(img.clone(), rect);
                Imgproc.cvtColor(image2, image2, Imgproc.COLOR_BGR2RGB);
                Letterbox letterbox2 = new Letterbox(168,48);
                image2 = letterbox2.letterbox(image2);

                double ratio2  = letterbox2.getRatio();
                double dw2 = letterbox2.getDw();
                double dh2 = letterbox2.getDh();
                int rows2  = letterbox2.getHeight();
                int cols2  = letterbox2.getWidth();
                int channels2 = image2.channels();

                image2.convertTo(image2, CvType.CV_32FC1, 1. / 255);
                float[] whc2 = new float[3 * 168 * 48];
                image2.get(0, 0, whc2);
                float[] chw2 = ImageUtil.whc2cwh(whc2);

                // 创建OnnxTensor对象
                long[] shape2 = { 1L, (long)channels2, (long)rows2, (long)cols2 };
                OnnxTensor tensor2 = OnnxTensor.createTensor(environment2, FloatBuffer.wrap(chw2), shape2);
                HashMap<String, OnnxTensor> stringOnnxTensorHashMap2 = new HashMap<>();
                stringOnnxTensorHashMap2.put(session2.getInputInfo().keySet().iterator().next(), tensor2);

                // 运行推理
                OrtSession.Result output2 = session2.run(stringOnnxTensorHashMap2);
                float[][][] result = (float[][][]) output2.get(0).getValue();
                String plateNo = decodePlate(maxScoreIndex(result[0]));
                System.err.println("车牌号码:"+plateNo);
                plateNumberList.add(plateNo);
                //车牌颜色识别
                float[][] color = (float[][]) output2.get(1).getValue();
                double[] colorSoftMax = softMax(floatToDouble(color[0]));
                Double[] colorRResult = decodeColor(colorSoftMax);
                carDetection.setPlateNo(plateNo);
                carDetection.setPlateColor( PLATE_COLOR[colorRResult[0].intValue()]);

                Point topLeft = new Point((bbox[0]-dw)/ratio, (bbox[1]-dh)/ratio);
                Point bottomRight = new Point((bbox[2]-dw)/ratio, (bbox[3]-dh)/ratio);
                Imgproc.rectangle(img, topLeft, bottomRight, new Scalar(0,255,0), thickness);
                // 框上写文字
                BufferedImage bufferedImage = matToBufferedImage(img);
                Point boxNameLoc = new Point((bbox[0]-dw)/ratio, (bbox[1]-dh)/ratio-3);
                Graphics2D g2d = bufferedImage.createGraphics();
                g2d.setFont(new Font("微软雅黑", Font.PLAIN, 20));
                g2d.setColor(Color.RED);
                g2d.drawString(PLATE_COLOR[colorRResult[0].intValue()]+"-"+plateNo, (int)((bbox[0]-dw)/ratio), (int)((bbox[1]-dh)/ratio-3)); // 假设的文本位置
                g2d.dispose();

                try {
                    ImageIO.write(bufferedImage, "jpg", new File(outputPath));
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }

            }
            System.out.printf("time:%d ms.", (System.currentTimeMillis() - start_time));

            System.out.println();



            // 弹窗展示图像
            HighGui.imshow("Display Image", Imgcodecs.imread(outputPath));
            // 按任意按键关闭弹窗画面,结束程序
            HighGui.waitKey();

        }

        HighGui.destroyAllWindows();
        //System.exit(0);
        System.out.println("识别完成,车牌信息:"+plateNumberList);
        return plateNumberList;

    }

    public static void xywh2xyxy(float[] bbox) {
        float x = bbox[0];
        float y = bbox[1];
        float w = bbox[2];
        float h = bbox[3];

        bbox[0] = x - w * 0.5f;
        bbox[1] = y - h * 0.5f;
        bbox[2] = x + w * 0.5f;
        bbox[3] = y + h * 0.5f;
    }

    public static List<float[]> nonMaxSuppression(List<float[]> bboxes, float iouThreshold) {

        List<float[]> bestBboxes = new ArrayList<>();

        bboxes.sort(Comparator.comparing(a -> a[4]));

        while (!bboxes.isEmpty()) {
            float[] bestBbox = bboxes.remove(bboxes.size() - 1);
            bestBboxes.add(bestBbox);
            bboxes = bboxes.stream().filter(a -> computeIOU(a, bestBbox) < iouThreshold).collect(Collectors.toList());
        }

        return bestBboxes;
    }


    // 单纯为了显示中文演示使用,实际项目中用不到这个
    public static BufferedImage matToBufferedImage(Mat mat) {
        int type = BufferedImage.TYPE_BYTE_GRAY;
        if (mat.channels() > 1) {
            type = BufferedImage.TYPE_3BYTE_BGR;
        }
        int bufferSize = mat.channels() * mat.cols() * mat.rows();
        byte[] b = new byte[bufferSize];
        mat.get(0, 0, b); // 获取所有像素数据
        BufferedImage image = new BufferedImage(mat.cols(), mat.rows(), type);
        final byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
        System.arraycopy(b, 0, targetPixels, 0, b.length);
        return image;
    }

    private static int[] maxScoreIndex(float[][] result){
        int[] indexes = new int[result.length];
        for (int i = 0; i < result.length; i++){
            int index = 0;
            float max = Float.MIN_VALUE;
            for (int j = 0; j < result[i].length; j++) {
                if (max < result[i][j]){
                    max = result[i][j];
                    index = j;
                }
            }
            indexes[i] = index;
        }
        return indexes;
    }

    public static float computeIOU(float[] box1, float[] box2) {

        float area1 = (box1[2] - box1[0]) * (box1[3] - box1[1]);
        float area2 = (box2[2] - box2[0]) * (box2[3] - box2[1]);

        float left = Math.max(box1[0], box2[0]);
        float top = Math.max(box1[1], box2[1]);
        float right = Math.min(box1[2], box2[2]);
        float bottom = Math.min(box1[3], box2[3]);

        float interArea = Math.max(right - left, 0) * Math.max(bottom - top, 0);
        float unionArea = area1 + area2 - interArea;
        return Math.max(interArea / unionArea, 1e-8f);

    }

    private static Double[] decodeColor(double[] indexes){
        double index = -1;
        double max = Double.MIN_VALUE;
        for (int i = 0; i < indexes.length; i++) {
            if (max < indexes[i]){
                max = indexes[i];
                index = i;
            }
        }
        return new Double[]{index, max};
    }



    public static double [] floatToDouble(float[] input){
        if (input == null){
            return null;
        }
        double[] output = new double[input.length];
        for (int i = 0; i < input.length; i++){
            output[i] = input[i];
        }
        return output;
    }

    private static String decodePlate(int[] indexes){
        int pre = 0;
        StringBuffer sb = new StringBuffer();
        for(int index : indexes){
            if(index != 0 && pre != index){
                sb.append(PLATE_NAME.charAt(index));
            }
            pre = index;
        }
        return sb.toString();
    }

    //返回最大值的索引
    public static int argmax(float[] a) {
        float re = -Float.MAX_VALUE;
        int arg = -1;
        for (int i = 0; i < a.length; i++) {
            if (a[i] >= re) {
                re = a[i];
                arg = i;
            }
        }
        return arg;
    }


    public static double[] softMax(double[] tensor){
        if(Arrays.stream(tensor).max().isPresent()){
            double maxValue = Arrays.stream(tensor).max().getAsDouble();
            double[] value = Arrays.stream(tensor).map(y-> Math.exp(y - maxValue)).toArray();
            double total = Arrays.stream(value).sum();
            return Arrays.stream(value).map(p -> p/total).toArray();
        }else{
            throw new NoSuchElementException("No value present");
        }
    }
    public static Map<String, String> getImagePathMap(String imagePath){
        Map<String, String> map = new TreeMap<>();
        File file = new File(imagePath);
        if(file.isFile()){
            map.put(file.getName(), file.getAbsolutePath());
        }else if(file.isDirectory()){
            for(File tmpFile : Objects.requireNonNull(file.listFiles())){
                map.putAll(getImagePathMap(tmpFile.getPath()));
            }
        }
        return map;
    }


}

剩余一些工具类代码可以看文章最后GitHub地址

四、测试

键盘按任意键继续

最后处理后输出的图片:

最后拿到结果:

识别完成~~

GitHub地址:GitHub - bluefoxyu/yolo-study: 学习yolo+java案例第一次提交

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

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

相关文章

ES5到ES6 js的语法更新

js是一门弱语言类型&#xff0c;为了实现更有逻辑的代码&#xff0c;需要不断更新语法规范&#xff0c;es就是用来规范js语法的标准。 09年发布了es5&#xff0c;到15年发布es6&#xff0c;到现在es6泛指es5.1以后的版本es2016&#xff0c;es2017。 var、let、const 关键字&…

Promise学习之基本方法

前言 上一篇章我们学习了Promise的概念、基本使用、状态等等&#xff0c;对于Promise也有了基础的了解&#xff0c;那本章就对与Promise的方法作基本学习&#xff0c;去了解了解Promise提供了什么方法。 一、then then处理Promise返回结果&#xff0c;接收两个回调函数 第一…

新建一个基于标准新建一个基于标准固件库的工程模板固件库的工程模板(实现LED单灯闪烁)

实验报告原件在资源可选择性下载 一、实验目的&#xff1a; 1.了解STM32固件库&#xff1b; 2.掌握STM32固件库关键子目录及固件库关键文件&#xff1b; 3.能够新建一个基于标准固件库的工程模板并完成编译 二、实验器材&#xff1a; 笔记本或电脑。 三、实验内容&#…

大投资模型 arxiv 量化论文

郭建与沉向阳 摘要 传统的量化投资研究面临着回报递减以及劳动力和时间成本上升的问题。 为了克服这些挑战&#xff0c;我们引入了大型投资模型&#xff08;LIM&#xff09;&#xff0c;这是一种新颖的研究范式&#xff0c;旨在大规模提高绩效和效率。 LIM 采用端到端学习和通…

数据结构系列-归并排序

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 归并排序 递归版本 首先&#xff0c;我们来看一下归并的示意图&#xff1a; 这是归并排序当中分解的过程。 然后便是两个两个进行排序&#xff0c;组合的过程。 归并完美的诠释…

docker镜像,ip,端口映射,持久化

docker 镜像的迁移&#xff1a;导出和导入镜像 查看镜像&#xff1a; [rootdocker ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE centos latest 5d0da3dc9764 2 years ago 231MB 打包 将镜像打包&#xff0c;找到save,可以将…

远程在电脑上玩PS5《黑神话:悟空》?借助极空间实现PS5远程串流攻略

远程在电脑上玩PS5《黑神话&#xff1a;悟空》&#xff1f;借助极空间实现PS5远程串流攻略 哈喽小伙伴们好&#xff0c;我是Stark-C~ 这两天的《黑神话&#xff1a;悟空》可谓是火爆出圈呀&#xff01;虽说我也是第一时间体验到了这款可以说是划时代意义的首款国产3A大作&…

maven 依赖管理(4)

依赖就是项目里运行的jar 一个项目可以设置多个依赖 这种的 1.依赖传递 直接依赖&#xff1a;就是当前自己的项目pom里的依赖 间接依赖&#xff1a;在自己pom文件引入别人的项目 就能共享到别人项目的依赖 2.依赖传递冲突问题 路径优先&#xff1a;出现相同依赖&#xff0…

华为数通方向HCIP-DataCom H12-821题库(更新单选真题:1-10)

第1题 1、下面是一台路由器的部分配置,关于该配置描述正确的是? [HUAWEllact number 2001 [HUAWEl-acl-basic-2001]rule 0 permit source 1.1.1.1 0 [HUAWEl-acl-basic-2001]rule 1 deny source 1.1.1.0 0 [HUAWEl-acl-basic-2001]rule

SSRF+Redis+Fastcgi

目录 1、打redis 2、打fastcgi 3、SSRF绕过 4、SSRF防御 1、打redis ssrfme靶场实战 页面直接给出了代码&#xff0c;过滤了file: dict ,等等 但是下面我们看到只要有info就能打印phpinfo() 通过phpinfo()打印的信息&#xff0c;发现有内网其他服务器的ip 直接访问 发现…

漏洞挖掘 | 浅谈一次edusrc文件上传成功getshell

0x1 前言 这里记录一下我在微信小程序挖人社局等一些人力资源和社会保障部信息中心漏洞&#xff0c;人社这类漏洞相对于web应用端的漏洞来讲要好挖很多&#xff0c;里面的WAF过滤等一些验证也少。比如你在开始学习src漏洞挖掘&#xff0c;就可以从微信小程序下手。 一般像这类…

Python编码系列—Python CI/CD 实战:构建高效的自动化流程

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…

(7)JavaSE:注解与反射

一、注解 1.1什么是注解 Annotation 是从JDK5.0开始引入的新技术 。 作用: &#xff08;1&#xff09;不是程序本身 , 可以对程序作出解释.(这一点和注释(comment)没什么区别) &#xff08;2&#xff09;可以被其他程序(比如:编译器等)读取.使用范围&#xff1a; &#xff0…

Python进阶(十一)】—— Pandas和Seaborn可视化

&#x1f349;CSDN小墨&晓末:https://blog.csdn.net/jd1813346972 个人介绍: 研一&#xff5c;统计学&#xff5c;干货分享          擅长Python、Matlab、R等主流编程软件          累计十余项国家级比赛奖项&#xff0c;参与研究经费10w、40w级横向 文…

数字化与进制转换

1.数字化是什么&#xff1f; 数字化是将事物的属性转化为计算机可处理对象的过程。 2.数字化的好处&#xff1f; 可以让我们的生活&#xff0c;学习和工作更加便捷&#xff0c;大大提升我们学习和工作的效率。 3.如何将采集到的数据进行数字化&#xff1f; 可以通过两种信…

运维的利器–监控–zabbix–第三步:配置zabbix–网络–原理:通过ping实现网络连通性监控

文章目录 通过ping实现网络连通性监控1、参数说明2、建立监控项3、创建图形 通过ping实现网络连通性监控 1、参数说明 ICMPPING[,,,,]通过ICMP ping检查主机是否可以访问。 target-目标IP或者域名 packets-数据包数量 interval-间隔时间&#xff08;毫秒&#xff09; size-数…

Windows系统电脑安装多个Tomcat服务教程

文章目录 引言I 下载Tomcat安装包II 安装tomcat多个tomcat服务重命名Tomcat应用程序安装Tomcat服务安装和配置JRE配置服务信息III 知识扩展: windows RDP远程访问资源引言 需求: 基于Tomcat部署多个服务和站点都一台Windows机器 I 下载Tomcat安装包 https://tomcat.apache.o…

LabVIEW高速数据采集关键问题

在LabVIEW进行高速数据采集时&#xff0c;需要关注以下几个关键问题&#xff1a; 数据采集硬件的选择: 高速数据采集需要高性能的数据采集硬件&#xff0c;例如NI PXIe、USB DAQ等模块。硬件的选择应根据采集速率、通道数、精度、以及应用场景的具体需求来确定。 采集速率与带…

认知杂谈22

今天分享 有人说的一段争议性的话 I I 私人空间&#xff0c;成长的温床 咱一说到成长啊&#xff0c;可不能小瞧了外部环境对咱的影响。这环境啊&#xff0c;那可不是无关紧要的事儿&#xff0c;实际上呢&#xff0c;它对咱的成长起着特别关键的作用。你就想想看&#xff0c…

ssrf漏洞复现分析(1)

目录 Web-ssrfme 搭建环境 分析 ssrf攻击本地fastcgi漏洞复现 Web-ssrfme 搭建环境 这里我们使用的是docker环境&#xff0c;只需要把docker压缩包下载到Ubuntu下解压后执行命令即可&#xff0c; docker-compose up -d 但是我的环境中不知道是缺少什么东西&#xff0c;他…