转载

一直想找本书,能在机器学习复杂的算法原理和高效的编程实战之间达到合适的平衡:让感兴趣的同学拿到就有能用的代码,还有基本原理的介绍,因为了解原理才知道什么时候用什么算法最合适,以及如何调整参数。

一直没找到合适的,所以动手写了一本:p 拖拖拉拉花了三年多时间,幸运的是三年间技术一直在进步,也就有机会将最新的OpenCV4机器学习ML和深度学习DNN模块的精彩呈现在纸面,汇集了大量的算法原理与对应的示例程序,希望能对大家的学习有所帮助:)

本文的思路是:

先介绍涉及的知识体系和主要特色,并给出这本书的目录结构;
    再给出书中的三个案例,分别是DNN深度学习模型落地和SVM的在机器视觉中的应用;
    最后是书中内容的截图展示。

目录

内容介绍

全书目录

案例1:用C++ 和OpenCV 实现视频目标检测(YOLOv4)

1.实现思路

2.实现步骤

案例2:使用C++ 和OpenCV 实现场景文本检测识别(DB+CRNN)

1.实现思路

2.实现步骤

案例3:使用C++ 和OpenCV 实现手写数字识别(HOG+SVM)

应用提示

内容截图

内容介绍

机器学习关注的问题是:计算机程序如何随着经验积累自动提高性能。机器学习算法已成功应用于模式识别、通信、控制、金融、生物信息学、计算机视觉等众多领域。近年来,深度学习技术的进步,更是推动了计算机视觉领域的研究与行业应用的巨大变革。

目前介绍机器学习的书籍大致分为理论与实践两类,大多数应用类书籍使用Python或MATLAB语言编程实现。这本书的初衷是为读者拉近机器学习理论与算法C++编程实践之间的距离。OpenCV的机器学习与深度学习模块为我们在机器学习理论与编程实战之间架设了一座桥梁。读者通过阅读本书可在理解算法原理的基础上,通过大量应用与示例代码迅速提升基于C++语言的机器学习算法编程实践能力,书中的大量OpenCV函数用法、参数的介绍同样适用于Python接口调用。

本书以OpenCV4为工具,介绍的机器学习算法原理、代码实现与应用示例。第1章和第2章介绍了OpenCV4的安装配置、基本数据结构与图像处理操作;第3章讲解机器学习的基本概念;第4章从最简单的K均值和K近邻算法入手介绍聚类、分类与回归算法原理与应用;第5章至第7章介绍了最早的机器学习算法之一的决策树算法,及其改进算法——随机森林和Boosting集成学习算法;第8章介绍了应用广泛的支持向量机算法及应用,并涉及到一些基本的统计学习理论知识;第9章至第10章,重点介绍了人工神经网络与深度学习算法,并通过图像分类、对象检测、实例分割、目标跟踪与场景文本检测与识别等不同类型的大量应用介绍了GoogLeNet、YOLOv4、Mask R-CNN、GOTURN、DB、CRNN等深度学习算法模型的部署方法,其中不乏近年出现的高性能模型。

全书目录

第1章 概述
1.1 OpenCV简述
1.2 OpenCV的功能
1.3 OpenCV中的机器学习与深度神经网络模块
1.4 基本数据类型
1.4.1 数据类型概述
1.4.2 cv::Vec类
1.4.3 cv::Point类
1.4.4 cv::Scalar类
1.4.5 cv::Size类
1.4.6 cv::Rect类
1.4.7 cv::RotatedRect类
1.4.8 cv::Mat类
1.4.9 基本矩阵运算
参考文献

第2章 OpenCV在机器学习任务中的基本图像操作
2.1 基本图像操作
2.1.1 读取、显示和存储图像
2.1.2 颜色空间转换
2.1.3 图像的几何变换
2.1.4 直方图均衡化
2.1.5 标注文字和矩形框
2.2 基本视频操作
2.2.1 读取和播放视频文件
2.2.2 处理视频文件
2.2.3 存储视频文件
参考文献

第3章 机器学习的基本原理与OpenCV机器学习模块
3.1 机器学习的基本概念
3.1.1 机器学习的定义
3.1.2 机器学习的分类
3.2 机器学习的一般流程
3.2.1 机器学习流程
3.2.2 数据集
3.2.3 偏差与方差
3.2.4 评估分类器性能的方法
3.3 逻辑回归分类示例
3.3.1 图像数据与数据表示
3.3.2 逻辑回归模型
3.3.3 逻辑回归的损失函数
3.4 OpenCV支持的机器学习算法
3.4.1 机器学习模块的结构
3.4.2 机器学习模块中的算法
3.4.3 数据集准备
3.4.4 特征选择
参考文献

