OpenCV运行gstreamer管道获取相机数据,处理以后,再交给gstreamer显示(QT实现)

前言

        无意中发现,OpenCV也可以运行gstreamer的命令管道,然后使用appsink来与OpenCV连接起来进行处理,在不断测试之下,先后实现了以下功能:

        1. OpenCV运行gstreamer命令,通过appsink传递给OpenCV显示

        2. OpenCV运行gstreamer命令,然后再把Mat图像数据通过appsrc传递给gstreamer显示

        3. 增加OpenCV处理,然后使用gstreamer的overlay绑定QT的QWidget显示出来

一、环境安装以及简单的测试demo

注意:

  1. gstreamer和opencv的版本一定要匹配才行,比如目前使用的是gstreamer--1.16.3 ,opencv是4.2.0.  ,我没仔细去查具体的版本匹配,但是OpenCV3.4和gstreamer1.16肯定不匹配。

  2. 虚拟机的路径是/usr/lib/x86_64-linux-gnu/ orin上是/usr/local/lib,在pro文件需要区分

安装OpenCV环境:

方法一:源码安装opencv参考:Jetson Orin NX 开发指南(5): 安装 OpenCV 4.6.0 并配置 CUDA 以支持 GPU 加速_jetson安装opencv-CSDN博客

方法二:apt安装opencv开发库:sudo apt-get update sudo apt-get install libopencv-dev

我自己使用的是方法二,但是这个需要自己找到头文件、库那些位置。

安装gstreamer环境,请参考其他文章,或者以下:

sudo apt-get install -y libgstreamer1.0-0 \gstreamer1.0-plugins-base \gstreamer1.0-plugins-good \gstreamer1.0-plugins-bad \gstreamer1.0-plugins-ugly \gstreamer1.0-libav \gstreamer1.0-doc \gstreamer1.0-tools \libgstreamer1.0-dev \libgstreamer-plugins-base1.0-devsudo apt-get install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libqt5gstreamer-dev libgtk-3-devsudo apt-get install libpng12-0 

源码功能:实现OpenCV运行gstreamer管道

pro文件:

QT       += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
DESTDIR = $$PWD/bin
CONFIG += c++11DEFINES += QT_DEPRECATED_WARNINGSSOURCES += \main.cpp#orin: 
CONFIG += link_pkgconfig
PKGCONFIG += opencv4
LIBS    += -L/usr/local/lib -lopencv_core -lopencv_highgui -lopencv_imgproc -lopencv_imgcodecsINCLUDEPATH += \/usr/include/opencv2/#虚拟机:
#CONFIG      += link_pkgconfig
#PKGCONFIG   += opencv4
#LIBS        += -L/usr/lib/x86_64-linux-gnu/ -lopencv_core -lopencv_highgui -lopencv_imgproc -lopencv_imgcodecs -lopencv_videoio
#INCLUDEPATH += /usr/include/opencv4/opencv2

main.cpp文件:

注意:如果没有相机,可以把下面的 v4l2src device=/dev/video0 换成 videotestsrc

#include <opencv2/opencv.hpp>int main() {// GStreamer pipeline字符串std::string pipeline = "v4l2src device=/dev/video0 ! video/x-raw, width=640, height=480 ! videoconvert ! video/x-raw,format=BGR ! appsink  sync=0 drop=1";// 使用 GStreamer 捕获视频流cv::VideoCapture cap(pipeline, cv::CAP_GSTREAMER);// 检查捕获是否成功打开if (!cap.isOpened()) {std::cout << "Error opening video stream" << std::endl;return -1;}// 读取并显示视频流cv::Mat frame;while (true) {cap >> frame;  // 从视频流中读取帧if (frame.empty()) break;  // 如果帧为空,则退出循环cv::imshow("Video", frame);  // 显示帧if (cv::waitKey(1) == 27) break;  // 按下 ESC 键退出循环}// 释放 VideoCapture 对象cap.release();cv::destroyAllWindows();return 0;
}

如果可以实现播放视频,就说明成功。

二、OpenCV运行gstreamer命令,通过appsink传递给OpenCV显示,然后通过appsrc传递回gstreamer,通过overlay绑定QWidget

pro文件: (相关的库,需要按照自己的配)

