当前位置: 首页 > news >正文

在MacOS上Qt配置OpenCV并进行测试

目录

一.Qt环境准备

二.在Qt项目中加载Opencv库并编写代码测试 

1.使用Opencv加载图片

(1)在Qt中创建一个新项目

(2)在.pro文件中链接OpenCV库

(3)添加新资源文件

(4)在mainwindow.cpp中编写代码在窗口加载图片

 (5)代码中使用的OpenCV函数分析

        1)cv::imdecode()函数

        2)cv::namedWindow()函数

         3)cv::imshow()函数

        4)cv::waitKey()函数

        5)cv::destroyWindow()函数

2.使用Opencv加载视频

(1)使用Qt创建一个新项目

(2)在.pro文件中链接OpenCV库

(3)在mainwindow.cpp中编写代码

(4)代码中使用的OpenCV函数分析

        1)cv::VideoCapture

参考文档:


一.Qt环境准备

        上一篇博客我讲了如何下载配置OpenCV库,但是在Qt5.15.2使用OpenCV库时,出现了一个问题就是我下载的Qt5.15.2是x86架构的,不能对OpenCV库进行链接,而OpenCV库是arm架构的

        直接使用Qt5.15.2编译链接OpenCV库链接头文件是可以的,但是使用OpenCV代码就不能成功链接编译了

因此需要下载Qt6.3.1版本的, Qt6.3.1版本是arm架构的

下载完成后打开Qt  Creator在Qt版本里面加入Qt6.3.1的qmake

一般是在下载的Qt版本文件bin目录下

再在构建配套(Kit)中加入Qt6.3.1版本的构建配套

这样Qt环境就搭建好了

二.在Qt项目中加载Opencv库并编写代码测试 

1.使用Opencv加载图片

(1)在Qt中创建一个新项目

选择Qt6.3.1(arm)

(2)在.pro文件中链接OpenCV库

#链接OpenCV头文件
INCLUDEPATH +=/usr/local/include/
INCLUDEPATH +=/usr/local/include/opencv4/
INCLUDEPATH +=/usr/local/include/opencv4/opencv2
#链接OpenCV库文件
LIBS += -L/usr/local/lib -lopencv_gapi \-lopencv_stitching -lopencv_aruco -lopencv_bgsegm -lopencv_bioinspired \-lopencv_ccalib -lopencv_dnn_objdetect -lopencv_dnn_superres -lopencv_dpm \-lopencv_highgui -lopencv_face -lopencv_freetype -lopencv_fuzzy -lopencv_hfs \-lopencv_img_hash -lopencv_line_descriptor -lopencv_quality -lopencv_reg \-lopencv_rgbd -lopencv_saliency -lopencv_sfm -lopencv_stereo -lopencv_structured_light \-lopencv_phase_unwrapping -lopencv_superres -lopencv_optflow -lopencv_surface_matching \-lopencv_tracking -lopencv_datasets -lopencv_text -lopencv_dnn -lopencv_plot \-lopencv_videostab -lopencv_videoio -lopencv_xfeatures2d -lopencv_shape -lopencv_ml \-lopencv_ximgproc -lopencv_video -lopencv_xobjdetect -lopencv_objdetect \-lopencv_calib3d -lopencv_imgcodecs -lopencv_features2d -lopencv_flann -lopencv_xphoto \-lopencv_photo -lopencv_imgproc -lopencv_core

(3)添加新资源文件

(4)在mainwindow.cpp中编写代码在窗口加载图片

#include "ui_mainwindow.h"
#include <opencv2/opencv.hpp>
#include <QDebug>
#include <QFile>
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);//以只读的方式打开图片文件QFile file(":/img/tree.jpg");if(!file.open(QFile::ReadOnly))  {qDebug() << "打开图片失败";}//将整个图片文件内容读取到一个 QByteArray 对象中QByteArray photo = file.readAll();cv::Mat img = cv::imdecode(std::vector<char>(photo.begin(), photo.end()), cv::IMREAD_COLOR);//判定图片是否加载成功if(img.empty()){qDebug() << "没有找到照片";}cv::namedWindow("tree", cv::WINDOW_AUTOSIZE);cv::imshow("tree", img);cv::waitKey(0); //cv::waitKey(10000);cv::destroyWindow("tree");
}MainWindow::~MainWindow()
{delete ui;
}

 运行结果:

 (5)代码中使用的OpenCV函数分析

        1)cv::imdecode()函数
//cv::Mat是OpenCV用于处理所有图像类型的结构
//cv::imdecode() 函数将 QByteArray 转换为 OpenCV 的图像格式 cv::Mat,以便进一步处理,cv::IMREAD_COLOR表示以彩色模式加载图像cv::Mat img = cv::imdecode(std::vector<char>(photo.begin(), photo.end()), cv::IMREAD_COLOR);

函数原型: 

