yolov5-7.0模型DNN加载函数及参数详解(重要)

news2024/10/6 17:18:36

yolov5-7.0模型DNN加载函数及参数详解(重要)

  • 引言
  • yolov5(v7.0)
    • 1,yolov5.h(加载对应模型里面的相关参数要更改)
    • 2,main主程序
      • (1)加载网络
      • (2)检测推理(forward)
        • (2.1)制作黑背景正方形,用于blobFromImage的无损缩放
        • (2.2)blobFromImage改变图像格式为网络出入格式
        • (2.3)输入setInput图像并forward推理
        • (2.4)结果解析
          • (2.4.0)方法0直接Mat读取解析(主要用于理解输出结构)
          • (2.4.1)方法1指针法Mat.data解析(快但不易理解)
        • (2.5)绘制结果

引言

  使用opencv的dnn模块对应yolov5(v7.0)的导出的onnx模型进行推理解析,明确各个参数的对应含义及结果。理论上,有了onnx模型,有了该网络模型的输入输出各个参数含义,就可以使用任意的可以读取onnx模型的部署框架进行部署推理。

yolov5(v7.0)

Yolov5(v7.0)
部署:使用opencv4.5.5(opencv4.5.4以上可以读取网络),dnn模块部署

已经导出的cpu、opset=12、640大小图像、默认静态
在这里插入图片描述

如上,输入输出层在后面的DNN模块推理会用到

1,yolov5.h(加载对应模型里面的相关参数要更改)

需要修改的相关参数如下:要根据自己的模型来进行
在这里插入图片描述
在这里插入图片描述

#include <fstream>
#include <sstream>
#include <iostream>
#include <opencv2/dnn.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
using namespace cv;
using namespace dnn;
using namespace std;

class YOLO
{
public:
    struct Detection
    {
        int class_id;
        float confidence;
        Rect box;
    };
public:
    YOLO();
    ~YOLO();
    bool loadNet(string model_path, bool is_cuda);
    Mat formatYolov5(const Mat& source);
    void detect(Mat& image, vector<Detection>& output);
    void drawRect(Mat& image, vector<Detection>& output);
private:
    Net m_net;
    //修改为训练时自己模型Img大小
    float inputWidth = 640;
    float inputHeight = 640;
    //修改 dimensions = 类别数 + 5
    const int dimensions = 6;
    //修改 通过Netron可查看,图片大小320,rows为6300,图片大小640,rows为25200
    const int rows = 25200;

    float scoreThreshold = 0.2;
    float nmsThreshold = 0.4;
    float confThreshold = 0.4;
public:
    //修改为自己的类别数
    const vector<string> m_classNames = { "qrcode" };
    /*const std::vector<std::string> m_classNames = { "person", "bicycle", "car", "motorcycle", "airplane", "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", "couch",
        "potted plant", "bed", "dining table", "toilet", "tv", "laptop", "mouse", "remote", "keyboard", "cell phone",
        "microwave", "oven", "toaster", "sink", "refrigerator", "book", "clock", "vase", "scissors", "teddy bear",
        "hair drier", "toothbrush" };*/

    const vector<Scalar> colors = { Scalar(255, 255, 0), Scalar(0, 255, 0), Scalar(0, 255, 255), Scalar(255, 0, 0) };
};

2,main主程序

int main(int argc, char** argv)
{
    Mat frame = imread("2.jpeg");
    YOLO yolov5;
    //加载模型
    yolov5.loadNet("qrcode.onnx", false);
    std::vector<YOLO::Detection> output;

    //进行检测
    //检测时间
    DWORD time_start, time_end;
    /* 获取开始时间 */
    time_start = GetTickCount(); //从操作系统启动经过的毫秒数

    yolov5.detect(frame, output);

    time_end = GetTickCount();
    int time = (time_end - time_start);
    cout << "Time = " << (time_end - time_start) << "ms\n ";
    //将所耗时间显示到图片上
    putText(frame, format("time:%dms", time), Point(20, 50), FONT_HERSHEY_SIMPLEX, 1.2, Scalar(255, 0,0), 2);
    
    //绘制结果
    yolov5.drawRect(frame, output);
    imshow("output", frame);
    waitKey(0);
    return 0;
}