QT       += core gui # multimediawidgetsgreaterThan(QT_MAJOR_VERSION, 4): QT += widgets
DESTDIR = $$PWD/bin
CONFIG += c++11DEFINES += QT_DEPRECATED_WARNINGSSOURCES += \main.cpp# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += targetCONFIG      += link_pkgconfig
PKGCONFIG   += opencv4
LIBS        += -L/usr/lib/x86_64-linux-gnu/ -lopencv_core -lopencv_highgui -lopencv_imgproc -lopencv_imgcodecs -lopencv_videoio
INCLUDEPATH += /usr/include/opencv4/opencv2
#*************************************************CONFIG += link_pkgconfig
# 虚拟机环境:gstreamer************************
PKGCONFIG += gstreamer-1.0 gstreamer-plugins-base-1.0  opencv4  #gtk+-3.0
LIBS    += -lX11
LIBS    +=-lglib-2.0
LIBS    +=-lgobject-2.0
LIBS    +=-lgstreamer-1.0          # <gst/gst.h>
LIBS    +=-lgstvideo-1.0             # <gst/video/videooverlay.h>
LIBS    +=-L/usr/lib/x86_64-linux-gnu/gstreamer-1.0
LIBS    +=-lgstautodetect
LIBS    +=-lgstaudio-1.0
LIBS    +=-lgstapp-1.0
LIBS    += -L/usr/local/lib/ -lgstrtspserver-1.0
LIBS    += -ltesseractINCLUDEPATH += \/usr/include/glib-2.0 \/usr/lib/x86_64-linux-gnu/glib-2.0/include \/usr/include/gstreamer-1.0 \/usr/lib/x86_64-linux-gnu/gstreamer-1.0/include
# ************************************

main.cpp:

实现思路:

如上图所示,以下是部分源码:

1. OpenCV运行gstreamer命令管道:

// 开始捕获视频并发送到 appsrc   v4l2src device=/dev/video0cv::VideoCapture capture("v4l2src device=/dev/video0 ! video/x-raw, width=640, height=480 ! videoconvert ! video/x-raw,format=BGR ! appsink sync=0 drop=1", cv::CAP_GSTREAMER);cv::Mat orinFrame;gst_app_src_set_stream_type(GST_APP_SRC(appsrc), GST_APP_STREAM_TYPE_STREAM);

