YOLOV4-车道线检测-车距离预测

news2025/5/24 16:38:39

1.前言

        最近在看华为的CANN框架,发现了一些很有意思的开源算法(本文所有的代码都出自华为开源git发布的代码),华为最近出了AI PRO开发板,想着现在开发板上用用(不想重新配置环境了,麻烦还累),看着代码有onnx的模型,就先用onnx实现,后续可能推出rknn的推理吧,谁知道呢。具体细节也不想写,无脑用就行。

2.代码准备

        代码是一个视频处理的程序,主要功能是使用YOLOv4模型进行目标检测,并结合车道检测,最后输出处理后的视频。

2.1 主要步骤

  1. 导入必要的库:导入了一系列常用的计算机视觉库,如OpenCV、numpy等,以及自定义的LaneFinder模块。
  2. 定义了一些常量和全局变量:包括类别标签、模型输入输出的尺寸、类别数量、锚点等。
  3. 定义了预处理函数preprocess:将输入的帧图像进行缩放和填充,使其符合模型的输入尺寸,并进行归一化处理。
  4. 定义了一些辅助函数:如计算两个框的重叠区域、计算IoU、应用非极大值抑制(NMS)等。
  5. 定义了模型输出解码函数decode_bbox:将模型输出的特征图转换为检测框的坐标和类别概率。
  6. 定义了后处理函数post_process:根据模型输出的结果进行NMS处理,并将检测结果转换为可读的格式。
  7. 定义了一些辅助函数:包括将标签转换为可读格式、处理帧图像等。
  8. 主函数main:读取视频帧,调用前述函数进行目标检测和车道检测,最后将结果写入输出视频文件中。

 2.2 JSON配置

        文件包含了相机校准矩阵、畸变系数、透视变换矩阵以及其他参数。

  1. cam_matrix(相机矩阵):相机内参矩阵,是用来描述相机的内部参数的一个3x3矩阵。其中包括了相机的焦距(fx、fy)、主点(cx、cy)等信息。在这个配置中,焦距分别为1156.94047、1152.13881,主点坐标为(665.948814, 388.784788)。

  2. dist_coeffs(畸变系数):相机的畸变系数,通常由径向畸变系数和切向畸变系数构成。这里包含了五个系数,分别是[-0.237638057, -0.0854041989, -0.000790999421, -0.000115882426, 0.105726054]。

  3. perspective_transform(透视变换矩阵):透视变换矩阵,用于将图像转换到鸟瞰图(俯视图)。该矩阵是一个3x3的矩阵,其中包含了变换的缩放、旋转和平移信息。

  4. pixels_per_meter(每米对应的像素数):这个参数表示在鸟瞰图中,每米对应的像素数。在水平方向上为46.56770571051312像素/m,在垂直方向上为33.06512376601635像素/m。

  5. WARPED_SIZE(鸟瞰图尺寸):进行透视变换后的图像尺寸,宽度为500像素,高度为600像素。

  6. ORIGINAL_SIZE(原始图像尺寸):原始图像的尺寸,宽度为1280像素,高度为720像素。

2.3 车道线检测

        LaneFinder.py是一个用于检测车道线的算法。以下是代码中各个函数的功能:

  1. get_center_shift(coeffs, img_size, pixels_per_meter): 计算车道线中心的偏移量。
  2. get_curvature(coeffs, img_size, pixels_per_meter): 计算车道线的曲率。
  3. LaneLineFinder: 一个类,用于检测车道线中的单条车道线。
  4. LaneFinder: 一个类,用于检测整个车道。它包括了左右两条车道线的检测。
  5. undistort(img): 对图像进行畸变校正。
  6. warp(img): 对图像进行透视变换,使车道线在图像中呈现平行。
  7. unwarp(img): 对透视变换后的图像进行逆变换,使车道线回到原始视角。
  8. equalize_lines(alpha): 对检测到的左右车道线进行均衡处理,使它们保持一定的间隔。
  9. find_lane(img, distorted=True, reset=False): 在图像中寻找车道线,包括畸变校正、透视变换、颜色过滤和车道线检测等步骤。
  10. draw_lane_weighted(img, thickness=5, alpha=0.8, beta=1, gamma=0): 在原始图像上绘制检测到的车道线,并添加曲率和车辆位置信息。
  11. process_image(img, reset=False): 对输入的图像进行处理,并返回带有检测到的车道线的图像。
  12. set_img_size(img_size): 设置图像的大小。

        这些函数共同构成了一个车道线检测算法,可以在道路图像中准确地检测出车道线并估计车辆的位置和行驶曲率。