Mat cv::imdecode (InputArray buf, int flags);
Mat cv::imdecode (InputArray buf, int flags, Mat *dst);
函数功能: 从内存的缓存区中读取图片
参数:    buf:一个数组或字节数组flags:用来指定图像加载的标志,通过这个参数,可以控制图像加载的一些行为和选项下面是falgs的枚举类型:enum cv::ImreadModes {cv::IMREAD_UNCHANGED = -1,            //按图像原样加载图像cv::IMREAD_GRAYSCALE = 0,             //以灰度模式加载图像cv::IMREAD_COLOR = 1,                 //以彩色模式加载图像cv::IMREAD_ANYDEPTH = 2,              //以原始深度加载图像cv::IMREAD_ANYCOLOR = 4,              //以任意颜色模式加载图像,返回一个3通道图像cv::IMREAD_LOAD_GDAL = 8,             //使用gdal驱动程序加载图像       cv::IMREAD_REDUCED_GRAYSCALE_2 = 16,  //将图像转换为单通道灰度图像,图像尺寸减小1/2cv::IMREAD_REDUCED_COLOR_2 = 17,      //图像转换为3通道BGR彩色图像,图像大小减少1/2cv::IMREAD_REDUCED_GRAYSCALE_4 = 32,  //将图像转换为单通道灰度图像,图像尺寸减小1/4cv::IMREAD_REDUCED_COLOR_4 = 33,      //将图像转换为3通道BGR彩色图像,图像大小减少1/4cv::IMREAD_REDUCED_GRAYSCALE_8 = 64,  //将图像转换为单通道灰度图像,图像尺寸减小1/8cv::IMREAD_REDUCED_COLOR_8 = 65,      //将图像转换为3通道BGR彩色图像,图像大小减少1/8cv::IMREAD_IGNORE_ORIENTATION = 128  //不根据EXIF的方向标志旋转图像(EXIF(Exchangeable Image File Format)是一种图像文件格式,用于存储数字图像中的元数据信息,例如相机设置、拍摄日期和时间、地理位置等。)}dst(可选):用于接收解码后的图像数据
返回值:成功: 一个Mat类型的值失败: NULL

例子: 

cv::Mat image;  // 定义用于存储解码后图像的 cv::Mat 对象
cv::imdecode(buffer, flags, &image);

         通过传递 &imagecv::imdecode() 函数的 dst 参数,解码后的图像数据将直接存储在 image

        也可以不使用第三个参数,直接使用返回值

cv::Mat image;  // 定义用于存储解码后图像的 cv::Mat 对象
image = cv::imdecode(buffer, flags);
        2)cv::namedWindow()函数
 //cv::namedWindow():函数将会在屏幕上打开一个窗口,窗口名为tree,cv::WINDOW_AUTOSIZE是窗口的属性:窗口的大小与载入的图片大小一致,图片会被缩放大小来适应窗口大小cv::namedWindow("tree", cv::WINDOW_AUTOSIZE);

 函数原型:

void cv::namedWindow(const String &winname,int flags = WINDOW_AUTOSIZE);
函数功能:函数namedWindow创建一个窗口,该窗口可用作图像和跟踪条的占位符。创建的窗口通过窗口名称来引用
参数:winname: 窗口标题,也是用于窗口标识符的窗口名称flags: 窗口标志下面是falgs的枚举类型:enum cv::WindowFlags {cv::WINDOW_NORMAL = 0x00000000,       //用户可以调整窗口的大小(没有限制)/也可以将全屏窗口切换到正常大小cv::WINDOW_AUTOSIZE = 0x00000001,     //用户无法调整窗口大小,窗口大小受显示图像的限制cv::WINDOW_OPENGL = 0x00001000,       //支持opengl的窗口cv::WINDOW_FULLSCREEN = 1,            //将窗口改为全屏cv::WINDOW_FREERATIO = 0x00000100,    //图像尽可能地扩展(没有比例限制)cv::WINDOW_KEEPRATIO = 0x00000000,    //保持图像原有的比例cv::WINDOW_GUI_EXPANDED =0x00000000,  //状态栏和工具栏cv::WINDOW_GUI_NORMAL = 0x00000010    //默认的窗口模式,会在图像显示时以普通窗口的形式呈现,并提供基本的窗口操作,如调整大小、移动和关闭}
返回值:无返回值
         3)cv::imshow()函数
//cv::imshow():函数将会创建一个窗口(如果这个窗口不存在,会自动调用cv::namedWindow()函数来新建一个窗口),调用cv::imshow()会将指定的图片绘制在窗口上cv::imshow("tree", img);

函数原型:


void cv::imshow(const String &winname, InputArray mat);
函数功能: 在指定窗口中显示图像
参数: winname: 指定的窗口对象mat: 展示的图像
返回值: 无返回值
        4)cv::waitKey()函数
//cv::waitKey():系统暂停并等待键盘事件发生(如果传入的参数值大于零,就会等待该值的毫秒时间(如果在等待时间中有键盘事件发生,会立马继续执行后面的程序),然后继续执行后面程序,如果参数设置为0或负数,程序将会无限等待,直到有键盘事件发生)cv::waitKey(0); //cv::waitKey(10000);

 函数原型:

int cv::waitKey	(int delay = 0);
函数功能: 等待键盘事件发生
参数: delay: 以毫秒为单位的延迟。0是代表“永远”的特殊值
返回值:返回按下的键的代码,如果在指定时间之前没有按下键,则返回-1
        5)cv::destroyWindow()函数
//cv::destroyWindow() 关闭指定的窗口并释放相关内存空间cv::destroyWindow("tree");

函数原型:

void cv::destroyWindow(const String &winname);	
函数功能: 销毁指定的窗口
参数:winname: 要销毁的窗口名称
返回值:无返回值