2. OpenCV显示接收到的图片,并且发送数据到appsrc,以供下一个gstreamer接收:

    while (capture.isOpened()) {capture.read(orinFrame);if (orinFrame.empty()) {break;}cv::imshow("Video", orinFrame);  // 显示原始帧// 其他处理:cv::Mat frame;frame = orinFrame;//cv::bitwise_not(orinFrame, frame);      // 反色//cv::GaussianBlur(orinFrame, frame, cv::Size(5, 5), 0);  //高斯模糊// 创建 GStreamer 缓冲区GstBuffer* buffer = gst_buffer_new_allocate(NULL, frame.total() * frame.elemSize(), NULL);GstMapInfo info;gst_buffer_map(buffer, &info, GST_MAP_WRITE);memcpy(info.data, frame.data, frame.total() * frame.elemSize());gst_buffer_unmap(buffer, &info);// 发送缓冲区到 appsrcGstFlowReturn ret = gst_app_src_push_buffer(GST_APP_SRC(appsrc), buffer);if (ret != GST_FLOW_OK) {g_printerr("Error pushing buffer to appsrc: %s\n", gst_flow_get_name(ret));}// 延时一段时间,模拟视频流cv::waitKey(30);}

3. 创建接收用的gstreamer管道,然后交给QWidget显示

    这里创建管道,有两种方式:

        1. 第一种是使用gst_parse_launch,然后通过gst_bin_get_by_name查找获取元素指针。

        2. 第二种是使用各种GstElement组合为管道。

    第一种:

// 使用gst_parse_launch// 创建 GStreamer 管道std::string pipeline_str = "appsrc name=source caps=\"video/x-raw,format=BGR,width=640,height=480\" ! videoconvert ! xvimagesink name=vsink2";GstElement* pipeline = gst_parse_launch(pipeline_str.c_str(), NULL);// 获取 appsrc 元素GstElement* appsrc = gst_bin_get_by_name(GST_BIN(pipeline), "source");GstElement* vsink2 = gst_bin_get_by_name(GST_BIN(pipeline), "vsink2");

    第二种:

    // 组合:GstElement* pipeline = gst_pipeline_new("test-pipeline");// 设置视频参数int width = 640;int height = 480;int fps = 30;// 创建 appsrc 元素GstElement* appsrc = gst_element_factory_make("appsrc", "video-source");// 创建 sink 元素GstElement* fpssink = gst_element_factory_make("fpsdisplaysink", "fpssink");GstElement* vsink = gst_element_factory_make("xvimagesink", "vsink");    //glimagesink  ximagesink  xvimagesinkGstElement* overlay = gst_element_factory_make("timeoverlay", "overlay");GstElement* converter = gst_element_factory_make("videoconvert", "converter");g_object_set(G_OBJECT(appsrc), "caps",gst_caps_new_simple("video/x-raw","format", G_TYPE_STRING, "BGR","width", G_TYPE_INT, width,"height", G_TYPE_INT, height,"framerate", GST_TYPE_FRACTION, fps, 1,NULL),"is-live", TRUE,"format", GST_FORMAT_TIME,NULL);// 连接 appsrc 元素和 glimagesink 元素gst_bin_add_many(GST_BIN(pipeline),appsrc, converter, vsink, NULL);if (!gst_element_link_many(appsrc, converter, vsink, NULL)) {g_printerr("Failed to link appsrc and fpssink!\n");gst_object_unref(pipeline);return -1;}

4. 链接QT界面,并且启动管道:

    // 链接QT界面gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (vsink2), xwinid);// 启动管道GstStateChangeReturn state_ret = gst_element_set_state(pipeline, GST_STATE_PLAYING);if (state_ret == GST_STATE_CHANGE_FAILURE) {g_printerr("Failed to start pipeline!\n");gst_object_unref(pipeline);return -1;}

注意事项:

  1. 接收用的gstreamer管道,其实不用QWidget链接也可,链接了只是为了方便以后扩展添加各种控件的,比如按钮和标签那些。
  2. 接收用的gstreamer管道,caps一定是给appsrc设置的。
  3. 接收用的gstreamer管道,fpsdisplaysink、timeoverlay等很多插件,都无法正常使用,目前不知道是哪里的问题。

完整代码:


#include <QApplication>
#include <QMainWindow>
#include <opencv2/opencv.hpp>
#include <gst/gst.h>
#include <gst/app/gstappsrc.h>
#include <gst/video/videooverlay.h>int main(int argc, char *argv[]) {QApplication app(argc, argv);// 初始化 GStreamerGMainLoop *loop;// 设置 GStreamer 调试环境变量//g_setenv("GST_DEBUG", "4", TRUE);gst_init(&argc, &argv);loop = g_main_loop_new (NULL, FALSE);// 创建窗口QWidget *window = new QWidget();window->resize(640, 480);window->show();WId xwinid = window->winId();#if 1// 使用gst_parse_launch// 创建 GStreamer 管道std::string pipeline_str = "appsrc name=source caps=\"video/x-raw,format=BGR,width=640,height=480\" ! videoconvert ! xvimagesink name=vsink2";GstElement* pipeline = gst_parse_launch(pipeline_str.c_str(), NULL);// 获取 appsrc 元素GstElement* appsrc = gst_bin_get_by_name(GST_BIN(pipeline), "source");GstElement* vsink2 = gst_bin_get_by_name(GST_BIN(pipeline), "vsink2");//GstElement* vsink = gst_element_factory_make("glimagesink", "vsink");//g_object_set (vsink2, "video-sink", vsink, NULL);
#else// 组合:GstElement* pipeline = gst_pipeline_new("test-pipeline");// 设置视频参数int width = 640;int height = 480;int fps = 30;// 创建 appsrc 元素GstElement* appsrc = gst_element_factory_make("appsrc", "video-source");// 创建 sink 元素GstElement* fpssink = gst_element_factory_make("fpsdisplaysink", "fpssink");GstElement* vsink = gst_element_factory_make("xvimagesink", "vsink");    //glimagesink  ximagesink  xvimagesinkGstElement* overlay = gst_element_factory_make("timeoverlay", "overlay");GstElement* converter = gst_element_factory_make("videoconvert", "converter");g_object_set(G_OBJECT(appsrc), "caps",gst_caps_new_simple("video/x-raw","format", G_TYPE_STRING, "BGR","width", G_TYPE_INT, width,"height", G_TYPE_INT, height,"framerate", GST_TYPE_FRACTION, fps, 1,NULL),"is-live", TRUE,"format", GST_FORMAT_TIME,NULL);// 连接 appsrc 元素和 glimagesink 元素gst_bin_add_many(GST_BIN(pipeline),appsrc, converter, vsink, NULL);if (!gst_element_link_many(appsrc, converter, vsink, NULL)) {g_printerr("Failed to link appsrc and fpssink!\n");gst_object_unref(pipeline);return -1;}#endif// 链接QT界面gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (vsink2), xwinid);// 启动管道GstStateChangeReturn state_ret = gst_element_set_state(pipeline, GST_STATE_PLAYING);if (state_ret == GST_STATE_CHANGE_FAILURE) {g_printerr("Failed to start pipeline!\n");gst_object_unref(pipeline);return -1;}// 开始捕获视频并发送到 appsrc   v4l2src device=/dev/video0cv::VideoCapture capture("v4l2src device=/dev/video0 ! video/x-raw, width=640, height=480 ! videoconvert ! video/x-raw,format=BGR ! appsink sync=0 drop=1", cv::CAP_GSTREAMER);cv::Mat orinFrame;gst_app_src_set_stream_type(GST_APP_SRC(appsrc), GST_APP_STREAM_TYPE_STREAM);while (capture.isOpened()) {capture.read(orinFrame);if (orinFrame.empty()) {break;}cv::imshow("Video", orinFrame);  // 显示原始帧// 其他处理:cv::Mat frame;frame = orinFrame;//cv::bitwise_not(orinFrame, frame);      // 反色//cv::GaussianBlur(orinFrame, frame, cv::Size(5, 5), 0);  //高斯模糊// 创建 GStreamer 缓冲区GstBuffer* buffer = gst_buffer_new_allocate(NULL, frame.total() * frame.elemSize(), NULL);GstMapInfo info;gst_buffer_map(buffer, &info, GST_MAP_WRITE);memcpy(info.data, frame.data, frame.total() * frame.elemSize());gst_buffer_unmap(buffer, &info);// 发送缓冲区到 appsrcGstFlowReturn ret = gst_app_src_push_buffer(GST_APP_SRC(appsrc), buffer);if (ret != GST_FLOW_OK) {g_printerr("Error pushing buffer to appsrc: %s\n", gst_flow_get_name(ret));}// 延时一段时间,模拟视频流cv::waitKey(30);}// 停止视频捕获capture.release();// 启动管道gst_element_set_state(pipeline, GST_STATE_PLAYING);// 主循环app.exec();// 停止管道gst_element_set_state(pipeline, GST_STATE_NULL);gst_object_unref(pipeline);return 0;
}