2.4 主函数代码

import sys
import os
import json
import numpy as np
import cv2 as cv
from PIL import Image
import LaneFinder
import onnxruntime as rt

labels = ["person",
        "bicycle", "car", "motorbike", "aeroplane",
        "bus", "train", "truck", "boat", "traffic light",
        "fire hydrant", "stop sign", "parking meter", "bench",
        "bird", "cat", "dog", "horse", "sheep", "cow", "elephant",
        "bear", "zebra", "giraffe", "backpack", "umbrella", "handbag",
        "tie", "suitcase", "frisbee", "skis", "snowboard", "sports ball",
        "kite", "baseball bat", "baseball glove", "skateboard", "surfboard",
        "tennis racket", "bottle", "wine glass", "cup", "fork", "knife", "spoon",
        "bowl", "banana", "apple", "sandwich", "orange", "broccoli", "carrot", "hot dog",
        "pizza", "donut", "cake", "chair", "sofa", "potted plant", "bed", "dining table",
        "toilet", "TV monitor", "laptop", "mouse", "remote", "keyboard", "cell phone",
        "microwave", "oven", "toaster", "sink", "refrigerator", "book", "clock", "vase",
        "scissors", "teddy bear", "hair drier", "toothbrush"]

OUTPUT_DIR = '../out/'
MODEL_WIDTH = 608
MODEL_HEIGHT = 608
class_num = 80
stride_list = [32, 16, 8]
anchors_3 = np.array([[12, 16], [19, 36], [40, 28]]) / stride_list[2]
anchors_2 = np.array([[36, 75], [76, 55], [72, 146]]) / stride_list[1]
anchors_1 = np.array([[142, 110], [192, 243], [459, 401]]) / stride_list[0]
anchor_list = [anchors_1, anchors_2, anchors_3]
iou_threshold = 0.3
colors = [(255, 0, 0), (0, 255, 0), (0, 0, 255), (0, 255, 255), (255, 0, 255), (255, 255, 0)]

def preprocess(frame):
    image = Image.fromarray(cv.cvtColor(frame, cv.COLOR_BGR2RGB))
    img_h = image.size[1]
    img_w = image.size[0]
    net_h = MODEL_HEIGHT
    net_w = MODEL_WIDTH

    scale = min(float(net_w) / float(img_w), float(net_h) / float(img_h))
    new_w = int(img_w * scale)
    new_h = int(img_h * scale)

    shift_x = (net_w - new_w) // 2
    shift_y = (net_h - new_h) // 2
    shift_x_ratio = (net_w - new_w) / 2.0 / net_w
    shift_y_ratio = (net_h - new_h) / 2.0 / net_h

    image_ = image.resize((new_w, new_h))
    new_image = np.zeros((net_h, net_w, 3), np.uint8)
    new_image[shift_y: new_h + shift_y, shift_x: new_w + shift_x, :] = np.array(image_)
    new_image = new_image.astype(np.float32)
    new_image = new_image / 255
    print('new_image.shape', new_image.shape)
    new_image = new_image.transpose(2, 0, 1).copy().reshape(1, 3, 608, 608)
    return new_image, image

def overlap(x1, x2, x3, x4):
    left = max(x1, x3)
    right = min(x2, x4)
    return right - left

def cal_iou(box, truth):
    w = overlap(box[0], box[2], truth[0], truth[2])
    h = overlap(box[1], box[3], truth[1], truth[3])
    if w <= 0 or h <= 0:
        return 0
    inter_area = w * h
    union_area = (box[2] - box[0]) * (box[3] - box[1]) + (truth[2] - truth[0]) * (truth[3] - truth[1]) - inter_area
    return inter_area * 1.0 / union_area

def apply_nms(all_boxes, thres):
    res = []

    for cls in range(class_num):
        cls_bboxes = all_boxes[cls]
        sorted_boxes = sorted(cls_bboxes, key=lambda d: d[5])[::-1]
        p = dict()
        for i in range(len(sorted_boxes)):
            if i in p:
                continue
            truth = sorted_boxes[i]
            for j in range(i + 1, len(sorted_boxes)):
                if j in p:
                    continue
                box = sorted_boxes[j]
                iou = cal_iou(box, truth)
                if iou >= thres:
                    p[j] = 1
        for i in range(len(sorted_boxes)):
            if i not in p:
                res.append(sorted_boxes[i])
    return res