2.使用Opencv加载视频

(1)使用Qt创建一个新项目

(2)在.pro文件中链接OpenCV库

#链接OpenCV头文件
INCLUDEPATH +=/usr/local/include/
INCLUDEPATH +=/usr/local/include/opencv4/
INCLUDEPATH +=/usr/local/include/opencv4/opencv2
#链接OpenCV库文件
LIBS += -L/usr/local/lib -lopencv_gapi \-lopencv_stitching -lopencv_aruco -lopencv_bgsegm -lopencv_bioinspired \-lopencv_ccalib -lopencv_dnn_objdetect -lopencv_dnn_superres -lopencv_dpm \-lopencv_highgui -lopencv_face -lopencv_freetype -lopencv_fuzzy -lopencv_hfs \-lopencv_img_hash -lopencv_line_descriptor -lopencv_quality -lopencv_reg \-lopencv_rgbd -lopencv_saliency -lopencv_sfm -lopencv_stereo -lopencv_structured_light \-lopencv_phase_unwrapping -lopencv_superres -lopencv_optflow -lopencv_surface_matching \-lopencv_tracking -lopencv_datasets -lopencv_text -lopencv_dnn -lopencv_plot \-lopencv_videostab -lopencv_videoio -lopencv_xfeatures2d -lopencv_shape -lopencv_ml \-lopencv_ximgproc -lopencv_video -lopencv_xobjdetect -lopencv_objdetect \-lopencv_calib3d -lopencv_imgcodecs -lopencv_features2d -lopencv_flann -lopencv_xphoto \-lopencv_photo -lopencv_imgproc -lopencv_core

(3)在mainwindow.cpp中编写代码

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);//新建一个窗口,窗口名为scenery,窗口模式为cv::WINDOW_AUTOSIZEcv::namedWindow("scenery", cv::WINDOW_AUTOSIZE);cv::VideoCapture cap; //cv::VideoCapture类型用于打开视频文件//打开指定的视频文件if(!cap.open("/Users/liwanyu/Downloads/opencvDemo/day1/video/videoload/video/scenery.mp4")){qDebug() << "打开视频文件失败";}//打开网络视频//cap.open("https://vd2.bdstatic.com/mda-njqbvdg1h8kdqez1/720p/h264/1666686182583726512/mda-njqbvdg1h8kdqez1.mp4?v_from_s=hkapp-haokan-hna&amp;auth_key=1703093507-0-0-fc2c4688c205be7eedb5e09162e45f57&amp;bcevod_channel=searchbox_feed&amp;pd=1&amp;cr=2&amp;cd=0&amp;pt=3&amp;logid=1907408427&amp;vid=14746953470406117750&amp;klogid=1907408427&amp;abtest=");cv::Mat frame; //用于保存视频帧//在while循环中循环播放视频while(1){//视频文件按照帧从视频流中读出来,每33毫秒换帧,如果在这33毫秒中有键盘事件发生就退出视频帧播放cap.read(frame); //cap >> frameif(frame.empty()){break;}cv::imshow("scenery", frame);if(cv::waitKey(33)>=0){break;}}cv::destroyWindow("scenery"); //关闭指定的窗口并销毁其内存空间
}MainWindow::~MainWindow()
{delete ui;
}

运行结果:

(4)代码中使用的OpenCV函数分析

        1)cv::VideoCapture

   cv::VideoCapture 

功能:用于从视频文件、图像序列或相机中捕获视频的类

        

Public Member Functions:

默认的空构造:

   

cv::VideoCapture::VideoCapture();

 重载的构造:

​cv::VideoCapture::VideoCapture(const String &filename, int apiPreference = CAP_ANY);

功能:

        打开视频文件或捕获摄像头设备或IP视频流(网络传输视频流),默认使用API首选项(CAP_ANY)进行视频捕获

参数:

        filename要打开的视频文件名、捕获设备的索引号(一般为0表示默认摄像头),或者是 IP 视频流地址

        apiPreference可选参数,用于指定视频捕获 API 的首选项。默认值为 CAP_ANY,表示尝试使用任何可用的视频捕获 API 来打开

 cv::VideoCapture::VideoCapture(const String &filename, int apiPreference, const std::vector<int> &params);

功能: 

         打开视频文件或捕获摄像头设备或IP视频流(网络传输视频流),默认使用API首选项(CAP_ANY)进行视频捕获

参数:       

        filename要打开的视频文件名、捕获设备的索引号(一般为0表示默认摄像头),或者是 IP 视频流地址

        apiPreference可选参数,用于指定视频捕获 API 的首选项。默认值为 CAP_ANY,表示尝试使用任何可用的视频捕获 API 来打开

        params:可选不定参数,以向底层视频捕获库传递附加的特定参数

例如:

       

 cv::VideoCapture cap("video.mp4", cv::CAP_FFMPEG, {cv::CAP_PROP_FRAME_WIDTH, 640, cv::CAP_PROP_FRAME_HEIGHT, 480});

        在此示例中,传递了一组参数来设置所捕获视频帧的宽度和高度。使用了 cv::CAP_PROP_FRAME_WIDTHcv::CAP_PROP_FRAME_HEIGHT,这些常量表示帧的宽度和高度属性,然后将期望的值分别设置为 640 和 480。这意味着设置了捕获的每个视频帧的宽度为 640 像素,高度为 480 像素。