效果:

三、其他:灰度化、高斯模糊、人脸识别

#include <QApplication>
#include <QMainWindow>
#include <opencv2/opencv.hpp>
#include <gst/gst.h>
#include <gst/app/gstappsrc.h>
#include <gst/video/videooverlay.h>#include <opencv2/core.hpp>
#include <opencv2/dnn.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
using namespace std;
using namespace cv;
using namespace cv::dnn;
int main(int argc, char *argv[]) {QApplication app(argc, argv);// 初始化 GStreamerGMainLoop *loop;// 设置 GStreamer 调试环境变量//g_setenv("GST_DEBUG", "4", TRUE);gst_init(&argc, &argv);loop = g_main_loop_new (NULL, FALSE);// 创建窗口QWidget *window = new QWidget();window->resize(640, 480);window->show();WId xwinid = window->winId();#if 1// 使用gst_parse_launch// 创建 GStreamer 管道std::string pipeline_str = "appsrc name=source caps=\"video/x-raw,format=BGR,width=640,height=480\" ! videoconvert ! xvimagesink name=vsink2";GstElement* pipeline = gst_parse_launch(pipeline_str.c_str(), NULL);// 获取 appsrc 元素GstElement* appsrc = gst_bin_get_by_name(GST_BIN(pipeline), "source");GstElement* vsink2 = gst_bin_get_by_name(GST_BIN(pipeline), "vsink2");//GstElement* vsink = gst_element_factory_make("glimagesink", "vsink");//g_object_set (vsink2, "video-sink", vsink, NULL);
#else// 组合:GstElement* pipeline = gst_pipeline_new("test-pipeline");// 设置视频参数int width = 640;int height = 480;int fps = 30;// 创建 appsrc 元素GstElement* appsrc = gst_element_factory_make("appsrc", "video-source");// 创建 sink 元素GstElement* fpssink = gst_element_factory_make("fpsdisplaysink", "fpssink");GstElement* vsink = gst_element_factory_make("xvimagesink", "vsink");    //glimagesink  ximagesink  xvimagesinkGstElement* overlay = gst_element_factory_make("timeoverlay", "overlay");GstElement* converter = gst_element_factory_make("videoconvert", "converter");g_object_set(G_OBJECT(appsrc), "caps",gst_caps_new_simple("video/x-raw","format", G_TYPE_STRING, "BGR","width", G_TYPE_INT, width,"height", G_TYPE_INT, height,"framerate", GST_TYPE_FRACTION, fps, 1,NULL),"is-live", TRUE,"format", GST_FORMAT_TIME,NULL);// 连接 appsrc 元素和 glimagesink 元素gst_bin_add_many(GST_BIN(pipeline),appsrc, converter, vsink, NULL);if (!gst_element_link_many(appsrc, converter, vsink, NULL)) {g_printerr("Failed to link appsrc and fpssink!\n");gst_object_unref(pipeline);return -1;}#endif// 链接QT界面gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (vsink2), xwinid);// 启动管道GstStateChangeReturn state_ret = gst_element_set_state(pipeline, GST_STATE_PLAYING);if (state_ret == GST_STATE_CHANGE_FAILURE) {g_printerr("Failed to start pipeline!\n");gst_object_unref(pipeline);return -1;}// 开始捕获视频并发送到 appsrc   v4l2src device=/dev/video0cv::VideoCapture capture("v4l2src device=/dev/video0 ! video/x-raw, width=640, height=480 ! videoconvert ! video/x-raw,format=BGR ! appsink sync=0 drop=1", cv::CAP_GSTREAMER);cv::Mat orinFrame;gst_app_src_set_stream_type(GST_APP_SRC(appsrc), GST_APP_STREAM_TYPE_STREAM);// 加载CNN模型//Net net = readNetFromTensorflow("tensorflow_inception_graph.pb");while (capture.isOpened()) {capture.read(orinFrame);if (orinFrame.empty()) {break;}cv::imshow("Video", orinFrame);  // 显示原始帧// 其他处理:cv::Mat frame;frame = orinFrame;//cv::bitwise_not(orinFrame, frame);      // 反色//cv::GaussianBlur(orinFrame, frame, cv::Size(5, 5), 0);  // 高斯模糊//cv::cvtColor(orinFrame, frame, cv::COLOR_BGR2GRAY);      // 灰度化// 识别:*********************************************************CascadeClassifier faceCascade;if (!faceCascade.load("/usr/share/opencv4/haarcascades/haarcascade_frontalface_alt.xml")){std::cerr << "Error loading face cascade file!" << std::endl;return -1;}//Mat frame(480, 640, CV_8UC3, Scalar(0, 0, 255)); // 模拟输入图片数据,这里使用红色图片代替resize(frame, frame, Size(640, 480));Mat frameGray;cvtColor(frame, frameGray, COLOR_BGR2GRAY);equalizeHist(frameGray, frameGray);std::vector<Rect> faces;faceCascade.detectMultiScale(frameGray, faces);for (const auto& face : faces){rectangle(frame, face, Scalar(255, 0, 0), 2); // 绘制人脸框}//*****************************************************************// 创建 GStreamer 缓冲区GstBuffer* buffer = gst_buffer_new_allocate(NULL, frame.total() * frame.elemSize(), NULL);GstMapInfo info;gst_buffer_map(buffer, &info, GST_MAP_WRITE);memcpy(info.data, frame.data, frame.total() * frame.elemSize());gst_buffer_unmap(buffer, &info);// 发送缓冲区到 appsrcGstFlowReturn ret = gst_app_src_push_buffer(GST_APP_SRC(appsrc), buffer);if (ret != GST_FLOW_OK) {g_printerr("Error pushing buffer to appsrc: %s\n", gst_flow_get_name(ret));}// 延时一段时间,模拟视频流cv::waitKey(30);}// 停止视频捕获capture.release();// 启动管道gst_element_set_state(pipeline, GST_STATE_PLAYING);// 主循环app.exec();// 停止管道gst_element_set_state(pipeline, GST_STATE_NULL);gst_object_unref(pipeline);return 0;
}