def _sigmoid(x):
    return 1.0 / (1 + np.exp(-x))


def decode_bbox(conv_output, anchors, img_w, img_h, x_scale, y_scale, shift_x_ratio, shift_y_ratio):
    print('conv_output.shape', conv_output.shape)
    _, _, h, w = conv_output.shape 
    conv_output = conv_output.transpose(0, 2, 3, 1)
    pred = conv_output.reshape((h * w, 3, 5 + class_num))
    pred[..., 4:] = _sigmoid(pred[..., 4:])
    pred[..., 0] = (_sigmoid(pred[..., 0]) + np.tile(range(w), (3, h)).transpose((1, 0))) / w
    pred[..., 1] = (_sigmoid(pred[..., 1]) + np.tile(np.repeat(range(h), w), (3, 1)).transpose((1, 0))) / h
    pred[..., 2] = np.exp(pred[..., 2]) * anchors[:, 0:1].transpose((1, 0)) / w
    pred[..., 3] = np.exp(pred[..., 3]) * anchors[:, 1:2].transpose((1, 0)) / h

    bbox = np.zeros((h * w, 3, 4))
    bbox[..., 0] = np.maximum((pred[..., 0] - pred[..., 2] / 2.0 - shift_x_ratio) * x_scale * img_w, 0)  # x_min
    bbox[..., 1] = np.maximum((pred[..., 1] - pred[..., 3] / 2.0 - shift_y_ratio) * y_scale * img_h, 0)  # y_min
    bbox[..., 2] = np.minimum((pred[..., 0] + pred[..., 2] / 2.0 - shift_x_ratio) * x_scale * img_w, img_w)  # x_max
    bbox[..., 3] = np.minimum((pred[..., 1] + pred[..., 3] / 2.0 - shift_y_ratio) * y_scale * img_h, img_h)  # y_max
    pred[..., :4] = bbox
    pred = pred.reshape((-1, 5 + class_num))
    pred[:, 4] = pred[:, 4] * pred[:, 5:].max(1)
    pred[:, 5] = np.argmax(pred[:, 5:], axis=-1)    
    pred = pred[pred[:, 4] >= 0.2]
    print('pred[:, 5]', pred[:, 5])
    print('pred[:, 5] shape', pred[:, 5].shape)

    all_boxes = [[] for ix in range(class_num)]
    for ix in range(pred.shape[0]):
        box = [int(pred[ix, iy]) for iy in range(4)]
        box.append(int(pred[ix, 5]))
        box.append(pred[ix, 4])
        all_boxes[box[4] - 1].append(box)
    return all_boxes

def convert_labels(label_list):
    if isinstance(label_list, np.ndarray):
        label_list = label_list.tolist()
        label_names = [labels[int(index)] for index in label_list]
    return label_names


def post_process(infer_output, origin_img):
    print("post process")
    result_return = dict()
    img_h = origin_img.size[1]
    img_w = origin_img.size[0]
    scale = min(float(MODEL_WIDTH) / float(img_w), float(MODEL_HEIGHT) / float(img_h))
    new_w = int(img_w * scale)
    new_h = int(img_h * scale)
    shift_x_ratio = (MODEL_WIDTH - new_w) / 2.0 / MODEL_WIDTH
    shift_y_ratio = (MODEL_HEIGHT - new_h) / 2.0 / MODEL_HEIGHT
    class_number = len(labels)
    num_channel = 3 * (class_number + 5)
    x_scale = MODEL_WIDTH / float(new_w)
    y_scale = MODEL_HEIGHT / float(new_h)
    all_boxes = [[] for ix in range(class_number)]
    # print(infer_output[0].shape)
    # print(infer_output[1].shape)
    # print(infer_output[2].shape)
    for ix in range(3):    
        pred = infer_output[ix]
        print('pred.shape', pred.shape)
        anchors = anchor_list[ix]
        boxes = decode_bbox(pred, anchors, img_w, img_h, x_scale, y_scale, shift_x_ratio, shift_y_ratio)
        all_boxes = [all_boxes[iy] + boxes[iy] for iy in range(class_number)]
        print("all_box:", all_boxes)
    res = apply_nms(all_boxes, iou_threshold)
    print("res:", res)
    if not res:
        result_return['detection_classes'] = []
        result_return['detection_boxes'] = []
        result_return['detection_scores'] = []
        return result_return
    else:
        new_res = np.array(res)
        picked_boxes = new_res[:, 0:4]
        picked_boxes = picked_boxes[:, [1, 0, 3, 2]]
        picked_classes = convert_labels(new_res[:, 4])
        picked_score = new_res[:, 5]
        result_return['detection_classes'] = picked_classes
        result_return['detection_boxes'] = picked_boxes.tolist()
        result_return['detection_scores'] = picked_score.tolist()
        return result_return