​cv::VideoCapture::VideoCapture(int index, int apiPreference = CAP_ANY);

功能:

         打开摄像机进行视频捕获

参数:

        index:捕获设备的索引号,用于指定要打开的特定设备。通常情况下,0 表示默认摄像头,1 表示第二个摄像头,以此类推。如果你的系统上有多个摄像头或其他捕获设备,可以通过指定不同的索引号来选择打开哪个设备

        apiPreference可选参数,用于指定视频捕获 API 的首选项。默认值为 CAP_ANY,表示尝试使用任何可用的视频捕获 API 来打开

​cv::VideoCapture::VideoCapture(int index, int apiPreference = CAP_ANY,  int apiPreference, const std::vector<int> &params); 

功能:

        使用API首选项和不定参数打开摄像机进行视频捕获。

参数:      

        index:捕获设备的索引号,用于指定要打开的特定设备。通常情况下,0 表示默认摄像头,1 表示第二个摄像头,以此类推。如果你的系统上有多个摄像头或其他捕获设备,可以通过指定不同的索引号来选择打开哪个设备

        apiPreference可选参数,用于指定视频捕获 API 的首选项。默认值为 CAP_ANY,表示尝试使用任何可用的视频捕获 API 来打开

        params:可选不定参数,以向底层视频捕获库传递附加的特定参数

 默认的析构函数:

virtual cv::VideoCapture::~VideoCapture();

其他成员函数: 

virtual double cv::VideoCapture::get(int propld) const;

功能:

        返回指定的VideoCapture属性

参数:

        propld:要获取属性的标识符(例如,如果propId为CV_CAP_PROP_FRAME_WIDTH,则该函数将返回输入视频流的帧宽度)

返回值:

        返回值类型为double,表示所请求属性的当前值

String cv::VideoCapture::getBackendName()const;

功能:

        用于返回使用的视频捕获后端API的名称

参数:

        无参数

返回值:

        成功:String类型的后端API名称

        失败:NULL

bool cv::VideoCapture::getExceptionMode();

功能:

        用于获取异常模式的状态

参数:

        无参数

返回值:

        返回true,则表示异常模式已启用,即当发生错误时,将抛出异常

        返回false,则表示异常模式已禁用,即当发生错误时,不会抛出异常,而是通过错误码或其他方式通知用户

 virtual bool cv::VideoCapture::grab();

功能:

        用于从输入视频流中抓取一帧图像,但不将其解码

参数:

        无参数

返回值:

        返回true,则表示成功抓取了一帧图像

        返回false,则表示未能成功抓取图像

virtual bool cv::VideoCapture::isOpened()const;

功能:

        用于检查当前视频捕获对象是否成功打开了视频文件或设备

参数:

        无参数

返回值:

        返回true,则表示视频捕获对象已成功打开,并且可以从该对象读取视频帧

        返回false,则表示视频捕获对象无法打开,可能是由于文件路径错误、设备未连接或者不支持的格式等原因

用于打开视频文件或设备的open函数:(open函数的参数和cv::VideoCapture:构造函数的参数一样就不再解释了)

​
virtual bool cv::VideoCapture::open(const String &filename, int apiPreference = CAP_ANY);
virtual bool cv::VideoCapture::open(const String &filename, int apiPreference, const std::vector<int> &params);
virtual bool cv::VideoCapture::open(int index, int apiPreference = CAP_ANY);
virtual bool cv::VideoCapture::open(int index, int apiPreference = CAP_ANY,  int apiPreference, const std::vector<int> &params); 

重载的运算符函数: 

virtual VideoCapture &operator>>(Mat &image);

功能:

        用于从视频流中读取一帧图像并将其存储到提供的Mat对象中

参数:

        image:要存储读取帧的Mat对象。它将存储从视频流中读取的图像数据        

virtual VideoCapture &operator>>(UMat &image);

功能:

        用于从视频流中读取一帧图像并将其存储到提供的UMat对象中

参数:

        image:要存储读取帧的UMat对象。它将存储从视频流中读取的图像数据        

virtual bool cv::VideoCapture::read(OutputArray image);	

功能:

        用于从视频流中读取一帧图像并将其存储在提供的OutputArray对象中

参数:

        image:要存储读取帧的OutputArray对象。它可以是MatUMat或其他可接受输出图像数据的对象类型

返回值:

        返回true,则表示成功读取到一帧图像,并将其存储在提供的OutputArray对象中

    返回false,则表示未能成功读取图像,可能是由于视频结束、读取错误或其他原因

virtual void cv::VideoCapture::release();

功能:

        用于释放视频捕获对象所占用的资源 

参数:

        无参数

返回值:

        无返回值

virtual bool cv::VideoCapture::retrieve(OutputArray image, int flag=0);

功能:

        用于解码和获取当前抓取的视频帧

参数:

        image:要存储解码后图像的OutputArray对象。它可以是MatUMat或其他可接受输出图像数据的对象类型

        falg:可选参数,用于指定附加的操作标志。默认值为0

返回值:

        返回true,则表示成功解码当前抓取的视频帧,并将其存储在提供的OutputArray对象中

        返回false,则表示未能成功解码视频帧