效果:

四、其他待补充

        时间有限,待补充,大家有想法,欢迎一起交流!

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

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

相关文章

Java入门及环境变量

文章目录 1.1 Java简介1.2 JDK的下载和安装1.3 第一个程序1.4 常见问题1.5 常用DOS命令1.6 Path环境变量 1.1 Java简介 下面我们正式进入Java的学习&#xff0c;在这里&#xff0c;大家第一个关心的问题&#xff0c;应该就是 Java 是什么&#xff0c;我们一起来看一下&#xf…

ktutil编写生成keytab文件的脚本、通过keytab文件认证用户

文章目录 1. 生成keytab文件脚本2. 通过keytab文件认证3. 查看认证的用户4. 失效认证的用户 1. 生成keytab文件脚本 生成keytab文件的脚本 vim generate_kb.sh #!/usr/bin/bash ktutil <<EOF add_entry -password -p $1 -k 1 -e arcfour-hmac $2 write_kt $3 EOF示例&am…

C语言系列-带有副作用的宏参数#和##命名约定宏替换的规则

&#x1f308;个人主页: 会编辑的果子君 &#x1f4ab;个人格言:“成为自己未来的主人~” 目录 带有副作用的宏参数 宏替换的规则 宏函数的对比 #和## #运算符 ##运算符 命名约定 #undef 带有副作用的宏参数 当宏参数在宏的定义中出现超过一次的时候&#xff0c;如果…

