Opencv-C++笔记 (17) : 模板匹配

文章目录

  • 1--概念
  • 2-- 方法
  • 3 结果
    • 3.1 ROI区域的获取使用
      • 自适应目标匹配

1–概念

opencv 提供了一个专门用于模板匹配的函数 cv::matchTemplate();其调用方式如下:

void cv::matchTemplate(
 
    cv::InputArray image, // 用于搜索的输入图像, 8U 或 32F, 大小 W-H
 
    cv::InputArray templ, // 用于匹配的模板,和image类型相同, 大小 w-h
 
    cv::OutputArray result, // 匹配结果图像, 类型 32F, 大小 (W-w+1)-(H-h+1)
 
    int method // 用于比较的方法   );

2-- 方法

在这里插入图片描述

3 结果

模板匹配函数cv::MatchTemplate一次计算模板与待测图像的相似度,并将结果存入映 图像result中,也就是result图像中的每一个点的值代表一次相似度比较结果;其中,模
通过在待检测的图像上从左到右,从上到下滑动,每到达一个像素点,就会以这个像素点
左上角顶点从原图像中截取一个与模板大小一样的图像进行像素比较的运算,模板在滑动
过程中,将模板和当前截取的图像的比较计算结果储存在result矩阵中,result的大小为(W
w+1,H-h+1),在result中的每个位置(x,y)的值都表示以这个点为左上角顶点截取的图像
模板像素计算后的计算结果;模板在待测图像上每次在横向或者纵向上每次移动一个像素点
然后进行一次比较,所以横向比较W-w+1次,纵向比较H-h+1次,最终得到一个(W w+1)x(H-h+1)的result矩阵;

3.1 ROI区域的获取使用

cv::MinMaxLoc(result,&min_val,&max_val,&min_loco,&max_loc,NULL);从result中提取最大值(相似度最高)以及最大值的位置(即在result中该最大值max_val的坐标位置max_loc,即模板滑行时左上角的坐标,类似于图中的坐标(x,y);

 由此得到rect=cvRect(max_loc.x,max_loc.y,tmp->width,tmp->height);
    其中rect表示最佳的匹配的矩形区域;
    minVal参数表示返回的最小值,如果不需要,则使用NULL。
    maxVal参数表示返回的最大值,如果不需要,则使用NULL。
    minLoc参数表示返回的最小位置的指针(在2D情况下); 如果不需要,则使用NULL。
    maxLoc参数表示返回的最大位置的指针(在2D情况下); 如果不需要,则使用NULL

3.2、 代码实现

单目标匹配

#include <opencv2/opencv.hpp>
#include <iostream>
#include <stdio.h>
 
using namespace std;
using namespace cv;
 
int main()
{
    Mat img, templ, result;      //img为待测图 templ是目标图片  result是结构图
    img = imread("../1.jpg");
    templ = imread("../2.jpg");
 
    //1.构建结果图像resultImg(注意大小和类型)
    //如果原图(待搜索图像)尺寸为W x H, 而模版尺寸为 w x h, 则结果图像尺寸一定是(W-w+1)x(H-h+1)
    //结果图像必须为单通道32位浮点型图像
    int result_cols = img.cols - templ.cols + 1;       //result的尺寸大小
    int result_rows = img.rows - templ.rows + 1;
    result.create(result_cols, result_rows, CV_32FC1);
 
    //2.模版匹配
    //这里我们使用的匹配算法是标准平方差匹配 method=CV_TM_SQDIFF_NORMED,数值越小匹配度越好
    matchTemplate(img, templ, result, CV_TM_SQDIFF_NORMED);
    //3.正则化(归一化到0-1)
    normalize(result, result, 0, 1, NORM_MINMAX, -1, Mat());
 
    //4.找出resultImg中的最大值及其位置
    double minVal = -1;
    double maxVal;
    Point minLoc;
    Point maxLoc;
    Point matchLoc;
    cout << "匹配度:" << minVal << endl;
    // 定位极值的函数
    minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc, Mat());
    cout << "匹配度:" << minVal << endl;
    cout << "minPosition: " << minLoc << endl;
    cout << "maxPosition: " << maxLoc << endl;
 
    matchLoc = minLoc;     
    //5.根据resultImg中的最大值位置在源图上画出矩形和中心点
    Point center = Point(minLoc.x + templ.cols / 2, minLoc.y + templ.rows / 2);
    rectangle(img, matchLoc, Point(matchLoc.x + templ.cols, matchLoc.y + templ.rows), Scalar(0, 255, 0), 2, 8, 0);
    circle(img, center, 2, Scalar(255, 0, 0), 2);
 
    imshow("img", img);
    imshow("template", templ);
    waitKey(0);
 
    return 0;
}

在这里插入图片描述
实时单目标识别

#include "opencv2/opencv.hpp"
#include <iostream>
using namespace std;
using namespace cv;
 
int main()
{
    //1.定义VideoCapture类对象video,打开摄像头
    VideoCapture video(0);
    //1.1.判断是否打开
    if (!video.isOpened())
    {
        cout << "video open error!" << endl;
        return 0;
    }
    //2.循环读取视频的每一帧,对每一帧进行模版匹配
    while (1)
    {
        //2.1.读取帧
        Mat frame;
        video >> frame;
        //2.2.对帧进行异常检测
        if (frame.empty())
        {
            cout << "frame empty" << endl;
            break;
        }
        //2.3.对帧进行模版匹配
        Mat tempImg = imread("../1.jpg", CV_LOAD_IMAGE_COLOR);
        cout << "Size of template: " << tempImg.size() << endl;
        //2.3.1.构建结果图像resultImg(注意大小和类型)
        //如果原图(待搜索图像)尺寸为W x H, 而模版尺寸为 w x h, 则结果图像尺寸一定是(W-w+1)x(H-h+1)
        //结果图像必须为单通道32位浮点型图像
        int width = frame.cols - tempImg.cols + 1;
        int height = frame.rows - tempImg.rows + 1;
        Mat resultImg(Size(width, height), CV_32FC1);
        //2.3.2.模版匹配
        matchTemplate(frame, tempImg, resultImg, CV_TM_CCOEFF_NORMED);
        imshow("result", resultImg);
        //2.3.3.正则化(归一化到0-1)
        normalize(resultImg, resultImg, 0, 1, NORM_MINMAX, -1);
        //2.3.4.找出resultImg中的最大值及其位置
        double minValue = 0;
        double maxValue = 0;
        Point minPosition;
        Point maxPosition;
        minMaxLoc(resultImg, &minValue, &maxValue, &minPosition, &maxPosition);
        cout << "minValue: " << minValue << endl;
        cout << "maxValue: " << maxValue << endl;
        cout << "minPosition: " << minPosition << endl;
        cout << "maxPosition: " << maxPosition << endl;
        //2.3.5.根据resultImg中的最大值位置在源图上画出矩形
        rectangle(frame, maxPosition, Point(maxPosition.x + tempImg.cols, maxPosition.y + tempImg.rows), Scalar(0, 255, 0), 1, 8);
        imshow("srcImg", frame);
        imshow("template", tempImg);
        if (waitKey(10) == 27)
        {
            cout << "ESC退出" << endl;
            break;
        };
    }
    return 0;
}

多目标模板匹配

#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
 
using namespace std;
using namespace cv;
 
Point getNextMinLoc(Mat &result, Point minLoc, int maxValue, int templatW, int templatH);
 
int main()
{
    Mat src = imread("../1.jpg");
    Mat srcCopy = src.clone();
 
    Mat temp = imread("../2.jpg");
    Mat result;
 
    if (src.empty() || temp.empty())
    {
        cout << "打开图片失败" << endl;
        return 0;
    }
 
    vector<Mat> templat;
    vector<float> minV;
    vector<Point> minL;
 
    int srcW, srcH, templatW, templatH, resultH, resultW;
    srcW = src.cols;
    srcH = src.rows;
    templat.push_back(temp);
    double minValue, maxValue;
    Point minLoc, maxLoc;
 
    for (int i=0;i<10;i++)
    {
        cout << i << ": ";
        templatW = templat[i].cols;
        templatH = templat[i].rows;
 
        if (srcW < templatW || srcH < templatH)
        {
            cout << "模板不能比原图大" << endl;
            return 0;
        }
 
        resultW = srcW - templatW + 1;
        resultH = srcH - templatH + 1;
 
        result.create(Size(resultW, resultH), CV_32FC1);
        matchTemplate(src, templat[i], result, CV_TM_SQDIFF_NORMED);
 
        minMaxLoc(result, &minValue, &maxValue, &minLoc, &maxLoc);
 
        cout << "min1: " << minValue << endl;
        if (minValue<=0.070055)
        {
            rectangle(srcCopy, minLoc, Point(minLoc.x + templatW, minLoc.y + templatH), Scalar(0, 0, 255), 2, 8, 0);
 
            Point new_minLoc;
            new_minLoc = getNextMinLoc(result, minLoc, maxValue, templatW, templatH);
 
            float *data = result.ptr<float>(new_minLoc.y);
 
            cout << "min2: " << data[new_minLoc.x] << " ";
            if (data[new_minLoc.x]<=0.5)
            {
                cout << "进这个函数了:" << i << ":" << new_minLoc.x;
                cout << " " << new_minLoc.y;
                rectangle(srcCopy, new_minLoc, Point(new_minLoc.x + templatW, new_minLoc.y + templatH),
                          Scalar(0, 255, 0), 2, 8, 0);
                new_minLoc = getNextMinLoc(result, new_minLoc, maxValue, templatW, templatH);
            }
 
            float *data1 = result.ptr<float>(new_minLoc.y);
            cout << "min3: " << data1[new_minLoc.x] << " " << endl;
            if (data1[new_minLoc.x] <= 0.4)
            {
 
                rectangle(srcCopy, new_minLoc, Point(new_minLoc.x + templatW, new_minLoc.y + templatH),
                          Scalar(255, 0, 0), 2, 8, 0);
            }
        }
        cout << "#" << endl;
        Mat temp_templat;
        resize(templat[i], temp_templat, Size(templat[i].cols / 1.1, templat[i].rows / 1.1));
        templat.push_back(temp_templat);
    }
 
    imshow("结果", srcCopy);
    waitKey(0);
    return 0;
}
 
Point getNextMinLoc(Mat &result, Point minLoc, int maxValue, int templatW, int templatH)
{
    //imshow("result", result);
    //cout << "maxvalue: " << maxValue << endl;
    int startX = minLoc.x - templatW / 3;
    int startY = minLoc.y - templatH / 3;
    int endX = minLoc.x + templatW / 3;
    int endY = minLoc.y + templatH / 3;
    if (startX < 0 || startY < 0)
    {
        startX = 0;
        startY = 0;
    }
    if (endX > result.cols - 1 || endY > result.rows - 1)
    {
        endX = result.cols - 1;
        endY = result.rows - 1;
    }
    int y, x;
    for (y = startY; y < endY; y++)
    {
        for (x = startX; x < endX; x++)
        {
            float *data = result.ptr<float>(y);
 
            data[x] = maxValue;
        }
    }
    double new_minValue, new_maxValue;
    Point new_minLoc, new_maxLoc;
    minMaxLoc(result, &new_minValue, &new_maxValue, &new_minLoc, &new_maxLoc);
    //imshow("result_end", result);
    return new_minLoc;
}

在这里插入图片描述

通过得到的结果我们发现我们的模板匹配好像匹配区域与模板的尺寸是一致的,由此很容易产生误差,或是得到并不理想的区域,而在实际生活中,由于待测图像与摄像头之间的距离的变换,模板的大小因素的影响,若是想要得到较好的匹配结果,则需要我们实现自适应尺寸的模板匹配;

由此,我们开始进行自适应尺寸的模板匹配,载入的模板图像,另其进入循环,每次循环缩放一定的比例,在进行模板匹配,最终我们得到了不同比例下的ROI区域,对所有的ROI区域与我们的模板图片进行相似度的比较,选出相似度最高的匹配图像,同时获得最佳的匹配比例;

自适应目标匹配

代码流程:

    1,载入待测图像与模板;

    2,将模板图像等比例放大或缩小

    3,没改变一次进行一次模板匹配

    4,得到匹配区域的图片

    5,将得到的ROI图片与原始模板进行相似性比较

    6,筛选出相似性最好的ROI区域

    7,在待测图片上进行框选

    8,输出图片
#include <opencv2/opencv.hpp>
#include <iostream>
#include <stdio.h>
 
using namespace std;
using namespace cv;
 
int pHash(Mat matSrc1, Mat matSrc2)
//int main()
{
    Mat matDst1, matDst2;
 
//    Mat matSrc1 = imread("../1.jpg");
//    Mat matSrc2 = imread("../3.jpg");
 
    cv::resize(matSrc1, matDst1, cv::Size(32, 32), 0, 0, cv::INTER_CUBIC);
    cv::resize(matSrc2, matDst2, cv::Size(32, 32), 0, 0, cv::INTER_CUBIC);
 
    cv::cvtColor(matDst1, matDst1, CV_BGR2GRAY);
    cv::cvtColor(matDst2, matDst2, CV_BGR2GRAY);
 
    matDst1.convertTo(matDst1, CV_32F);
    matDst2.convertTo(matDst2, CV_32F);
    dct(matDst1, matDst1);
    dct(matDst2, matDst2);
 
    int iAvg1 = 0, iAvg2 = 0;
    int arr1[64], arr2[64];
 
    for (int i = 0; i < 8; i++)
    {
        uchar* data1 = matDst1.ptr<uchar>(i);
        uchar* data2 = matDst2.ptr<uchar>(i);
 
        int tmp = i * 8;
 
        for (int j = 0; j < 8; j++)
        {
            int tmp1 = tmp + j;
 
            arr1[tmp1] = data1[j];
            arr2[tmp1] = data2[j];
 
            iAvg1 += arr1[tmp1];
            iAvg2 += arr2[tmp1];
        }
    }
 
    iAvg1 /= 64;
    iAvg2 /= 64;
 
    for (int i = 0; i < 64; i++)
    {
        arr1[i] = (arr1[i] >= iAvg1) ? 1 : 0;
        arr2[i] = (arr2[i] >= iAvg2) ? 1 : 0;
    }
 
    int iDiffNum = 0;
 
    for (int i = 0; i < 64; i++)
        if (arr1[i] != arr2[i])
            ++iDiffNum;
//    cout<<iDiffNum<<endl;
    return iDiffNum;
}
 
//int main()
//{
//    Mat img,templ,result;
//    img = imread("../1.jpg");
//    templ = imread("../2.jpg");
//
//    int result_cols = img.cols - templ.cols + 1;
//    int result_rows = img.rows - templ.rows + 1;
//
//    result.create(result_cols,result_rows,CV_32FC1);
//    matchTemplate(img, templ, result, CV_TM_SQDIFF_NORMED);
//
//    Point minLoc;
//    Point maxLoc;
//    double minVal = -1;
//    double maxVal;
//
//    minMaxLoc(result,&minVal,&maxVal,&minLoc,&maxLoc,Mat());
//    cout<<"minLoc.x:"<<minLoc.x<<endl;
//    cout<<"minLoc.y:"<<minLoc.y<<endl;
//    cout<<"result_cols:"<<result_cols<<endl;
//
//    int ROI_rows =templ.rows - 0.05*templ.rows;
//    int ROI_cols =templ.cols - 0.05 *templ.cols;
//
//    Rect img_ROI = Rect(minLoc.x, minLoc.y,ROI_rows,ROI_cols);
//
//    Mat ROI = img(img_ROI);
//    pHash(ROI,templ);
//
//}
 
int main()
{
    //加载图片
    Mat src_img,temp_img,result_img;
    src_img = imread("../1.jpg");
    temp_img = imread("../2.jpg");
 
    imshow("src_img",src_img);
    imshow("temp_img",temp_img);
 
    //构建结果图像,结果图像必须是单通道32位浮点型图像
    int result_cols = src_img.cols - temp_img.cols + 1;       //result的尺寸大小
    int result_rows = src_img.rows - temp_img.rows + 1;
    result_img.create(result_cols, result_rows, CV_32FC1);
 
    int n = 0;
 
    //循环缩放模板图片
    for(int i = 0; i <10; i++)
    {
        cout<<i<<endl;
        Mat temp_imgc = temp_img.clone();
        int temp_imgc_col = temp_img.cols - i * 0.05 * temp_img.cols;
        int temp_imgc_row = temp_img.rows - i * 0.05 * temp_img.rows;
        resize(temp_imgc,temp_imgc,Size(temp_imgc_col,temp_imgc_row));
 
        //进行模板匹配
        matchTemplate(src_img,temp_imgc,result_img,0);
 
        double minVal = -1;
        double maxVal;
        Point minLoc;
        Point maxLoc;
        Point matchLoc;
        minMaxLoc(result_img, &minVal, &maxVal, &minLoc, &maxLoc, Mat());
 
        Rect ROI = Rect(minLoc.x,minLoc.y,temp_imgc_row,temp_imgc_col);
 
        Mat img_show = src_img.clone();
        matchLoc = minLoc;
        //5.根据resultImg中的最大值位置在源图上画出矩形和中心点
        Point center = Point(minLoc.x + temp_imgc.cols / 2, minLoc.y + temp_imgc.rows / 2);
        rectangle(img_show, matchLoc, Point(matchLoc.x + temp_imgc.cols, matchLoc.y + temp_imgc.rows), Scalar(0, 255, 0), 1, 8, 0);
 
//        imshow("result",img_show);
//        waitKey(0);
 
        //获取匹配得到区域
        Rect img_ROI = Rect(matchLoc,Point(matchLoc.x + temp_imgc.cols, matchLoc.y + temp_imgc.rows));
        Mat img = src_img.clone();
        Mat ROI_img = img(img_ROI);
 
//        imshow("ROI",ROI_img);
//        waitKey(0);
 
        //进行相似度比较
        if(pHash(ROI_img,temp_img) < 20)
        {
            n = pHash(ROI_img,temp_img);
            cout<<"n="<<n<<endl;
            imshow("zhy", img_show);
            waitKey(0);
        }
        
//        //获取模板匹配得到的区域
//        double minVal;
//        double maxVal;
//        Point minLoc;
//        Point maxLoc;
//        minMaxLoc(result_img,&minVal,&maxVal,&minLoc,&maxLoc,Mat());  //找矩阵中最小位置点的坐标
//        //画出ROI区域的矩形框
//        Rect ROI = Rect(minLoc.x,minLoc.y,temp_imgc_row,temp_imgc_col);
//
//        Mat result_img_ROI = result_img(ROI);
//        cout<<i<<endl;
//        imshow("show",result_img_ROI);
//        waitKey(0);
    }
}

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LabVIEW使用图像处理进行交通控制性能分析

LabVIEW使用图像处理进行交通控制性能分析 采用普雷维特、拉普拉斯、索贝尔和任意的空间域方法对存储的图像进行边缘检测&#xff0c;并获取实时图像。然而&#xff0c;对四种不同空间域边缘检测方法的核的性能分析。 以前&#xff0c;空路图像存储在数据库中&#xff0c;道路…

drawio----输出pdf为图片大小无空白(图片插入论文)

自己在写论文插入图片时为了让论文图片放大不模糊&#xff0c;啥方法都试了&#xff0c;最后摸索出来这个。 自己手动画图的时候导出pdf总会出现自己的图片很小&#xff0c;pdf的白边很大如下如所示&#xff0c;插入论文的时候后虽然放大不会模糊&#xff0c;但是白边很大会显…

看完《孤注一掷》:原来这类人最容易被电信诈骗!

最近&#xff0c;你看了诈骗电影《孤注一掷》吗&#xff1f; “想成功先发疯&#xff0c;不顾一切向钱冲&#xff1b;拼一次富三代&#xff0c;拼命才能不失败&#xff1b;今天睡地板&#xff0c;明天当老板&#xff01;”诈骗工厂里的被骗去打黑工的人们一次次高呼着朗朗上口…

HTTPS 的加密流程

目录 一、HTTPS是什么&#xff1f; 二、为什么要加密 三、"加密" 是什么 四、HTTPS 的工作过程 1.对称加密 2.非对称加密 3.中间人攻击 4.证书 总结 一、HTTPS是什么&#xff1f; HTTPS (Hyper Text Transfer Protocol Secure) 是基于 HTTP 协议之上的安全协议&…

c语言——拷贝数组

这段代码是一个简单的数组拷贝示例。它的功能是将一个原始数组 original 的内容拷贝到另一个数组 copied 中&#xff0c;并输出两个数组的元素。 代码执行过程如下&#xff1a; 首先&#xff0c;在 main() 函数中定义了一个整型数组 original&#xff0c;并初始化了它的元素。…

【java毕业设计】基于SSM+MySql的人才公寓管理系统设计与实现(程序源码)--人才公寓管理系统

基于SSMMySql的人才公寓管理系统设计与实现&#xff08;程序源码毕业论文&#xff09; 大家好&#xff0c;今天给大家介绍基于SSMMySql的人才公寓管理系统设计与实现&#xff0c;本论文只截取部分文章重点&#xff0c;文章末尾附有本毕业设计完整源码及论文的获取方式。更多毕业…

shell脚本之正则表达式

目录 一.常见的管道命令1.1sort命令1.2uniq命令1.3tr命令1.4cut命令1.5实例1.5.1统计当前主机连接状态1.5.2统计当前主机数 二.正则表达式2.1正则表达式的定义2.2常见元字符&#xff08;支持的工具&#xff1a;find&#xff0c;grep&#xff0c;egrep&#xff0c;sed和awk&…

23.8.16日总结

原先写的评论是每级评论用缩进来区分&#xff0c;所以最多设置的是九级评论&#xff0c;修改了排版和格式&#xff1a; 还有管理员页面&#xff0c;查看文章时可以进行点赞&#xff0c;收藏的操作&#xff0c;现在进行了修改&#xff0c;将相关操作隐藏。 还有点击查看未发布…

语聚AI公测发布,大语言模型时代下新的生产力工具

语聚AI 公测发布 距离语聚AI内测上线已经过去近1个月。 这期间&#xff0c;我们共邀请了近百位资深用户与行业专家加入语聚AI产品体验。通过大家的热情参与积极反馈&#xff0c;我们不断优化并完善了语聚AI的功能与使用体验。 经过研发团队不懈的努力&#xff0c;今天语聚AI终…

深入源码分析kubernetes informer机制(三)Resync

[阅读指南] 这是该系列第三篇 基于kubernetes 1.27 stage版本 为了方便阅读&#xff0c;后续所有代码均省略了错误处理及与关注逻辑无关的部分。 文章目录 为什么需要resyncresync做了什么 为什么需要resync 如果看过上一篇&#xff0c;大概能了解&#xff0c;client数据主要通…

B树和B+树区别

B树和B树的区别 B树 B树被称为平衡树&#xff0c;在B树中&#xff0c;一个节点可以有两个以上的子节点。B树的高度为log M N。在B树中&#xff0c;数据按照特定的顺序排序&#xff0c;最小值在左侧&#xff0c;最大值在右侧。 B树是一种平衡的多分树&#xff0c;通常我们说m阶…

Unity-Linux部署WebGL项目MIME类型添加

在以往的文章中有提到过使用IIS部署WebGL添加MIME类型使WebGL项目在浏览器中能够正常加载&#xff0c;那么如果咱们做的是商业项目&#xff0c;往往是需要部署在学校或者云服务器上面的&#xff0c;大部分情况下如果项目有接口或者后台管理系统&#xff0c;后台基本都会使用Lin…

arcgis pro 3.0.2 安装及 geemap

arcgis pro 3.0.2 安装及 geemap arcgis pro 3.0.2 安装 arcgis pro 3 版本已经很多了&#xff0c;在网上找到资源就可以进行安装 需要注意的是&#xff1a;有的文件破解文件缺少&#xff0c;导致破解不成功。 能够新建地图就是成功了&#xff01; geemap安装 1.需要进行环…

FL Studio 21最新for Windows-21.1.0.3267中文解锁版安装激活教程及更新日志

FL Studio 21最新版本for Windows 21.1.0.3267中文解锁版是最新强大的音乐制作工具。它可以与所有类型的音乐一起创作出令人惊叹的音乐。它提供了一个非常简单且用户友好的集成开发环境&#xff08;IDE&#xff09;来工作。这个完整的音乐工作站是由比利时公司 Image-Line 开发…

Flutter源码分析笔记:Widget类源码分析

Flutter源码分析笔记 Widget类源码分析 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at: https://jclee95.blog.csdn.netEmail: 291148484163.com. Shenzhen ChinaAddress of this article:https://blog.csdn.net/qq_28550263/article/details/132259681 【介绍】&#x…

Spring源码深度解析一(IOCDI)

1. Spring架构设计 Spring框架是一个分层架构&#xff0c;他包含一系列的功能要素&#xff0c;并被分为大约20个模块 2. 设计理念 Spring是面向Bean的编程&#xff08;BOP&#xff1a;Bean Oriented Programming&#xff09;&#xff0c;Bean在Spring中才是真正的主角。Bean在…

物联网工程应用实训室建设方案

一、物联网工程应用系统概述 1.1物联网工程定义 物联网工程&#xff08;Internet of Things Engineering&#xff09;是一种以信息技术&#xff08;IT&#xff09;来改善实体世界中人们生活方式的新兴学科&#xff0c;它利用互联网技术为我们的日常生活活动提供服务和增益&am…

CI+JUnit5并发单测机制创新实践

目录 一. 现状问题 二. 分析原因 三. 采取措施 四. 实践步骤 五. 效能提升 资料获取方法 一. 现状问题 针对现如今高并发场景的业务系统&#xff0c;“并发问题” 终归是必不可少的一类&#xff08;占比接近10%&#xff09;&#xff0c;每次出现问题和事故后&#xff0c…

年至年的选择仿elementui的样式

组件&#xff1a;<!--* Author: liuyu liuyuxizhengtech.com* Date: 2023-02-01 16:57:27* LastEditors: wangping wangpingxizhengtech.com* LastEditTime: 2023-06-30 17:25:14* Description: 时间选择年 - 年 --> <template><div class"yearPicker"…

Vue2(组件开发)

目录 前言一&#xff0c;组件的使用二&#xff0c;插槽slot三&#xff0c;refs和parent四&#xff0c;父子组件间的通信4.1&#xff0c;父传子 &#xff1a;父传子的时候&#xff0c;通过属性传递4.2&#xff0c;父组件监听自定义事件 五&#xff0c;非父子组件的通信六&#x…