virtual bool cv::VideoCapture::set(int propId, double value);

功能:

        用于设置视频捕获对象的属性值 

参数:

    propId:要设置的属性的标识符。可以使用不同的标识符来设置不同的属性值。例如,如果propIdCV_CAP_PROP_FRAME_WIDTH,则代表设置输入视频流的帧宽度

    value:要设置的属性值

返回值:

        返回true,则表示成功设置属性的值

        返回false,则表示无法设置属性的值,可能是由于不支持的属性或其他原因

void cv::VideoCapture::setExceptionMode(bool enable);

功能:

        用于设置异常模式的状态

参数:

        enable:一个bool值,表示是否启用异常模式。如果enabletrue,则启用异常模式,即当发生错误时,将抛出异常  ;如果enablefalse,则禁用异常模式,即当发生错误时,不会抛出异常,而是通过错误码或其他方式通知用户

返回值:

        无返回值

静态成员函数: 

static bool cv::VideoCapture::waitAny(const std::vector< VideoCapture > &streams, std::vector< int > &readyIndex, int64 timeoutNs=0);

功能:       

        静态成员函数,用于等待多个视频捕获对象中至少一个准备就绪(有可读取的帧)

参数:

        streams:一个包含多个VideoCapture对象的std::vector,表示要等待的视频捕获对象列表。

    readyIndex:一个空的std::vector<int>,用于存储准备就绪的视频捕获对象的索引。准备就绪的对象即有可读取的帧。

    timeoutNs:可选参数,以纳秒为单位指定的超时时间。默认值为0,表示无限等待

返回值:

        返回true,则表示至少一个视频捕获对象已准备就绪。

        返回false,则表示在超时时间内没有可用的视频捕获对象

友元类:

friend class internal::VideoCapturePrivateAccessor

参考文档:

OpenCV: Image file reading and writing

OpenCV: High-level GUI

OpenCV: cv::VideoCapture Class Reference

相关文章:

在MacOS上Qt配置OpenCV并进行测试

目录 一.Qt环境准备 二.在Qt项目中加载Opencv库并编写代码测试 1.使用Opencv加载图片 &#xff08;1&#xff09;在Qt中创建一个新项目 &#xff08;2&#xff09;在.pro文件中链接OpenCV库 &#xff08;3&#xff09;添加新资源文件 &#xff08;4&#xff09;在mainw…...

java数据结构与算法刷题-----LeetCode167:两数之和 II - 输入有序数组

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 思路 题目要求我们找到两个数相加的和&#xff0c;等于target指定的值。而…...

Linux:jumpserver V3的安装与升级(在线离线)(2)

官方文档写的非常详细&#xff0c;我这篇文章时间长了&#xff0c;会随着官方版本更新而落后 JumpServer - 开源堡垒机 - 官网https://www.jumpserver.org/安装和升级在官网也有详细的信息&#xff0c;我写本章是为了记录一下实验 我的系统是centos7.9 在线安装 在确定我们可…...

【GoLang】Go语言几种标准库介绍(一)

你见过哪些令你膛目结舌的代码技巧&#xff1f; 文章目录 你见过哪些令你膛目结舌的代码技巧&#xff1f;前言几种库bufio&#xff08;带缓冲的 I/O 操作&#xff09;特性示例 bytes (实现字节操作)特性示例 总结专栏集锦写在最后 前言 随着计算机科学的迅猛发展&#xff0c;编…...

短剧分销系统:月入百w的新模式

随着我国短剧的高速发展&#xff0c;越来越多的人进入到了短剧影视行业。本文旨在介绍短剧市场的发展前景以及短剧分销系统的设计和开发。 一、短剧发展背景 短剧具有时长短、剧情紧凑、节奏快、剧情新颖等特点&#xff0c;满足了国内观众的碎片化时间&#xff0c;在当下短视频…...

鞋服用户运营策略如何实现有效闭环?

实现长期价值和业务闭环是企业经营的关键。对于鞋服行业来说&#xff0c;如何基于客户旅程编排&#xff08;Customer Journey Orchestration&#xff0c;简称 CJO&#xff09;实现用户运营策略的有效闭环&#xff0c;提升长期价值呢&#xff1f; 本文围绕该主题&#xff0c;从鞋…...

简单工厂、工厂方法、抽象工厂和策略模式

摘要 本文简单介绍软件开发过程中面临的痛点和几个总体原则。详细介绍了简单工厂、工厂方法、抽象工厂和策略模式的实现&#xff0c;以及各种模式之间的相似、区别。 背景 开发面临哪些问题&#xff08;痛点&#xff09;&#xff1f; 相信做过大型软件开发的tx都遇到过以下类似…...

junit mocktio request打桩

Controller下request组装参数 HttpServletRequest request new MockHttpServletRequest(); ((MockHttpServletRequest) request).addHeader("router","login"); ((MockHttpServletRequest) request).addParameter("test","wwww"); …...

第十四节TypeScript 联合类型

1、简介 联合类型可以通过管道&#xff08;|&#xff09;将变量设置多种类型&#xff0c;赋值时可以根据设置的类型来赋值。 注意&#xff1a;只能赋值指定的类型&#xff0c;如果赋值其它类型就会报错的。 2、创建联合类型的语法格式&#xff1a; Type1|Type2|Type3 实例&a…...