def preprocess_frame(bgr_img):
    bgr_img = bgr_img[:, :, ::-1]
    image = bgr_img
    image = LaneFinder.Image.fromarray(image.astype('uint8'), 'RGB')
    fframe = np.array(image)
    fframe = lf.process_image(fframe, False)
    frame = LaneFinder.Image.fromarray(fframe)
    framecv = cv.cvtColor(np.asarray(frame), cv.COLOR_RGB2BGR)
    return framecv

def calculate_position(bbox, transform_matrix, warped_size, pix_per_meter): 
    if len(bbox) == 0:
        print('Nothing')
    else:
        point = np.array((bbox[1] / 2 + bbox[3] / 2, bbox[2])).reshape(1, 1, -1)
        pos = cv.perspectiveTransform(point, transform_matrix).reshape(-1, 1)
        return np.array((warped_size[1] - pos[1]) / pix_per_meter[1])

def main():
    if (len(sys.argv) != 2):
        print("Please input video path")
        exit(1)
    frame_count = 0
    sess = rt.InferenceSession('../model/yolov4_bs.onnx')
    #open video
    video_path = sys.argv[1]
    print("open video ", video_path)
    cap = cv.VideoCapture(video_path)
    fps = cap.get(cv.CAP_PROP_FPS)
    Width = int(cap.get(cv.CAP_PROP_FRAME_WIDTH))
    Height = int(cap.get(cv.CAP_PROP_FRAME_HEIGHT))

    lf.set_img_size((Width, Height))

    #create output directory
    if not os.path.exists(OUTPUT_DIR):
        os.mkdir(OUTPUT_DIR)
    output_Video = os.path.basename(video_path)
    output_Video = os.path.join(OUTPUT_DIR, output_Video)

    fourcc = cv.VideoWriter_fourcc(*'mp4v')  # DIVX, XVID, MJPG, X264, WMV1, WMV2
    outVideo = cv.VideoWriter(output_Video, fourcc, fps, (Width, Height))
    
    # 模型的输入和输出节点名,可以通过netron查看
    input_name = 'input'
    outputs_name = ['feature_map_1', 'feature_map_2', 'feature_map_3']
    # Read until video is completed
    while (cap.isOpened()):
        ret, frame = cap.read()
        if ret == True:
            #preprocess
            data, orig = preprocess(frame)
            result_list = sess.run(outputs_name, {input_name: data})
            result_return = post_process(result_list, orig)
            frame_with_lane = preprocess_frame(frame)

            distance = np.zeros(shape=(len(result_return['detection_classes']), 1))
            for i in range(len(result_return['detection_classes'])):
                box = result_return['detection_boxes'][i]
                class_name = result_return['detection_classes'][i]
                # confidence = result_return['detection_scores'][i]
                distance[i] = calculate_position(bbox=box, transform_matrix=perspective_transform,
                            warped_size=WARPED_SIZE, pix_per_meter=pixels_per_meter)
                label_dis = '{} {:.2f}m'.format('dis:', distance[i][0])
                cv.putText(frame_with_lane, label_dis, (int(box[1]) + 10, int(box[2]) + 15), 
                            cv.FONT_ITALIC, 0.6, colors[i % 6], 1)

                cv.rectangle(frame_with_lane, (int(box[1]), int(box[0])), (int(box[3]), int(box[2])), colors[i % 6])
                p3 = (max(int(box[1]), 15), max(int(box[0]), 15))
                out_label = class_name
                cv.putText(frame_with_lane, out_label, p3, cv.FONT_ITALIC, 0.6, colors[i % 6], 1)

            outVideo.write(frame_with_lane)
            print("FINISH PROCESSING FRAME: ", frame_count)
            frame_count += 1
        else:
            break
    cap.release()
    outVideo.release()
    print("Execute end")