(1)加载网络

加载已经导出的onnx网络,打印各个层级参数,此时网络读取成功(opencv要在4.5.4以上)
bool YOLO::loadNet(string model_path, bool is_cuda)
{
    try {
        m_net = readNet(model_path);

        //获取各层信息
        vector<string> layer_names = m_net.getLayerNames();		//此时我们就可以获取所有层的名称了,有了这些可以将其ID取出
        for (int i = 0; i < layer_names.size(); i++) {
            int id = m_net.getLayerId(layer_names[i]);			//通过name获取其id
            auto layer = m_net.getLayer(id);						//通过id获取layer
            printf("layer id:%d,type:%s,name:%s\n", id, layer->type.c_str(), layer->name.c_str());	//将每一层的id,类型,姓名打印出来(可以明白此网络有哪些结构信息了)
        }
    }
    catch (const std::exception&) {
        cout << "load faild" << endl;
        return false;
    }
    
    if (is_cuda)
    {
        cout << "Attempty to use CUDA\n";
        m_net.setPreferableBackend(DNN_BACKEND_CUDA);
        m_net.setPreferableTarget(DNN_TARGET_CUDA_FP16);
    }
    else
    {
        cout << "Running on CPU\n";
        m_net.setPreferableBackend(DNN_BACKEND_OPENCV);
        m_net.setPreferableTarget(DNN_TARGET_CPU);
    }
    return true;
}

在这里插入图片描述

(2)检测推理(forward)

推理前要对图像进行预处理,使其变为网络的输入格式

(2.1)制作黑背景正方形,用于blobFromImage的无损缩放

也可以不制作黑背景,但后面blobFromImage缩放计算可能结果有损失

//制作黑背景正方形,用于blobFromImage的无损缩放
//对于长宽比过大的图片,由于opencv的blobFromImage()函数在缩放的时候不是无损缩放,
//会导致图像变形严重导致结果错误或者漏检。虽然blobFromImage里面有个参数可以保持比例缩放,
//但是只会保留中间的部分,两边信息全部丢掉,所以如果你的目标全部在中间就可以无所谓,
//如果不是,那么需要简单的自己做个无损缩放,制作一张全黑的3通道正方形图片,边长为原图的长边,
//最后将原图放在(0,0)的位置上面,这样就可以直接输入blobFromImage里面就可以实现无损缩放了,
//而且不用对检测结果进行二次修正位置了。
//https ://blog.csdn.net/qq_34124780/article/details/116464727
Mat YOLO::formatYolov5(const Mat& source)
{
    int col = source.cols;
    int row = source.rows;
    int _max = MAX(col, row);
    Mat result = Mat::zeros(_max, _max, CV_8UC3);
    source.copyTo(result(Rect(0, 0, col, row)));
    return result;
}
(2.2)blobFromImage改变图像格式为网络出入格式
 Mat blob;
 auto input_image = formatYolov5(image);
 blobFromImage(input_image, blob, 1. / 255., Size(inputWidth, inputHeight), Scalar(), true, false);//1. / 255.数据归一化,图像大小变为输入格式(640*640)true进行通道交换,false不进行切片

此时经过blobFromImage的图像就变成4维了,在imagewatch中不显示
在这里插入图片描述
在这里插入图片描述

(2.3)输入setInput图像并forward推理
m_net.setInput(blob);
vector<Mat> outputs;
m_net.forward(outputs, m_net.getUnconnectedOutLayersNames());

Forward函数有很多,可以得到如下,有的是将所有的输出结果得到(有时输出层有多个),有的是将对应层的输出结果得到,这里直接得到所有最终输出结果就行了
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

实际这里推理只有1个输出结果

 cout << "outputs.size():" << outputs.size() << endl;

在这里插入图片描述

(2.4)结果解析

实际此时推理输出为[1252006]共三维的图像,使用指针的方法的话二维还是三维都会展开成一维指针进行读取
在这里插入图片描述

输出结果如下dims=3维度
在这里插入图片描述

将其转换成Mat可以显示的方式,用于查看对应的效果
在这里插入图片描述

效果如下
在这里插入图片描述

(2.4.0)方法0直接Mat读取解析(主要用于理解输出结构)