[x86汇编语言]从实模式到保护模式第二版

下载汇编器&#xff1a;https://www.nasm.us/pub/nasm/releasebuilds/2.16.02rc6/win64/ mov ax, 0x3f add bx,ax add cx,ax 编译&#xff1a; C:\Users\HP>cd D:\BaiduNetdiskDownload\01b站\lizhong\myasm C:\Users\HP>D: D:\BaiduNetdiskDownload\01b站\lizhong…...

基本的逻辑门

前言 本篇文章介绍基本的逻辑门&#xff0c;然后给出C语言描述 逻辑门是在集成电路上的基本组件。简单的逻辑门可由晶体管组成。这些晶体管的组合可以使代表两种信号的高低电平在通过它们之后产生高电平或者低电平的信号。高、低电平可以分别代表逻辑上的“真”与“假”或二进…...

云原生系列3-Kubernetes

1、Kubernetes概述 k8s缩写是因为k和s之间有八个字符。k8s是基于容器技术的分布式架构方案。官网&#xff1a;https://kubernetes.io/zh-cn/ Google在 2014年开源了Kubernetes项目&#xff0c;Kubernetes是一个用于自动化部署、扩展和管理容器化应用程序的开源系统。同样类似的…...

R-列表、矩阵、数组转化为向量

目录 一、c()函数 二、unlist()函数 一、c()函数 c()&#xff1a;对应的英文是combine. 当你使用c()函数时&#xff0c;它会将输入的对象连接成一个向量。因此&#xff0c;无论输入是矩阵、数组还是列表&#xff0c;c()函数都会将它们连接成一个简单的向量。因此&#xff…...

算法通关村-番外篇排序算法

大家好我是苏麟 , 今天带来番外篇 . 冒泡排序 BubbleSort 最基本的排序算法&#xff0c;最常用的排序算法 . 我们以关键字序列{26,53,48,11,13,48,32,15}看一下排序过程: 动画演示 : 代码如下 : (基础版) class Solution {public int[] sortArray(int[] nums) {for(int i …...

三种方式简单搭建http本地文件服务

有时候想写一个简单的html文件&#xff0c;然后加上一些image、js、css文件用于测试。希望有一个简单的http服务&#xff0c;总结了如下三种方式&#xff0c;欢迎讨论更多高效的方式。 &#xff08;一&#xff09;使用Web Server for Chrome浏览器扩展 之前写过一篇博文&#x…...

设计模式--适配器模式

实验8&#xff1a;适配器模式 本次实验属于模仿型实验&#xff0c;通过本次实验学生将掌握以下内容&#xff1a; 1、理解适配器模式的动机&#xff0c;掌握该模式的结构&#xff1b; 2、能够利用适配器模式解决实际问题。 [实验任务]&#xff1a;双向适配器 实现一个双向…...

Node.js教程-express框架

概述 Express是基于Node.js平台(建立在Node.js内置的http模块上)&#xff0c;快速、开放、极简的Web开发框架。 中文官网 http://www.expressjs.com.cn/。 Github地址&#xff1a;https://github.com/orgs/expressjs。 Express核心特性&#xff1a; 可设置中间件来响应 HTTP…...

location.origin兼容

if (!window.location.origin) {window.location.origin window.location.protocol "//" window.location.hostname (window.location.port ? : window.location.port: );}...

spring boot集成mybatis和springsecurity实现权限控制功能

上一篇已经实现了登录认证功能&#xff0c;这一篇继续实现权限控制功能&#xff0c;文中代码只贴出来和上一篇不一样的修改的地方&#xff0c;完整代码可结合上一篇一起整理spring boot集成mybatis和springsecurity实现登录认证功能-CSDN博客 数据库建表 权限控制的意思就是根…...

按键修饰符

在键盘监听事件时&#xff0c;我们经常需要判断详细的按键&#xff0c;此时&#xff0c;可以为键盘相关的事件添加按键修饰符&#xff0c;例如&#xff1a; 键盘修饰符案例&#xff1a;...

新版IDEA中Git的使用(一)

说明&#xff1a;本文介绍如何在新版IDEA中使用Git 创建项目 首先&#xff0c;在GitLab里面创建一个项目&#xff08;git_demo&#xff09;&#xff0c;克隆到桌面上。 然后在IDEA中创建一个项目&#xff0c;项目路径放在这个Git文件夹里面。 Git界面 当前分支&Commit …...

【性能测试】真实企业,性能测试流程总结分析(一)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 性能测试什么时候…...

20231224解决outcommit_id.xml1 parser error Document is empty的问题

20231224解决outcommit_id.xml1 parser error Document is empty的问题 2023/12/24 18:13 在开发RK3399的Android10的时候&#xff0c;出现&#xff1a;rootrootrootroot-X99-Turbo:~/3TB/Rockchip_Android10.0_SDK_Release$ make installclean PLATFORM_VERSION_CODENAMEREL…...

电子电器架构刷写方案——General Flash Bootloader

电子电器架构刷写方案——General Flash Bootloader 我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 注&#xff1a;文章1万字左右&#xff0c;深度思考者入&#xff01;&#xff01;&#xff01; 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免…...

【Linux】僵尸与孤儿 进程等待