if __name__ == '__main__':
    path = './configure.json'
    config_file = open(path, "rb")
    fileJson = json.load(config_file)
    cam_matrix = fileJson[0]["cam_matrix"]
    dist_coeffs = fileJson[0]["dist_coeffs"]
    perspective_transform = fileJson[0]["perspective_transform"]
    pixels_per_meter = fileJson[0]["pixels_per_meter"]
    WARPED_SIZE = fileJson[0]["WARPED_SIZE"]
    ORIGINAL_SIZE = fileJson[0]["ORIGINAL_SIZE"]

    cam_matrix = np.array(cam_matrix)
    dist_coeffs = np.array(dist_coeffs)
    perspective_transform = np.array(perspective_transform)
    pixels_per_meter = tuple(pixels_per_meter)
    WARPED_SIZE = tuple(WARPED_SIZE)
    ORIGINAL_SIZE = tuple(ORIGINAL_SIZE)

    lf = LaneFinder.LaneFinder(ORIGINAL_SIZE, WARPED_SIZE, cam_matrix, dist_coeffs,
                    perspective_transform, pixels_per_meter)
    main()

3.结果视频

4. 结尾

        代码可以去资源下载,就这样吧

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

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

相关文章

《深入Linux内核架构》第2章 进程管理和调度 (3)

目录 2.5 调度器的实现 2.5.1 概观 2.5.2 数据结构 2.5.3 处理优先级 2.5.3.1 nice和prior 2.5.3.2 vruntime 2.5.3.3 weight权重 2.5.4 核心调度器 2.5 调度器的实现 调度器的任务&#xff1a; 1. 执行调度策略。 2. 执行上下文切换。 无论用户态抢占&#xff0c;还是…

Spring MVC入门(4)