在这里插入图片描述

与指针相比,通过mat数组获取对应的第4列的数据是对应的起来的,如下应该使用32F数据格式即可(要将其结果转为(25200*6格式的数据保存到mat中))
在这里插入图片描述

上图最右侧的第6列的数据是类的分数(虽然显示1,但实际上分值是浮点数接近1的)
在这里插入图片描述

三维的
在这里插入图片描述

//使用Mat进行相关数据的保存解析(这里主要通过mat用于理解对应的输出结构)
void YOLO::detect2(Mat& image, vector<Detection>& output) {
    Mat blob;
    auto input_image = formatYolov5(image);
    blobFromImage(input_image, blob, 1. / 255., Size(inputWidth, inputHeight), Scalar(), true, false);//1. / 255.数据归一化,图像大小变为输入格式(640*640)true进行通道交换,false不进行切片

    m_net.setInput(blob);
    vector<Mat> outputs;
    m_net.forward(outputs, m_net.getUnconnectedOutLayersNames());

    //结果解析
    //方法0、使用Mat进行解析
    //***********输出测试
    //几个输出结果
    cout << "outputs.size():" << outputs.size() << endl;

    /*Mat detect_res = m_net.forward("output0");
    cout << "detect_res.channels():" << detect_res.size() << endl;
    cout << "outputs[0].channels():" << outputs[0].size() << endl;*/

    //对其结果使用下方的重新复制一个MAT,这样的才能在imagewatch中看到,否则无法显示
    Mat d1 = outputs[0].clone();
    //重新定义一个Mat对象接收(将其转换成输出结构)(rows = 25200, dimensions=6)
    Mat detectionMat2(rows, dimensions, CV_32F, d1.ptr<float>());		//此处是初始化一个行为size[2],深度为浮点型,数据从detection中获取	
                                                                                        //使用imagewatch可以看到6*25200的数组,单通道32F深度
    cout << "detect_res.rows:" << detectionMat2.rows << endl;

    //先得到原始用于blobFromImage归一化的input_image图像与/640的比例,后面用于目标框的结果返回
    float x_factor1 = float(input_image.cols) / inputWidth;   //用于blobFromImage归一化的input_image图像/640,得到对应的比例
    float y_factor1 = float(input_image.rows) / inputHeight;  //用于blobFromImage归一化的input_image图像/640

    vector<int> class_ids1;
    vector<float> confidences1;
    vector<Rect> boxes1;
    //25200行的数据(对应的onnx的输出参数)
    for (int i = 0; i < detectionMat2.rows; i++) {
        float confidence1 = detectionMat2.at<float>(i, 4);         //置信度方框box的得分分值
        //cout << "confidence1:" << confidence1 << endl;
        if (confidence1 >= confThreshold)    //求置信度>某个值
        {
            //cout << "confidence1:" << confidence1 << endl;

            //求类别得分将第一个类别后面的所有的类别作为一个mat一行
            //制作一个vector对象,//循环从类别后面截取各个类的分值,并保存
            vector<float> classes_scores1;
            for (int j = 5; j < detectionMat2.cols; j++) {
                classes_scores1.push_back(detectionMat2.at<float>(i, j));
            }
            //求classes_scores1的最大值及对应的索引
            auto max_class_score = max_element(classes_scores1.begin(), classes_scores1.end());
            int idMax = max_class_score - classes_scores1.begin();
            //cout << "类别的分数值:" << *max_class_score << "id:" << idMax << endl;

            if (*max_class_score > scoreThreshold)
            {
                confidences1.push_back(confidence1);
                class_ids1.push_back(idMax);

                //前4行对应的(物体的x、y、w、h)(这里的x、y、w、h结果只是图像640*640的结果的,要返回)
                float x = detectionMat2.at<float>(i, 0);
                float y = detectionMat2.at<float>(i, 1);
                float w = detectionMat2.at<float>(i, 2);
                float h = detectionMat2.at<float>(i, 3);

                //将x、y、w、h结果返回(由640*640的结果返回到原图size()大小的结果)
                int left = int((x - 0.5 * w) * x_factor1);//(x_factor1*x)
                int top = int((y - 0.5 * h) * y_factor1);
                int width = int(w * x_factor1);             //宽高直接*对应比列即可
                int height = int(h * y_factor1);
                boxes1.push_back(Rect(left, top, width, height));   //得到最终原图对应的矩形框大小
            }
        }

    }

    cout << "boxes.size():" << boxes1.size() << endl;

    //NMS结果非极大值抑制(有些结果是重合的,此处通过nms去除)
    vector<int> nms_result; //保存对应的索引值
    NMSBoxes(boxes1, confidences1, scoreThreshold, nmsThreshold, nms_result);
    for (int i = 0; i < nms_result.size(); i++)
    {
        int idx = nms_result[i];
        Detection result;
        result.class_id = class_ids1[idx];
        result.confidence = confidences1[idx];
        result.box = boxes1[idx];
        output.push_back(result);
    }
}
(2.4.1)方法1指针法Mat.data解析(快但不易理解)
//使用指针进行相关的结果解析(更快速,但不易理解)(相关取值计算过程和上方一样,可以看detect2进行理解)
void YOLO::detect(Mat& image, vector<Detection>& output)
{
    Mat blob;
    auto input_image = formatYolov5(image);
    blobFromImage(input_image, blob, 1. / 255., Size(inputWidth, inputHeight), Scalar(), true, false);//1. / 255.数据归一化,图像大小变为输入格式(640*640)true进行通道交换,false不进行切片
    
    m_net.setInput(blob);
    vector<Mat> outputs;
    m_net.forward(outputs, m_net.getUnconnectedOutLayersNames());

     
    //方法1、使用指针进行解析(1*25200*6)
    float x_factor = float(input_image.cols) / inputWidth;   //用于blobFromImage归一化的input_image图像/640,得到对应的比例
    float y_factor = float(input_image.rows) / inputHeight;  //用于blobFromImage归一化的input_image图像/640
    float* data = (float*)outputs[0].data;  //获取输出结果的初始指针

    vector<int> class_ids;
    vector<float> confidences;
    vector<Rect> boxes;

    for (int i = 0; i < rows; ++i)
    {
        float confidence = data[4];          //置信度方框box的分值
        
        if (confidence >= confThreshold)    //求置信度
        {
            float* classes_scores = data + 5;   //求类别得分
            //求类别得分将第一个类别后面的所有的类别作为一个mat一行(x、y、w、h、confidence、class1、class2、、、)
            //一行,m_classNames.size()个长度
            Mat scores(1, m_classNames.size(), CV_32FC1, classes_scores);
            //求当前最大分数的类别及其索引
            Point class_id;
            double max_class_score;
            minMaxLoc(scores, 0, &max_class_score, 0, &class_id);

            if (max_class_score > scoreThreshold)
            {
                confidences.push_back(confidence);
                class_ids.push_back(class_id.x);

                //box
                float x = data[0];
                float y = data[1];
                float w = data[2];
                float h = data[3];
                int left = int((x - 0.5 * w) * x_factor);
                int top = int((y - 0.5 * h) * y_factor);
                int width = int(w * x_factor);
                int height = int(h * y_factor);
                boxes.push_back(Rect(left, top, width, height));
            }
        }
        data += dimensions;  //data隔着对应结果(类别数1+5(x、y、w、h))
    }

    //NMS结果非极大值抑制
    vector<int> nms_result;
    NMSBoxes(boxes, confidences, scoreThreshold, nmsThreshold, nms_result);
    for (int i = 0; i < nms_result.size(); i++)
    {
        int idx = nms_result[i];
        Detection result;
        result.class_id = class_ids[idx];
        result.confidence = confidences[idx];
        result.box = boxes[idx];
        output.push_back(result);
    }
}
(2.5)绘制结果