目录 一&#xff0c;僵尸进程 1&#xff0c;僵尸进程 2&#xff0c;僵尸进程的危害 二&#xff0c;孤儿进程 1&#xff0c;孤儿进程 三&#xff0c;进程等待 1&#xff0c;进程等待的必要性 2&#xff0c;wait 方法 3&#xff0c;waitpid 方法 4&#xff0c;回收小结…...

Java小案例-Sentinel的实现原理

前言 Sentinel是阿里开源的一款面向分布式、多语言异构化服务架构的流量治理组件。 主要以流量为切入点&#xff0c;从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。 核心概念 要想理解一个新的技…...

【Leetcode Sheet】Weekly Practice 21

Leetcode Test 1901 寻找峰值Ⅱ(12.19) 一个 2D 网格中的 峰值 是指那些 严格大于 其相邻格子(上、下、左、右)的元素。 给你一个 从 0 开始编号 的 m x n 矩阵 mat &#xff0c;其中任意两个相邻格子的值都 不相同 。找出 任意一个 峰值 mat[i][j] 并 返回其位置 [i,j] 。 …...

C语言使用qsort和bsearch实现二分查找

引言 在计算机科学领域&#xff0c;查找是一项基本操作&#xff0c;而二分查找是一种高效的查找算法。本博客将详细解释一个简单的C语言程序&#xff0c;演示如何使用标准库函数qsort和bsearch来对一个整数数组进行排序和二分查找。 代码解析 包含头文件 #include <stdi…...

MySQL的替换函数及补全函数的使用

前提&#xff1a; mysql的版本是8.0以下的。不支持树形结构递归查询的。但是&#xff0c;又想实现树形结构的一种思路 提示&#xff1a;如果使用的是MySQL8.0及其以上的&#xff0c;想要实现树形结构&#xff0c;请参考&#xff1a;MySQL数据库中&#xff0c;如何实现递归查询…...

2022第十二届PostgreSQL中国技术大会-核心PPT资料下载

一、峰会简介 本次大会以“突破•进化•共赢 —— 安全可靠&#xff0c;共建与机遇”为主题&#xff0c;助力中国数据库基础软件可掌控、可研究、可发展、可生产&#xff0c;并推动数据库生态的繁荣与发展。大会为数据库从业者、数据库相关企业、数据库行业及整个IT产业带来崭…...

2024 年 10大 AI 趋势

2025 年&#xff0c;全球人工智能市场预计将达到惊人的 1906.1 亿美元&#xff0c;年复合增长率高达 36.62%。 人工智能软件正在迅速改变我们的世界&#xff0c;而且这种趋势在未来几年只会加速。 我们分析了未来有望彻底改变 2024 年的 10 个AI趋势。从生成式人工智能的兴起到…...

Uboot

什么是Bootloader? Linux系统要启动就必须需要一个 bootloader程序&#xff0c;也就说芯片上电以后先运行一段bootloader程序。 这段 **bootloader程序会先初始化时钟&#xff0c;看门狗&#xff0c;中断&#xff0c;SDRAM&#xff0c;等外设&#xff0c;然后将 Linux内核从f…...

ECMAScript 的未来:预测 JavaScript 创新的下一个浪潮

以下是简单概括关于JavaScript知识点以及一些目前比较流行的比如&#xff1a;es6 想要系统学习&#xff1a; 大家有关于JavaScript知识点不知道可以去 &#x1f389;博客主页&#xff1a;阿猫的故乡 &#x1f389;系列专栏&#xff1a;JavaScript专题栏 &#x1f389;ajax专栏&…...

代码随想录算法训练营第十三天 | 239. 滑动窗口最大值、347.前 K 个高频元素

239. 滑动窗口最大值 题目链接&#xff1a;239. 滑动窗口最大值 给你一个整数数组 nums&#xff0c;有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗口中的最大值 。 文章讲解…...

推荐五个免费的网络安全工具

导读&#xff1a; 在一个完美的世界里&#xff0c;信息安全从业人员有无限的安全预算去做排除故障和修复安全漏洞的工作。但是&#xff0c;正如你将要学到的那样&#xff0c;你不需要无限的预算取得到高质量的产品。这里有SearchSecurity.com网站专家Michael Cobb推荐的五个免费…...

Cross-Drone Transformer Network for Robust Single Object Tracking论文阅读笔记

Cross-Drone Transformer Network for Robust Single Object Tracking论文阅读笔记 Abstract 无人机在各种应用中得到了广泛使用&#xff0c;例如航拍和军事安全&#xff0c;这得益于它们与固定摄像机相比的高机动性和广阔视野。多无人机追踪系统可以通过从不同视角收集互补的…...

【LeetCode刷题笔记】动态规划(二)

647. 回文子串 解题思路: 1. 暴力穷举 , i 遍历 [0, N) , j 遍历 [i+1, N] ,判断每一个子串 s[i, j) 是否是回文串,判断是否是回文串可以采用 对撞指针 的方法。如果是回文串就计数 +1...

(十七)Flask之大型项目目录结构示例【二扣蓝图】

大型项目目录结构&#xff1a; 问题引入&#xff1a; 在上篇文章讲蓝图的时候我给了一个demo项目&#xff0c;其中templates和static都各自只有一个&#xff0c;这就意味着所有app的模板和静态文件都放在了一起&#xff0c;如果项目比较大的话&#xff0c;这就非常乱&#xf…...