请求 获取Cookie/Session 获取Cookie 传统方式: RequestMapping("/m11")public String method11(HttpServletRequest request, HttpServletResponse response) {//获取所有Cookie信息Cookie[] cookies request.getCookies();//打印Cookie信息StringBuilder build…

大数据主要技术

1.大数据文件系统&#xff1a; GFS(谷歌的分布式文件系统&#xff09; HDFS&#xff08;hadoop distrubuted file system&#xff09;分布式文件系统&#xff0c;衍生自GFS 2.大数据平台 MapReduce &#xff1a;谷歌的大数据处理平台&#xff0c;服务于搜索 Hadoop&#…

C#混淆心得

C#混淆心得 近期遇到混淆C#代码的需求&#xff0c;在网上找了很多办法&#xff0c;在此记录一下。 混淆的本质就是让代码变丑&#xff0c;让别人看不懂。 为什么要混淆&#xff1a; 1.保护核心代码 可以在一定程度上避免别人偷代码&#xff0c;从而保护重要的部分&#xf…

蓝桥杯单片机快速开发笔记——超声波测距

一、原理分析 超声波测距是一种常见的测距方法&#xff0c;其原理是利用超声波在空气中传播的速度恒定且较快的特性&#xff0c;通过发送超声波信号并接收回波&#xff0c;计算出物体与传感器之间的距离。以下是超声波测距的原理和应用&#xff1a; 原理&#xff1a; 发送超声…

Linux安装Mysql5.7数据库

一、前置条件 系统版本&#xff1a;Linux CentOS 7.5 MySQL版本&#xff1a;mysql5.7.31 二、操作步骤 2.1、关闭mysql服务 service mysqld stop 提示使用命令&#xff1a;systemctl stop mysqld.service 2.2、grep查找已安装的mysql服务 rpm -qa | grep -i mysql 2.3、卸载…

机器学习(1)机器学习的概念与应用领域

文章目录 一、前提二、机器学习的概念与应用领域1.认识①亚瑟•塞缪尔的定义②汤姆米切尔的定义 2.相关术语数据术语训练模型术语获得模型后术语 3.应用领域语音识别计算机视觉自然语言处理①自然语言分析②自然语言生成 大数据分析 一、前提 Python语言具有数量庞大且功能相对…

记录一次爬虫接单项目【采集国际淘宝数据】

1.背景 前几天接了一个爬虫的单子&#xff0c;上周六已经完成这个单子&#xff0c;也收到了酬劳&#xff08;数目还不错&#xff0c;哈哈哈&#xff0c;小喜了一下&#xff09;。这个项目大概我用了两天写完了&#xff08;空闲时间写的&#xff09;。 2.介绍 大概要采集的数据…

Flutter-仿淘宝京东录音识别图标效果

效果 需求 弹起键盘&#xff0c;录制按钮紧挨着输入框收起键盘&#xff0c;录制按钮回到初始位置 实现 第一步&#xff1a;监听键盘弹起并获取键盘高度第二步&#xff1a;根据键盘高度&#xff0c;录制按钮高度计算偏移高度&#xff0c;并动画移动第三步&#xff1a;键盘收起…

深度学习_卷积

卷积 卷积&#xff08;Convolution&#xff09;是数学和计算机科学中的一个重要概念&#xff0c;特别在信号处理和图像处理中应用广泛。在信号处理领域&#xff0c;卷积是两个函数之间的一种数学操作&#xff0c;它表示两个函数的重叠部分的积分量。 在图像处理中&#xff0c…

KKVIEW远程: TODESK退出了还能远程吗

Todesk退出了还能远程吗 当我们谈论Todesk或其他远程桌面软件时&#xff0c;一个经常被提及的问题是&#xff1a;当我退出Todesk后&#xff0c;是否仍然可以远程访问我的计算机&#xff1f;为了回答这个问题&#xff0c;我们首先需要了解Todesk的工作原理和远程访问的基本条件…

WhatsApp商业推广有哪些推广技巧?

在现代化商业&#xff0c;与用户创造紧密、良好的互动体验&#xff0c;建立强大的品牌形象以及找到最佳的推广途径&#xff0c;变得尤为重要。而WhatsApp作为全球使用最广泛的即时通讯应用之一&#xff0c;成为无数企业选择优选的推广平台。那么&#xff0c;在WhatsApp商业推广…

图书推荐|西门子S7-1200 PLC编程与应用实例

一线资深工程师的全彩版PLC实战教程&#xff0c;软硬件及编程全方位详解&#xff08;配视频教学&#xff09; 本书内容 《西门子S7-1200 PLC编程与应用实例》对西门子S7-1200 PLC的硬件和编程软件的功能进行详细讲解&#xff0c;内容包括PLC编程基础、博途TIA软件入门、指令介…

使用OCC进行切割操作

OCC中切割操作以一个平面作为切割面&#xff0c;对物体进行切割操作 //要操作的图形 TopoDS_Shape shape getHanleShape(); //构造切割面 TopoDS_Shape faceShape getSplitterFace(); //切割操作 BOPAlgo_Splitter splitter; splitter.AddArgument(shape); splitter.AddTool(…

13.Python从入门到精通—Python 集合操作与方法概览

13.Python从入门到精通—Python 集合操作与方法概览 Python 集合集合的基本操作1、添加元素2、移除元素3、计算集合元素个数4、清空集合5、判断元素是否在集合中存在 集合内置方法完整列表 Python 集合 在Python中&#xff0c;集合是一种无序、不重复的数据类型。集合通常用于…

unicloud快速上手,unicloud项目创建以及项目创建注意事项

uniCloud快速上手 本项目地址https://gitee.com/qayrup/unicloud-demo 创建unicloud项目 新建一个uni项目,并选择启用unicloud,选择阿里云或腾讯云 阿里云和支付宝云都支持一个月免费的云,如果只想体验啥的,可以选择这两个, 但是需要注意,支付宝云需要配置跨域,否则很多云函…

0基础学习VR全景平台篇第145篇:图层控件功能

大家好&#xff0c;欢迎观看蛙色VR官方——后台使用系列课程&#xff01;这期&#xff0c;我们将为大家介绍如何使用图层控件功能。 一.如何使用图层控件功能&#xff1f; 进入作品编辑页面&#xff0c;点击左边的控件后就可以在右边进行相应设置。 二.图层控件有哪些功能&am…

C++有关内存的那些事

个人主页&#xff1a;PingdiGuo_guo 收录转栏&#xff1a;C干货专栏 前言 本篇博客是讲解关于C内存的一些知识点的。 文章目录 前言 1.内存函数 1.1memcpy函数 1.2memmove函数 1.3 memset函数 2.各数据类型占用 2.1bool类型 2.2char类型 2.3short、int、long类型及整数…

英语广场杂志英语广场杂志社英语广场编辑部2024年第3期目录

英语翻译理论与实践 浅析钱钟书“化境论”与文言文英译的适配度 冯睿;姚锦宁;李佳彧; 3-6《英语广场》投稿&#xff1a;cn7kantougao163.com 目的论视角下《写作、阅读和演讲的艺术》的翻译分析报告 张俊怡; 7-10 新加坡籍译者温宏文翻译行为研究 周梦; 11-14 …

CVE-2024-24112 XMall后台管理系统 SQL 注入漏洞分析

------作者本科毕业设计项目 基于 Spring Boot Vue 开发而成...... [Affected Component] /item/list /item/listSearch /sys/log /order/list /member/list (need time-based blind injection) /member/list/remove 项目下载地址 Exrick/xmall: 基于SOA架构的分布式…