Offer必备算法07_递归_五道力扣题详解(由易到难)

目录 递归算法原理 ①力扣面试题 08.06. 汉诺塔问题 解析代码 ②力扣21. 合并两个有序链表 解析代码 ③力扣206. 反转链表 解析代码 ④力扣24. 两两交换链表中的节点 解析代码 ⑤力扣50. Pow(x, n) 解析代码 本篇完。 递归算法原理 递归算法个人经验&#xff1a;给…

PHP支持的伪协议

php.ini参数设置 在php.ini里有两个重要的参数allow_url_fopen、allow_url_include。 allow_url_fopen:默认值是ON。允许url里的封装协议访问文件&#xff1b; allow_url_include:默认值是OFF。不允许包含url里的封装协议包含文件&#xff1b; 各协议的利用条件和方法 php:/…

数据结构OJ题——top-k问题:最小的K个数(Java实现)

题目链接&#xff1a;top-k问题&#xff1a;最小的K个数 top-k问题&#xff1a;最小的K个数假 1.方法一2.方法二时间复杂度 3.方法三时间复杂度 1.方法一 各种排序算法&#xff08;由于本文主要讲有关堆的使用&#xff0c;这里不做有关排序算法解决本题的介绍。对于Top-K问题…

linux(阿里云)安装pytorch

目录 环境 安装步骤 1 检查python3和pip3是否已经安装 2 安装pytorch 3 安装完毕&#xff0c;检查pytorch版本 环境 阿里云 ubuntu 22.04 UEFI版 64位 安装步骤 1 检查python3和pip3是否已经安装 输入下面两条指令&#xff1a; python3 --version pip --version 检…

1Panel使用GMSSL+Openresty实现国密/RSA单向自适应

本文 首发于 Anyeの小站&#xff0c;转载请取得作者同意。 前言 国密算法是国家商用密码算法的简称。自2012年以来&#xff0c;国家密码管理局以《中华人民共和国密码行业标准》的方式&#xff0c;陆续公布了SM2/SM3/SM4等密码算法标准及其应用规范。其中“SM”代表“商密”&a…

ChatGPT对软件测试的影响!

ChatGPT 是一个经过预训练的 AI 语言模型&#xff0c;可以通过聊天的方式回答问题&#xff0c;或者与人闲聊。它能处理的是文本类的信息&#xff0c;输出也只能是文字。它从我们输入的信息中获取上下文&#xff0c;结合它被训练的大模型&#xff0c;进行分析总结&#xff0c;给…

【C++杂货铺】string详解

目录 1. 基本概念&#xff1a; 1.1 本质&#xff1a; 1.2 string和char*区别&#xff1a; 1.3 特点&#xff1a; 2. 构造函数(初始化) 3. 赋值操作 4. 字符串拼接 5 查找 和 替换 6. 字符串比较 7. 字符存取 8. 插入和删除 ​9. 子串获取 &#x1f308;前言&#x…