第4章 K-means和KNN
4.1 算法原理
4.1.1 K-means原理
4.1.2 KNN原理
4.2 OpenCV实现
4.2.1 K-means的实现
4.2.2 KNN的实现
4.3 应用示例
4.3.1 K-means聚类示例
4.3.2 KNN手写数字识别示例
4.3.3 应用提示
参考文献

第5章 决策树
5.1 决策树原理
5.1.1 决策树的基本思想
5.1.2 决策树的表示方法
5.1.3 最佳切分属性的选择
5.1.4 停止标准
5.1.5 剪枝
5.2 OpenCV实现
5.2.1 创建决策树
5.2.2 训练决策树
5.2.3 使用决策树预测
5.3 应用示例
5.3.1 蘑菇可食性分类
5.3.2 预测波士顿房价
5.3.3 应用提示
参考文献

第6章 随机森林
6.1 随机森林原理
6.1.1 随机森林的基本思想
6.1.2 Bagging算法
6.2 OpenCV实现
6.2.1 OpenCV中的随机森林
6.2.2 创建随机森林
6.2.3 训练随机森林
6.2.4 使用随机森林预测
6.3 应用示例
6.3.1 蘑菇可食性分类
6.3.2 预测波士顿房价
6.3.3 应用提示
参考文献

第7章 Boosting算法
7.1 Boosting算法原理
7.1.1 Boosting算法的基本思想
7.1.2 Boosting算法
7.1.3 AdaBoost算法
7.2 OpenCV实现
7.2.1 创建AdaBoost模型
7.2.2 训练AdaBoost模型
7.2.3 使用AdaBoost模型预测
7.3 应用示例
7.3.1 蘑菇可食性分类
7.3.2 英文字母分类问题
7.3.3 应用提示
参考文献

第8章 支持向量机
8.1 支持向量机原理
8.1.1 统计学习理论概述
8.1.2 线性SVM算法基本原理
8.1.3 非线性SVM算法的基本原理
8.1.4 SVM回归算法的基本原理
8.1.5 SVM算法执行SRM准则的解释
8.2 OpenCV实现
8.2.1 OpenCV中的SVM算法
8.2.2 创建SVM模型
8.2.3 训练SVM模型
8.2.4 使用SVM模型预测
8.3 应用示例
8.3.1 使用HOG特征与SVM算法识别手写数字
8.3.2 应用提示
参考文献

第9章 神经网络
9.1 神经网络算法原理
9.1.1 神经网络的结构与表示
9.1.2 单隐层前馈神经网络
9.1.3 多隐层前馈神经网络
9.1.4 梯度下降法
9.1.5 反向传播算法
9.2 OpenCV实现
9.2.1 OpenCV中的MLP算法
9.2.2 创建MLP模型
9.2.3 训练MLP模型
9.2.4 使用MLP模型预测
9.3 应用示例
9.3.1 使用神经网络识别手写数字
9.3.2 应用提示
参考文献

第10章 深度神经网络
10.1 卷积神经网络的基本原理
10.1.1 卷积神经网络的结构
10.1.2 卷积层
10.1.3 池化
10.1.4 Softmax层
10.1.5 CNN特征学习的过程
10.1.6 CNN特征学习的原理
10.2 OpenCV的DNN模块
10.2.1 OpenCV支持的深度学习框架
10.2.2 支持的层类型
10.2.3 编译支持GPU加速的OpenCV
10.2.4 DNN模块的使用
10.3 应用示例
10.3.1 典型计算机视觉任务
10.3.2 使用GoogLeNet实现图像分类
10.3.3 使用YOLOv4实现目标检测
10.3.4 使用Mask R-CNN实现实例分割
10.3.5 使用GOTURN模型实现目标跟踪
10.3.6 使用DB算法实现场景文本检测
10.3.7 使用CRNN实现场景文本识别
10.3.8 应用提示
参考文献

案例1:用C++ 和OpenCV 实现视频目标检测(YOLOv4)
1.实现思路

读取视频流,载入模型,执行推理,找出所有目标及其位置,最后绘制检测结果。
2.实现步骤

读取摄像头视频流或本地视频文件:

cv::VideoCapture cap;
    cap.open(0); //打开摄像头
    //cap.open("TH1.mp4"); //读取视频文件

载入模型:

cv::dnn::Net net = cv::dnn::readNet(config, model, framework);
    net.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA);

执行推理:

net.forward(outs, outNames); //前向传播

找出所有目标及其位置(部分):

for (size_t i = 0; i < outs.size(); ++i) {
         data = (float*)outs[i].data;
         for (int j = 0; j < outs[i].rows; ++j, data += outs[i].cols)
         {
             scores = outs[i].row(j).colRange(5, outs[i].cols);
             cv::minMaxLoc(scores, 0, &confidence, 0, &classIdPoint);

绘制检测结果(部分):

void drawPred(
        cv::Mat &frame,
        vector<cv::Rect> &boxes,
        vector<int> &classIds,
        vector<int> &indices,
        vector<string> &classNamesVec)

案例2:使用C++ 和OpenCV 实现场景文本检测识别(DB+CRNN)

将检测模型的文本区域检测结果输入识别模型后,便可以对场景图像中的文字进行检测识别了。示例代码10-7是在OpenCV官方场景文字检测识别示例代码基础上修改而来的。
1.实现思路

读取图像,初始化参数,载入模型,载入词典,场景文本提取,提取后文本识别,检测结果后处理。
2.实现步骤

初始化参数(部分):

//[1]初始化参数
        //DB文本检测模型
        cv::String detModelPath =
            "D:/models/TextRecognitionModel_google/DB_TD500_resnet50.onnx";
        float binThresh = 0.3;
        float polyThresh = 0.5;  
        double unclipRatio = 2.0;
        uint maxCandidates = 200;
        int height = 736;
        int width = 736;
        //CRNN文本识别模型
    cv::String recModelPath =
             "D:/models/TextRecognitionModel_google/crnn_cs_CN.onnx";
        cv::String vocPath =
             "D:/models/TextRecognitionModel_google/alphabet_3944.txt";
        int imreadRGB = 1;

载入模型:

//[2]载入模型
        cv::dnn::TextDetectionModel_DB detector(detModelPath);
        detector.setBinaryThreshold(binThresh)
            .setPolygonThreshold(polyThresh)
            .setUnclipRatio(unclipRatio)
            .setMaxCandidates(maxCandidates);

载入词典(部分):

//[3]载入词典
        CV_Assert(!vocPath.empty());
        std::ifstream vocFile;
        vocFile.open(samples::findFile(vocPath));
        CV_Assert(vocFile.is_open());
        cv::String vocLine;
        std::vector<String> vocabulary;
        while (std::getline(vocFile, vocLine)) {
            vocabulary.push_back(vocLine);
        }

模型推理(部分):

//[4]推理
          cv::Mat frame = imread(samples::findFile(imgPath), imreadRGB);
          CV_Assert(!frame.empty());
          std::string recognitionResult = recognizer.recognize(frame);
          cv::imshow("evaluate image", frame);

载入图像:

//[5]载入图像
        cv::Mat frame = cv::imread("acmilan.jpg");
        std::cout << frame.size << std::endl;

模型推理:

//[6]推理
        std::vector< std::vector<cv::Point> > detResults;
        detector.detect(frame, detResults);

检测结果后处理(部分):

std::vector< std::vector<Point> > contours;
            for (uint i = 0; i < detResults.size(); i++)
            {
                const auto& quadrangle = detResults[i];
                CV_CheckEQ(quadrangle.size(), (size_t)4, "");
                contours.emplace_back(quadrangle);
                std::vector<Point2f> quadrangle_2f;
                for (int j = 0; j < 4; j++)
                    quadrangle_2f.emplace_back(quadrangle[j]);

图10-59是示例代码10-7综合了DB文本检测与CRNN文本识别模型后的识别结果。图10-59中左上角的小图为文本区域仿射变换后的切片图像,将其作为CRNN识别模型的输入,识别结果自动显示在大图中文本区域的右侧。

案例3:使用C++ 和OpenCV 实现手写数字识别(HOG+SVM)

特征描述子是图像或图像块的某种表示,通过提取有用的信息并丢弃多余的信息来简化图像。在识别任务中,我们会使用某种特征描述子,先从原始图像中提取出特征,构成描述该图像的特征向量x^((i)),再使用分类算法对图像进行分类。在本例中,我们使用梯度直方图(Histogram of Oriented Gradients,HOG)特征描述子将灰度图像转换为特征向量。

在了解了类的关键构造参数后,首先,创建HOGDescriptor类的一个实例hog,根据手写数字图像大小来初始化实例hog的参数:

HOGDescriptor hog(
        Size(20, 20), //winSize
        Size(10, 10), //blocksize
        Size(5, 5), //blockStride
        Size(10, 10), //cellSize
        9, //nBins
        1, //derivAper
        -1, //winSigma
        0, //histogramNormType
        0.2, //L2HysThresh
        1,//gammal correction
        64,//nlevels=64
        1);//Use signed gradients

然后,调用HOGDescriptor类的compute方法计算HOG特征,得到特征描述子descriptors:

vector<float> descriptors;
        hog.compute(img, descriptors);

接着,将特征描述子descriptors转换成OpenCV的Mat数据类型,并存入训练样本集:

vector<Mat> trainDataVec
    trainDataVec.push_back(Mat(descriptors).clone());

最后,使用convert_to_ml函数将vector<cv::Mat>类型的样本特征向量集转成OpenCV机器学习算法要求的训练数据集格式:

void convert_to_ml(const vector<Mat> & train_samples, Mat& trainData)
    {
        //--Convert data
        const int rows = (int)train_samples.size();
        const int cols = (int)std::max(train_samples[0].cols,
                             train_samples[0].rows);
        Mat tmp(1, cols, CV_32FC1);
        trainData = Mat(rows, cols, CV_32FC1);
        for (size_t i = 0; i < train_samples.size(); ++i)
        {
            CV_Assert(train_samples[i].cols == 1 || train_samples[i].rows == 1);
            if (train_samples[i].cols == 1)
            {
                transpose(train_samples[i], tmp);
                tmp.copyTo(trainData.row((int)i));
            }
            else if (train_samples[i].rows == 1)
            {
                train_samples[i].copyTo(trainData.row((int)i));
            }
        }
    }

前文介绍了如何计算每幅图像的HOG特征,并将其组成训练样本。下面编写函数generateDataSet,完成整个数据集的制作:

/** @生成模型的训练集与测试集
    参数1:img,输入,灰度图像,由固定尺寸的小图像拼接成的大图,不同类别的小图像依次排列
    参数2:trainDataVec,输出,训练集维度为训练样本数×单个样本特征数,CV_32F类型
    参数3:testDataVec,输出,测试集维度为测试样本数×单个样本特征数,CV_32F类型
    参数4:trainLabel,输出,训练集标签维度为训练样本数×1,int型向量
    参数4:testLabel ,输出,测试集标签维度为测试样本数×1,int型向量
    参数5:train_rows,输入,用于训练的样本所占的行数,默认4行用于训练,1行用于测试
    参数6:HOG_flag,输入。true:提取HOG特征描述子作为特征向量。false:直接使用图像原始像素
    */
    void generateDataSet(Mat &img, vector<Mat> &trainDataVec, vector<Mat> &testDataVec, vector<int> &trainLabel, vector<int> &testLabel, int train_rows, bool HOG_flag)
    {
        //初始化图像中切片图像与其他参数
        int width_slice = 20;  //单个数字切片图像的宽度
        int height_slice = 20; //单个数字切片图像的高度
        int row_sample = 100;  //每行样本数
        int col_sample = 50;   //每列样本数
        int row_single_number = 5; //单个数字占5行
        int test_rows = row_single_number - train_rows; //测试样本所占行数
        Mat trainMat(train_rows * 20 * 10, img.cols, CV_8UC1);
        //存放所有训练图片
        trainMat = Scalar::all(0);
        Mat testMat(test_rows * 20 * 10, img.cols, CV_8UC1);  
        //存放所有测试图片
        testMat = Scalar::all(0);
     
        //生成测试大图和训练大图
        for (int i = 1; i <= 10; i++)
        {
            Mat tempTrainMat = img.rowRange((i - 1) * row_single_number * 20, (i *
                row_single_number - 1) * 20).clone();
            Mat tempTestMat = img.rowRange((i * row_single_number - 1) * 20, (i *
                row_single_number) * 20).clone();
            //train
            cv::Mat roi_train = trainMat(Rect(0, (i - 1) * train_rows * 20,
     tempTrainMat.cols, tempTrainMat.rows));
            Mat mask_train(roi_train.rows, roi_train.cols, roi_train.depth(),
                Scalar(1));
            //test
            cv::Mat roi_test = testMat(Rect(0, (i - 1) * test_rows * 20,
                 tempTestMat.cols, tempTestMat.rows));
            Mat mask_test(roi_test.rows, roi_test.cols, roi_test.depth(),
                 Scalar(1));
            //把提取的训练测试行分别复制到训练图片与测试图片中
            tempTrainMat.copyTo(roi_train, mask_train);
            tempTestMat.copyTo(roi_test, mask_test);
        }

表8-3为不同的特征与SVM核函数在手写数字数据集上的测试结果。表中“特征”栏“原图”指的是将20像素×20像素的原始图像直接拉成400×1的向量作为特征向量;“HOG”为算法从每幅图中抽取的81×1维的HOG特征向量。从测试结果可以看出,使用偏斜校正后的图像训练的分类器,准确率要好于使用原始图像的分类器。当然,如果使用偏斜校正后的图像来训练分类器,那么测试样本也需要经偏斜校正后再送入分类器进行分类。

应用提示

SVM的类型非常多。针对线性可分数据,可以使用软间隔SVM;针对非线性可分数据,可以使用引入核技巧的非线性SVM;针对回归任务可以使用SVR。在具体使用时有两个重要的问题,一是模型选择问题(即参数搜索),二是特征提取问题。
例如,当使用高斯核函数的C-SVM时,主要参数为C和γ,那么如何选择呢?最好的方法是使用“网格搜索”寻找不同的参数组合,之后进行交叉验证,找出使交叉验证精度最高的参数组合(C,γ)。OpenCV提供的trainAuto函数可以测试不同的参数网格,通过k折叠交叉验证自动完成参数寻优。

此外,可以通过控制SV的数量对模型进行选择。下面用留一交叉验证(Leave-One-Out Cross Validation,LOOCV)的方法进行简要说明。LOOCV是指每次只留1个样本作为交叉验证集,剩下的m-1个样本作为训练集。由此可见,LOOCV本质是m折交叉验证(样本集被平分为m份,每份1个样本)。用E_loocv表示留一交叉验证误差,它比k折叠(k<m)交叉验证误差更能反映模型的真实泛化能力,因为每一次几乎所有的样本都用来训练,训练样本非常接近原始集合,再对m次误差求平均得到E_loocv,这样得到的泛化能力更为可靠。可以证明在SVM算法中,E_loocv nSV/m,即E_loocv与支持向量的数量nSV占总样本数m的比例有关,因此可以通过控制nSV对模型进行选择(不同nSV对应不同的模型)。具体做法为先控制SV的数量到合适的值,例如,ν-SVM算法的参数ν可以控制nSV占总样本比例的下限。nSV通常用来排除过拟合风险较大的模型,如果做完SVM训练发现nSV太大,则可马上知道该模型的误差上限较大,模型可能不太好。在排除过拟合风险的模型后,再进一步对其他参数进行网格搜索,从而找到一个最佳组合。

-----------------------------------------------------------------------------------------------------------

更多内容后续逐步更新,大家也可使用原书(含全套源码)学习参考。

内容截图

决策树算法的原理(部分)

决策树算法的原理(部分)

决策树算法的原理(部分)

OpenCV对算法的实现

应用示例

示例源码及分析

应用提示

本文更新链接:https://blog.csdn.net/iracer/article/details/116051674

转载请注明出处。
————————————————
版权声明:本文为CSDN博主「iracer」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/iracer/article/details/116051674

OpenCV4 视频目标检测 场景文本检测 手写数字识别 案例相关推荐

  1. 机器学习算法 08 —— 支持向量机SVM算法(核函数、手写数字识别案例)

    文章目录 系列文章 支持向量机SVM算法 1 SVM算法简介 1.1 引入 1.2 算法定义 2 SVM算法原理 2.1 线性可分支持向量机 2.2 SVM计算过程与算法步骤(有点难,我也没理解透,建 ...

  2. 手写数字识别案例、手写数字图片处理

    python_手写数字识别案例.手写数字图片处理 1.手写数字识别案例 步骤: 收集数据 带有标签的训练数据集来源于trainingDigits文件夹里面所有的文件,接近2000个文件,每个文件中有3 ...

  3. 深度学习-Pytorch:项目标准流程【构建、保存、加载神经网络模型;数据集构建器Dataset、数据加载器DataLoader(线性回归案例、手写数字识别案例)】

    1.拿到文本,分词,清晰数据(去掉停用词语): 2.建立word2index.index2word表 3.准备好预训练好的word embedding 4.做好DataSet / Dataloader ...

  4. MindSpore手写数字识别初体验,深度学习也没那么神秘嘛

    摘要:想了解深度学习却又无从下手,不如从手写数字识别模型训练开始吧! 深度学习作为机器学习分支之一,应用日益广泛.语音识别.自动机器翻译.即时视觉翻译.刷脸支付.人脸考勤--不知不觉,深度学习已经渗入 ...

  5. 基于深度学习的手写数字识别Matlab实现

    基于深度学习的手写数字识别Matlab实现 1.网络设计 2. 训练方法 3.实验结果 4.实验结果分析 5.结论 1.网络设计 1.1 CNN(特征提取网络+分类网络) 随着深度学习的迅猛发展,其应 ...

  6. 基于深度学习的手写数字识别算法Python实现

    摘 要 深度学习是传统机器学习下的一个分支,得益于近些年来计算机硬件计算能力质的飞跃,使得深度学习成为了当下热门之一.手写数字识别更是深度学习入门的经典案例,学习和理解其背后的原理对于深度学习的理解有 ...

  7. 教程 | 基于LSTM实现手写数字识别

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 基于tensorflow,如何实现一个简单的循环神经网络,完成手写 ...

  8. k-近邻算法实现手写数字识别系统

    k-近邻算法实现手写数字识别系统 一.实验介绍 1.1 实验内容 本实验将会从电影题材分类的例子入手,详细讲述k-近邻算法的原理.在这之后,我们将会使用该算法实现手写数字识别系统. 1.2 课程来源 ...

  9. Python实现基于机器学习的手写数字识别系统

    目 录 摘要 I ABSTRACT II 1 绪论 1 1.1 数字识别研究现状 1 1.2 深度学习的发展与现状 1 1.3 研究意义 2 1.4 论文结构 3 2 卷积神经网络基本原理 4 2.1 ...

  10. 1.3.1 手写数字识别之数据处理

    文章目录 概述 一.加载类库 二.读入数据并划分数据集 扩展阅读:为什么针对固定数据集的模型总在不断精进呢? 三.训练样本乱序.生成批次数据 四.校验数据有效性 机器校验 人工校验 五.封装数据读取与 ...

最新文章

  1. Android 轮播Banner 实现 附代码
  2. 【例题收藏】◇例题·6◇ 电压机制(voltage)
  3. 注入游戏没有焦点_《热血传奇怀旧版》即将登陆咪咕快游 盛趣游戏端游上云再落一子...
  4. Android ViewRoot、DecorViewWindow浅析
  5. java的add方法的使用_Java HashSet add()方法与示例
  6. 在InstallShield中发布单一的Setup.exe文件
  7. gcc/g++ 静态动态库 混链接.
  8. vue中如何实现pdf文件预览?
  9. 回溯算法高效解标准数独(MarkDown)
  10. ROS中gazebo工具学习(使用gazebo加载机器人模型)
  11. 食品生产设备用什么清洗消毒效果比较好?
  12. 01 电阻的简介及常见电路分析
  13. 0 – 30 V稳压电源电路
  14. 设计模式之简单工厂模式与策略模式
  15. js 解析多层json字符串
  16. 启动mongodb数据库服务
  17. 计算机专业英语博士就业情况,英语专业博士就业前景
  18. 如何下载原生纯净的Windows系统?(MSDN)
  19. mp4分离h265_音视频封装:MP4结构概述和分析工具
  20. 区块链技术与应用(赵其刚等)课后题答案

热门文章

  1. html插入图片向下,HTML基础8--插入图片及嵌入
  2. arcmap裁剪后的tif保存_在arcgis下如何进行影像图裁剪
  3. oracle按顺序新增字段,Oracle 修改字段顺序的两种方法
  4. 树莓派制作游戏机教程
  5. Windows下打开.jar文件的方式
  6. 中国象棋-单机游戏-微信小程序的项目开发流程详解
  7. 微信文件夹的dat文件怎么打开_微信文件夹里的照片文件是DAT格式怎么才能打开?...
  8. Ubuntu20.04代理设置
  9. 自学Python+Selenium自动化测试
  10. 决定一台计算机运行速度快慢的配件是什么,电脑运行慢换什么配件