就是将矩形框、分值等数据绘制到对应的图像上

void YOLO::drawRect(Mat& image, vector<Detection>& output)
{
    int detections = output.size();
    for (int i = 0; i < detections; ++i)
    {
        auto detection = output[i];
        auto box = detection.box;
        auto classId = detection.class_id;
        const auto color = colors[classId % colors.size()];
        rectangle(image, box, color, 3);

        rectangle(image, Point(box.x, box.y - 40), Point(box.x + box.width, box.y), color, FILLED);
        string label = m_classNames[classId] + ":" + to_string(output[i].confidence);
        putText(image, label, Point(box.x, box.y - 5), FONT_HERSHEY_SIMPLEX, 1.5, Scalar(0, 0, 0), 2);
    }

}

下面是Yolov5s.onnx对应模型的结果

在这里插入图片描述

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

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

相关文章

超酷!任务栏美化 给任务栏添加一个好看的时钟

如何给任务栏美化&#xff1f;今天我们这个主题就是帮大家美化任务栏&#xff0c;估计很多伙伴都用过任务栏美化工具。任务栏美化是非常有个性化的功能&#xff0c;不但可以让你的任务栏变得漂亮&#xff0c;还可以增加一些非常有创意的功能&#xff0c;比如今天小编要给大家带…