蓝牙技术在物联网中的应用

随着蓝牙技术的不断演进和发展&#xff0c;蓝牙已经从单一的传统蓝牙技术发展成集传统蓝牙。高速蓝牙和低耗能蓝牙于一体的综合技术&#xff0c;不同的应用标准更是超过40个越来越广的技术领域和越来越多的应用场景&#xff0c;使得目前的蓝牙技术成为包含传感器技术、识别技术…...

宝塔面板Linux服务器CentOS 7数据库mysql5.6升级至5.7版本教程

近段时间很多会员问系统更新较慢&#xff0c;也打算上几个好的系统&#xff0c;但几个系统系统只支持MYSQL5.7版本&#xff0c;服务器一直使用较低的MYSQL5.6版本&#xff0c;为了测试几个最新的系统打算让5.6和5.7并存使用&#xff0c;参考了多个文档感觉这种并存问题会很多。…...

掌握常用Docker命令,轻松管理容器化应用

Docker是一个开源的应用容器引擎&#xff0c;它可以让开发者将应用程序及其依赖打包到一个轻量级、可移植的容器中&#xff0c;然后发布到任何流行的Linux机器或Windows机器上&#xff0c;也可以实现虚拟化。容器是完全使用沙箱机制&#xff0c;相互之间不会有任何接口。下面介…...

【数据结构1-2】P5076 普通二叉树(简化版)(c++,multiset做法)

文章目录 一、题目【深基16.例7】普通二叉树&#xff08;简化版&#xff09;题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1基本思路&#xff1a; 一、题目 【深基16.例7】普通二叉树&#xff08;简化版&#xff09; 题目描述 您需要写一种数据结构&#xff0c;来维…...

Linux系统安装及管理

目录 一、Linux应用程序基础 1.1应用程序与系统命令的关系 1.2典型应用程序的目录结构 1.3常见的软件包装类型 二、RPM软件包管理 1.RPM是什么&#xff1f; 2.RPM命令的格式 2,1查看已安装的软件包格式 2.2查看未安装的软件包 3.RPM安装包从哪里来&#xff1f; 4.挂…...

MySQL学生向笔记以及使用过程问题记录(内含8.0.34安装教程

MySQL 只会写代码 基本码农 要学好数据库&#xff0c;操作系统&#xff0c;数据结构与算法 不错的程序员 离散数学、数字电路、体系结构、编译原理。实战经验&#xff0c; 高级程序员 去IOE&#xff1a;去掉IBM的小型机、Oracle数据库、EMC存储设备&#xff0c;代之以自己在开源…...

obs video-io.c

video_frame_init 讲解 /* messy code alarm video_frame_init 函数用于初始化视频帧。它接受一个指向 struct video_frame 结构体的指针 frame&#xff0c; 视频格式 format&#xff0c;以及宽度 width 和高度 height。该函数根据视频格式的不同&#xff0c;计算出每个视频帧…...

简述 tcp 和 udp的区别?

简述 tcp 和 udp的区别&#xff1f; TCP&#xff08;Transmission Control Protocol&#xff09;和UDP&#xff08;User Datagram Protocol&#xff09;是两种不同的传输层协议&#xff0c;用于在计算机网络中进行数据传输。以下是它们的主要区别&#xff1a; 区别&#xff1…...

信息收集 - 谷歌hack

搜索引擎 FOFA网络空间测绘:https://fofa.info/ FOFA(FOcus on Assets)是一个网络空间搜索引擎,可以帮助用户快速定位和收集特定目标的信息。 ZoomEye:https://www.zoomeye.org ZoomEye 是一个网络空间搜索引擎,可以用于发现和收集特定目标的网络设备、Web应用程序、开放…...

英飞凌TC3xx之一起认识DSADC系列(七)应用实战项目二(实现旋变软解码)

英飞凌TC3xx之一起认识DSADC系列(七) 1 项目要求2 项目实现2.1 内部时钟配置2.2 输入信号配置2.3 调制器配置2.4 滤波器链路配置2.5 整流器配置3 总结本文写一篇关于DSADC的resover的载波信号生成的应用,刚刚接触DSADC的开发者很容易被手册中简短的文字描述弄的迷惑,它到底…...

【浏览器】同源策略和跨域

1. 什么是跨域 在说跨域之前,先说说同源策略,什么是同源策略呢?同源策略是浏览器的一种安全机制,减少跨站点脚本攻击(XSS,Cross Site Scripting)、跨站点请求伪造(CSRF,Cross Site Request Forgery)攻击等,因为非同源的请求会被浏览器拦截掉。 同源就是协议、域名(…...

云计算与大数据之间的羁绊(期末不挂科版):云计算 | 大数据 | Hadoop | HDFS | MapReduce | Hive | Spark

文章目录 前言&#xff1a;一、云计算1.1 云计算的基本思想1.2 云计算概述——什么是云计算&#xff1f;1.3 云计算的基本特征1.4 云计算的部署模式1.5 云服务1.6 云计算的关键技术——虚拟化技术1.6.1 虚拟化的好处1.6.2 虚拟化技术的应用——12306使用阿里云避免了高峰期的崩…...