Rocky Linux网卡静态配置

一、开源系统 Rocky Linux 下载安装 1、安装教程 Rocky Linux 下载安装 二、远程工具 MobaXterm下载安装 1、安装教程 MobaXterm 下载安装 三、Rocky Linux 网卡配置 1、使用ip addr确认网卡名称&#xff08;此处可得知网卡为ens160&#xff09; [rootlocalhost ~]# ip a 1:…

23款奔驰GLE350升级小柏林音响 安装效果分享

小柏林之声音响是13个喇叭1个功放&#xff0c;功率是590W&#xff0c;对应普通音响来说&#xff0c;已经是上等了。像著名的哈曼卡顿音响&#xff0c;还是丹拿音响&#xff0c;或者是BOSE音响&#xff0c;论地位&#xff0c;论音质柏林之声也是名列前茅。星骏汇小许Xjh15863 升…

2.C语言——输入输出

1.字符输入输出函数 1.输入:getchar() 字面意思&#xff0c;接收单个字符&#xff0c;使用方法 char a; a getchar();实际上效果等同于char a; scanf("%c",&a);2.输出:putchar() 2.格式化输入输出函数 1.输入:scanf() 格式&#xff1a; scanf(“格式控制…

Axes属性汇总

Axes属性很多&#xff0c;主要起控制坐标区的外观和行为的作用&#xff0c;共涉及十三类。 第1类&#xff1a;字体 Font Name——字体名称&#xff0c;默认为’Helvetica’。 要使用在任何区域设置中都有较好显示效果的等宽字体&#xff0c;请使用 “FixedWidth”。等宽字体依…

系统测试计划(直接套用实际)

1测试目的 2测试范围 3资源要求 3.1人力资源 3.2指派干系人 3.3测试环境 3.4测试工具 4测试类型 5测试安排 5.1测试进度 5.2测试策略 5.2.1测试需求 5.2.2测试类型 6测试停止标准 7测试风险 8缺陷管理 8.1缺陷属性 8.2缺陷类型 8.3缺陷严重程度 8.4缺陷优先级 8.5缺陷状态 8.6缺…

C#上位机与三菱PLC的通信07--使用第3方通讯库读写数据

1、通讯库介绍 mcprotocol 是一个基于 Node.js 的三菱 PLC MC 协议通信库&#xff0c;具有以下特点&#xff1a; 支持多种三菱 PLC MC 协议的设备&#xff0c;如 FX3U、Q03UDECPU、QJ71E71 等。 支持多种功能码和数据类型&#xff0c;如读取线圈&#xff08;M&#xff09;、…

[AIGC] 利用 chatgpt 深入理解 Java 虚拟机(JVM)

Java 虚拟机&#xff08;JVM&#xff09;是 Java 编程语言的核心运行环境&#xff0c;它负责解释和执行 Java 字节码。它是 Java 程序能够跨平台运行的关键&#xff0c;因为不同的操作系统和硬件平台都有自己的指令集和体系结构&#xff0c;而 JVM 则提供了一个统一的运行环境&…

硬核!10分钟教你搭建一个本地版GPT4.0!

今天10分钟手把手教会你在自己电脑上搭建一个官方原版的GPT4.0。 不用ChatGPT账号&#xff0c;不用API&#xff0c;直接免费使用上官方原版的GPT4.0&#xff01; 对&#xff01;你没看错&#xff01;不仅是正版GPT4.0&#xff0c;还完全免费&#xff01; 而且整个部署流程极其简…

java根据前端所要格式返回树形3级层级数据

一、业务分析&#xff0c;根据前端需求返回如下数据格式 二、后端设计数据类型VO /*** author TTc* version 1.0* date 2024/2/15 16:47*/ Data AllArgsConstructor NoArgsConstructor public class Catalog2Vo {/*** 一级父分类的 id*/private String catalog1Id;/*** 三级子…

C# 12 中新增的八大功能你都知道吗?

一、主构造函数 在 Visual Studio 2022 版本 17.6 预览版 2 中引入。 从 C# 12 开始&#xff0c;可以在类和结构中声明主构造函数。主构造函数参数都在类的整个主体的范围内。为了确保显式分配所有主构造函数参数&#xff0c;所有显式声明的构造函数都必须使用 this() 语法调用…