文件共享软件推荐,哪些工具最实用?

预计到2025年文档共享市场将增长至近100亿美金。文件共享软件助力跨区域协作&#xff0c;推荐ZohoWorkDrive、GoogleDrive、DropboxBusiness。软件设计直观&#xff0c;上手易&#xff0c;可保障数据安全&#xff0c;选择时需考虑企业规模、需求及预算。 一、什么是文件共享软件…

linux部署NFS和autofs自动挂载

目录 &#xff08;一&#xff09;NFS&#xff1a; 1. 什么是NFS 2. NFS守护进程 3. RPC服务 4. 原理 5. 部署 5.1 安装NFS服务 5.2 配置防火墙 5.3 创建服务端共享目录 5.4 修改服务端配置文件 (1). /etc/exports (2). nfs.conf 5.5 启动nfs并加入自启 5.6 客户端…

陀螺仪LSM6DSV16X与AI集成(14)----上报匿名上位机

陀螺仪LSM6DSV16X与AI集成.14--上报匿名上位机 概述视频教学样品申请源码下载硬件准备上位机通讯陀螺仪工作方式欧拉角数据的转换数据帧填充校验和计算数据发送演示开启INT中断中断读取传感器数据主程序演示 概述 本文介绍了如何将 LSM6DSV16X 传感器的姿态数据通过匿名通信协…

【Android】Handler消息机制

文章目录 前言概述核心组件概述Android消息机制概述 Android消息机制分析ThreadLocal的工作原理ThreadLocal基础ThreadLocal实现原理 MessageQueueLooperHandler的工作原理总结 前言 本文用于记录Android的消息机制&#xff0c;主要是指Handler的运行机制。部分内容参考自《An…

产品经理都会的ComfyUI搭建指南

最近准备参加一个ComfyUI的活动&#xff0c;发现还没有上手过ComfyUI&#xff0c;于是先部署起来。ComfyUI是一个基于Stable Diffusion开发的UI。比起WebUI表单式交互的简单&#xff0c;ComfyUI主打灵活&#xff0c;Diffusion Model管线中的各个模块如&#xff1a;VAE、Control…

DINOv2: Learning Robust Visual Featureswithout Supervision

Abstract 在自然语言处理方面的模型&#xff0c;可以产生通用视觉特征&#xff08;即无需微调即可跨图像分布和任务工作的特征&#xff09;来极大地简化任何系统中图像的使用。这些模型能够提取出一些可以在不同类型的图像和任务中通用的视觉特征。这意味着不管图像的来源&…

电脑断网或者经常断网怎么办?

1、首先&#xff0c;按一下键盘的win R &#xff0c; 在打开的运行框内输入&#xff1a;cmd 然后按一下回车 或者 点击一下【确定】 2、在命令窗口输入&#xff1a;ipconfig/release , 然后按一下回车 作用&#xff1a;IP释放&#xff0c;相当于把网线拔了重新插上 3、接着…

【D3.js in Action 3 精译_029】3.5 给 D3 条形图加注图表标签(上)

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第一部分 D3.js 基础知识 第一章 D3.js 简介&#xff08;已完结&#xff09; 1.1 何为 D3.js&#xff1f;1.2 D3 生态系统——入门须知1.3 数据可视化最佳实践&#xff08;上&#xff09;1.3 数据可…

C++11之线程

编译环境&#xff1a;Qt join&#xff1a;阻塞当前线程&#xff0c;直到线程函数退出 detach&#xff1a;将线程对象与线程函数分离&#xff0c;线程不依赖线程对象管理 注&#xff1a;join和detach两者必选其一&#xff0c;否则线程对象的回收会影响线程的回收&#xff0c;导致…

MATLAB下的RSSI定位程序,二维平面上的定位,基站数量可自适应

文章目录 引言程序概述程序代码运行结果待定位点、锚点、计算结果显示待定位点和计算结果坐标 引言 随着无线通信技术的发展&#xff0c;基于 R S S I RSSI RSSI&#xff08;接收信号强度指示&#xff09;的方法在定位系统中变得越来越流行。 R S S I RSSI RSSI定位技术特别适…

Vue 插槽全攻略:重塑组件灵活性

前言 &#x1f4eb; 大家好&#xff0c;我是南木元元&#xff0c;热爱技术和分享&#xff0c;欢迎大家交流&#xff0c;一起学习进步&#xff01; &#x1f345; 个人主页&#xff1a;南木元元 目录 什么是slot插槽 默认插槽 编译作用域 后备内容 具名插槽 作用域插槽 应…

医药行业的智能合同审查:大模型与AI赋能合规管理

随着医药行业的快速发展&#xff0c;尤其是在全球化背景下&#xff0c;企业在业务拓展、合作协议签订中需要处理大量复杂的合同。合同不仅是业务的法律保障&#xff0c;更是风险管理的重要工具。医药行业合同审查的复杂性源于其严格的合规性要求&#xff0c;包括与政府机构、研…

学会这几个简单的bat代码,轻松在朋友面前装一波13[通俗易懂]

大家好&#xff0c;又见面了&#xff0c;我是你们的朋友全栈君。 这个标题是干什么用的? 最近看晚上某些人耍cmd耍的十分开心&#xff0c;还自称为“黑客”&#xff0c;着实比较搞笑.他们那些花里胡哨的东西在外行看来十分nb,但只要略懂一些&#xff0c;就会发现他们的那些十…

数据库(MySQL):使用命令从零开始在Navicat创建一个数据库及其数据表(三),单表查询

前言 Navicat Premium 17 数据表需要经常清缓存&#xff0c;不然之前的自增的数据可能会一直存在&#xff0c;所以把之前的表删除重新创建是对练习数据库最简单的办法。新建数据库的命令如下&#xff1a; /* 创建有 自增主键的属性id&#xff0c;非空的属性name&#xff0c;唯…

如何使用ssm实现基于BS的超市商品管理系统的设计与实现+vue

TOC ssm787基于BS的超市商品管理系统的设计与实现vue 研究背景与现状 时代的进步使人们的生活实现了部分自动化&#xff0c;由最初的全手动办公已转向手动自动相结合的方式。比如各种办公系统、智能电子电器的出现&#xff0c;都为人们生活的享受提供帮助。采用新型的自动化…

TypeScript面向对象 02

抽象类 以abstract开头的类是抽象类。抽象类和其他类区别不大&#xff0c;只是不能用来创建对象。抽象类就是专门用来被继承的类。 抽象类中可以添加抽象方法。定义一个抽象方法使用abstract&#xff0c;没有方法体。抽象方法只能定义在抽象类中&#xff0c;子类必须对抽象方…

一些硬件知识(二十七)

单片机一般使用NOR FLASH &#xff0c;这是因为NOR FLASH支持字节级的随机读取&#xff0c;可以直接运行存贮其中的程序&#xff0c;NOR FLASH支持读取和执行存储其中的指令&#xff0c;而无需将程序拷贝到RAM中才可执行。NAND FLASH适用于大容量的数据存储&#xff0c;他的读写…

【Canvas与标志】灰座橙底红芯辐射标志

【成图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>灰座橙底红芯辐射标志</title><style type"text/css&q…

msvcp140.dll丢失的解决方法,详细解读6种解决方法

在使用电脑时&#xff0c;我们可能会遇到提示缺少msvcp140.dll的错误信息。这个提示意味着我们的电脑中缺少MSVCP140.dll这个文件&#xff0c;它是某些程序运行所必需的。如果我们遇到这个问题&#xff0c;应该如何解决呢&#xff1f;本文将详细解析如何解决msvcp140.dll丢失的…