opencv(C++)基础用法


文章目录

  • 前言
  • 一、opencv (C++)图片基本操作
    • 1.1 读取图片并显示
    • 1.2 颜色转换
    • 1.3 图像filtering
    • 1.4 形状调整
    • 1.5 绘制
  • 二、读取视频文件并显示
  • 三、RTSP 视频流
  • 四. 人脸检测
  • 总结


前言

学习笔记


一、opencv (C++)图片基本操作

1.1 读取图片并显示

#include "opencv2/opencv.hpp"
#include <iostream>int main(int argc,char** argv)
{//读取图片,mat是matrix的缩写,是一个矩阵cv::Mat image = cv::imread("./media/cat.jpg");//判断是否读取成功if (image.empty()){std::cout<<"Could not read the image:" <<std::endl;return 1;}//打印图片高度和宽度std::cout<<"height"<<image.rows<<"width"<<image.cols<<std::endl;//用numpy格式展示图片std::cout<<"data"<<cv::format(image,cv::Formatter::FMT_NUMPY)<<std::endl;//用python 列表格式展示图片std::cout<<"data"<<cv::format(image,cv::Formatter::FMT_PYTHON)<<std::endl;cv::Mat gray;cv::cvtColor(image,gray,cv::COLOR_BGR2GRAY);cv::imshow("image",image);cv::waitKey(0);cv::imwrite("./output/gray.jpg",gray);
}

必须在vscode里面展示,不能在服务器上,服务器上没有窗口,或者保存成图片文件查看

在这里插入图片描述

1.2 颜色转换

#include "opencv2/opencv.hpp"
#include <iostream>int main()
{cv::Mat src = cv::imread("./media/dog.jpg");cv::Mat gray;cv::cvtColor(src,gray,cv::COLOR_BGR2GRAY);cv::Mat hsv;cv::cvtColor(src,hsv,cv::COLOR_BGR2HSV);cv::Mat rgb;cv::cvtColor(src,rgb,cv::COLOR_BGR2RGB);cv::imwrite("./output/1.gray.jpg",gray);cv::imwrite("./output/1.hsv.jpg",hsv);cv::imwrite("./output/1.rgb.jpg",rgb);return 0;}

在这里插入图片描述
在这里插入图片描述

1.3 图像filtering

#include <iostream>
#include <opencv2/opencv.hpp>int main()
{cv::Mat src = cv::imread("./media/dog.jpg");//模糊cv::Mat blur;// 三个参数分别是输入图像、输出图像、卷积核大小cv::GaussianBlur(src,blur,cv::Size(7,7),0);// 膨胀cv::Mat dilate; cv::dilate(src,dilate,cv::getStructuringElement(cv::MORPH_RECT,cv::Size(5,5)));//腐蚀cv::Mat erode;cv::erode(src,erode,cv::getStructuringElement(cv::MORPH_RECT,cv::Size(5,5)));cv::imwrite("./output/blur.jpg",blur);cv::imwrite("./output/dilate.jpg",dilate);cv::imwrite("./output/erode.jpg",erode);return 0;}

在这里插入图片描述
在这里插入图片描述

1.4 形状调整

// 形状调整
#include "opencv2/opencv.hpp"
#include <iostream>
#include <vector>int main()
{// 读取图像cv::Mat cat_img = cv::imread("./media/cat.jpg");// ======== resize ========cv::Mat cat_resize;// 三个参数分别是输入图像、输出图像、输出图像大小cv::resize(cat_img, cat_resize, cv::Size(320, 240));// 保存cv::imwrite("./output/3.cat_resize.jpg", cat_resize);// ======== copy ========cv::Mat copy;cat_img.copyTo(copy);cv::imwrite("./output/3.copy.jpg", copy);// ======== ROI裁剪 ========cv::Rect rect(100, 100, 200, 100); // x, y, width, heightcv::Mat roi = cat_img(rect);cv::imwrite("./output/3.roi.jpg", roi);// ======== 拼接 ========cv::Mat dog_img = cv::imread("./media/dog.jpg");cv::Mat dog_resize;cv::resize(dog_img, dog_resize, cv::Size(320, 240));// 水平拼接,需要保证两张图片的高度(rows)一致cv::Mat hconcat_img;cv::hconcat(cat_resize, dog_resize, hconcat_img);cv::imwrite("./output/3.hconcat.jpg", hconcat_img);// 或者使用vector方式std::vector<cv::Mat> imgs{cat_resize, dog_resize, cat_resize, dog_resize};cv::Mat hconcat_img2;cv::hconcat(imgs, hconcat_img2);cv::imwrite("./output/3.hconcat2.jpg", hconcat_img2);// 数组方式cv::Mat imgs_arr[] = {dog_resize, cat_resize, dog_resize, cat_resize};cv::Mat hconcat_img3;cv::hconcat(imgs_arr, 4, hconcat_img3); // 4是数组长度cv::imwrite("./output/3.hconcat3.jpg", hconcat_img3);// 垂直拼接,需要保证两张图片的宽度(cols)一致cv::Mat vconcat_img;cv::vconcat(cat_resize, dog_resize, vconcat_img);cv::imwrite("./output/3.vconcat.jpg", vconcat_img);// ======== 翻转 ========cv::Mat flip;// 三个参数分别是输入图像、输出图像、翻转方向cv::flip(cat_img, flip, 1); // 1表示水平翻转,0表示垂直翻转,-1表示水平垂直翻转cv::imwrite("./output/3.flip.jpg", flip);// ======== 旋转 ========cv::Mat rotate;// 三个参数分别是输入图像、输出图像、旋转角度cv::rotate(cat_img, rotate, cv::ROTATE_90_CLOCKWISE); // 顺时针旋转90度cv::imwrite("./output/3.rotate.jpg", rotate);return 0;
}

1.5 绘制

// 绘制文字和图形
#include "opencv2/opencv.hpp"
#include <iostream>
#include <vector>int main()
{// 创建一个黑色图像,参数分别是图像大小、图像类型,CV_8UC3表示8位无符号整数,3通道cv::Mat image = cv::Mat::zeros(cv::Size(600, 600), CV_8UC3);// 绘制直线,参数分别是图像、起点、终点、颜色、线宽、线型cv::line(image, cv::Point(50, 50), cv::Point(350, 250), cv::Scalar(0, 0, 255), 2, cv::LINE_AA);// 绘制矩形,参数分别是图像、左上角、右下角、颜色、线宽、线型cv::rectangle(image, cv::Point(50, 50), cv::Point(350, 250), cv::Scalar(0, 255, 0), 2, cv::LINE_AA);// 绘制圆形,参数分别是图像、圆心、半径、颜色、线宽、线型cv::circle(image, cv::Point(200, 150), 100, cv::Scalar(255, 0, 0), 2, cv::LINE_AA);// 实心cv::circle(image, cv::Point(200, 150), 50, cv::Scalar(255, 0, 0), -1, cv::LINE_AA);// // ================== 多边形 ==================// cv::Point points[2][4]; // 定义两个多边形的顶点数组// // 第一个多边形的顶点// points[0][0] = cv::Point(100, 115);// points[0][1] = cv::Point(255, 135);// points[0][2] = cv::Point(140, 365);// points[0][3] = cv::Point(100, 300);// // 第二个多边形的顶点// points[1][0] = cv::Point(300, 315);// points[1][1] = cv::Point(555, 335);// points[1][2] = cv::Point(340, 565);// points[1][3] = cv::Point(300, 500);// // ppt[] 要同时添加两个多边形顶点数组的地址)// const cv::Point *pts_v[] = {points[0], points[1]};// // npts_v[]要定义每个多边形的顶点数// int npts_v[] = {4, 4};// // 绘制多边形,参数分别是图像、顶点数组、顶点数、曲线数量、是否闭合、颜色、线宽、线型// cv::polylines(image, pts_v, npts_v, 2, true, cv::Scalar(255, 0, 255), 2, 8, 0);// ================== 使用vector绘制多边形 ==================std::vector<cv::Point> points_v;// 随机生成5个点for (int i = 0; i < 5; i++){points_v.push_back(cv::Point(rand() % 600, rand() % 600));}// 绘制多边形,参数分别是图像、顶点容器、是否闭合、颜色、线宽、线型cv::polylines(image, points_v, true, cv::Scalar(255, 0, 0), 2, 8, 0);// ================== 绘制文字 ==================// 参数分别是图像、文字、文字位置、字体、字体大小、颜色、线宽、线型cv::putText(image, "Hello World!", cv::Point(400, 50), cv::FONT_HERSHEY_SIMPLEX, 1.0, cv::Scalar(255, 255, 255), 2, 8, 0);// 保存cv::imwrite("./output/4.drawing.jpg", image);return 0;
}

在这里插入图片描述

二、读取视频文件并显示

// 导入opencv 库
#include <opencv2/opencv.hpp>
#include <iostream>
// 导入gflags 库
#include <gflags/gflags.h>
// 定义命令行参数
DEFINE_string(video, "./media/dog.mp4", "Input video"); // 视频路径int main(int argc, char **argv)
{// 解析命令行参数gflags::ParseCommandLineFlags(&argc, &argv, true);// 读取视频:创建了一个VideoCapture对象,参数为视频路径cv::VideoCapture capture(FLAGS_video);// 判断视频是否读取成功,返回true表示成功if (!capture.isOpened()){std::cout << "无法读取视频: " << FLAGS_video << std::endl;return 1;}// 读取视频帧,使用Mat类型的frame存储返回的帧cv::Mat frame;// 灰度图cv::Mat gray_frame;// 循环读取视频帧while (true){// 读取视频帧,使用 >> 运算符或者read()函数,他的参数是返回的帧capture.read(frame);// capture >> frame;// 判断是否读取成功if (frame.empty()){std::cout << "文件读取完毕" << std::endl;break;}// 转成灰度图cv::cvtColor(frame, gray_frame, cv::COLOR_BGR2GRAY);// 显示视频帧cv::imshow("raw frame", frame);cv::imshow("gray frame", gray_frame);// 等待按键,延迟30ms,否则视频播放太快int k = cv::waitKey(30);// 按下ESC键退出if (k == 27){std::cout << "退出" << std::endl;break;}}return 0;
}

在这里插入图片描述

读取摄像头并写入文件

// 导入opencv 库
#include <opencv2/opencv.hpp>
#include <iostream>
// 导入gflags 库
#include <gflags/gflags.h>
// 定义命令行参数
DEFINE_int32(camera, 0, "Input camera"); // 摄像头编号int main(int argc, char **argv)
{// 解析命令行参数gflags::ParseCommandLineFlags(&argc, &argv, true);// 读取视频:创建了一个VideoCapture对象,参数为摄像头编号cv::VideoCapture capture(FLAGS_camera);// 设置指定摄像头的分辨率int width = 640;int height = 480;// 设置摄像头宽度和高度capture.set(cv::CAP_PROP_FRAME_WIDTH, width);capture.set(cv::CAP_PROP_FRAME_HEIGHT, height);// 判断视频是否读取成功,返回true表示成功if (!capture.isOpened()){std::cout << "无法打开摄像头: " << FLAGS_camera << std::endl;return 1;}// 读取视频帧,使用Mat类型的frame存储返回的帧cv::Mat frame;// 写入MP4文件,参数分别是:文件名,编码格式,帧率,帧大小cv::VideoWriter writer("./output/record.mp4", cv::VideoWriter::fourcc('H', '2', '6', '4'), 20, cv::Size(width, height));// 循环读取视频帧while (true){// 读取视频帧,使用 >> 运算符或者read()函数,他的参数是返回的帧capture.read(frame);// capture >> frame;// flipcv::flip(frame, frame, 1);// 显示视频帧cv::imshow("opencv demo", frame);// 写入视频writer.write(frame);// 等待按键,延迟30ms,否则视频播放太快int k = cv::waitKey(30);// 按下ESC键退出if (k == 27){std::cout << "退出" << std::endl;break;}}return 0;
}

在这里插入图片描述

三、RTSP 视频流

本机构造RTSP视频流(optional)

# Ubuntu安装ffmpegsudo apt-get install ffmpeg# 赋予权限chmod +x rtsp-simple-serverchmod +x start_server.sh# 运行服务./start_server.sh# 退出服务pkill rtsp-simple-serverpkill ffmpeg

用于启动多个视频流服务器和ffmpeg流媒体转发器。它的作用是将四个mp4视频文件以rtsp协议和tcp传输方式推送到本地的rtsp服务器上。同时,还启动了ffserver服务器来接收来自ffmpeg的流媒体流,并将其转发到指定的端口上。
start_server.sh

#ffserver -f server1.conf &
#ffserver -f server2.conf &
#ffserver -f server3.conf &
#ffserver -f server4.conf &
#ffmpeg -i 1.mp4 -vcodec libx264 -tune zerolatency -crf 18 http://localhost:1234/feed1.ffm &
#ffmpeg -i 2.mp4 -vcodec libx264 -tune zerolatency -crf 18 http://localhost:1235/feed2.ffm &
#ffmpeg -i 3.mp4 -vcodec libx264 -tune zerolatency -crf 18 http://localhost:1236/feed3.ffm &
#ffmpeg -i 4.mp4 -vcodec libx264 -tune zerolatency -crf 18 http://localhost:1237/feed4.ffm &
./rtsp-simple-server rtsp_server.yml &
ffmpeg -re -stream_loop -1 -i 1.mp4 -vcodec copy -acodec copy -f rtsp -rtsp_transport tcp rtsp://localhost:8554/live1.sdp &
ffmpeg -re -stream_loop -1 -i 2.mp4 -vcodec copy -acodec copy -f rtsp -rtsp_transport tcp rtsp://localhost:8554/live2.sdp &
ffmpeg -re -stream_loop -1 -i 3.mp4 -vcodec copy -acodec copy -f rtsp -rtsp_transport tcp rtsp://localhost:8554/live3.sdp &
ffmpeg -re -stream_loop -1 -i 4.mp4 -vcodec copy -acodec copy -f rtsp -rtsp_transport tcp rtsp://localhost:8554/live4.sdp &

使用OpenCV库来读取和显示四个RTSP视频流,并将它们拼接成一个单一的窗口

#include <opencv2/opencv.hpp>
#include <iostream>
#include <string>int main(int argc, char **argv)
{// Ubuntu安装ffmpeg:sudo apt-get install ffmpeg// rtsp地址变量// 一般main 主码流,sub 子码流std::string rtsp1 = "rtsp://admin:SEGJKL@192.168.1.185:554/h264/ch1/sub/av_stream";std::string rtsp2 = rtsp1;std::string rtsp3 = rtsp1;std::string rtsp4 = rtsp1;// std::string rtsp1 = "rtsp://localhost:8554/live1.sdp";// std::string rtsp2 = "rtsp://localhost:8554/live2.sdp";// std::string rtsp3 = "rtsp://localhost:8554/live3.sdp";// std::string rtsp4 = "rtsp://localhost:8554/live4.sdp";// CAP_FFMPEG:使用ffmpeg解码cv::VideoCapture stream1 = cv::VideoCapture(rtsp1, cv::CAP_FFMPEG);cv::VideoCapture stream2 = cv::VideoCapture(rtsp2, cv::CAP_FFMPEG);cv::VideoCapture stream3 = cv::VideoCapture(rtsp3, cv::CAP_FFMPEG);cv::VideoCapture stream4 = cv::VideoCapture(rtsp4, cv::CAP_FFMPEG);if (!stream1.isOpened() || !stream2.isOpened() || !stream3.isOpened() || !stream4.isOpened()){std::cout << "有视频流未打开" << std::endl;return -1;}cv::Mat frame1;cv::Mat frame2;cv::Mat frame3;cv::Mat frame4;cv::Mat H1, H2, V;// 使用namedWindow创建窗口,WINDOW_AUTOSIZE:自动调整窗口大小cv::namedWindow("rtsp_demo", cv::WINDOW_AUTOSIZE);while (true){if (!stream1.read(frame1) || !stream2.read(frame2) || !stream3.read(frame3) || !stream4.read(frame4)){std::cout << "有视频流未读取" << std::endl;continue;}// 缩放等处理cv::resize(frame1, frame1, cv::Size(500, 300));cv::resize(frame2, frame2, cv::Size(500, 300));cv::flip(frame2, frame2, 1);cv::resize(frame3, frame3, cv::Size(500, 300));cv::cvtColor(frame1, frame1, cv::COLOR_BGR2GRAY);cv::cvtColor(frame1, frame1, cv::COLOR_GRAY2BGR);cv::resize(frame4, frame4, cv::Size(500, 300));cv::putText(frame4, "RTSP demo", cv::Point(100, 100), cv::FONT_ITALIC, 1, cv::Scalar(0, 0, 255), 2);// 拼接cv::hconcat(frame1, frame2, H1);cv::hconcat(frame3, frame4, H2);cv::vconcat(H1, H2, V);cv::imshow("rtsp_demo", V);if (cv::waitKey(1) == 27){break;}}return 0;
}

四. 人脸检测

#include "opencv2/opencv.hpp"
#include <iostream>// 初始化模型
const std::string tensorflowConfigFile = "./weights/opencv_face_detector.pbtxt";
const std::string tensorflowWeightFile = "./weights/opencv_face_detector_uint8.pb";
cv::dnn::Net net = cv::dnn::readNetFromTensorflow(tensorflowWeightFile, tensorflowConfigFile);// 检测并绘制矩形框
void detectDrawRect(cv::Mat &frame)
{// 获取图像的宽高int frameHeight = frame.rows;int frameWidth = frame.cols;// 预处理,resize + swapRB + mean + scalecv::Mat inputBlob = cv::dnn::blobFromImage(frame, 1.0, cv::Size(300, 300), cv::Scalar(104.0, 177.0, 123.0), false, false);// 推理net.setInput(inputBlob, "data");cv::Mat detection = net.forward("detection_out");// 获取结果cv::Mat detectionMat(detection.size[2], detection.size[3], CV_32F, detection.ptr<float>());// 遍历多个人脸结果for (int i = 0; i < detectionMat.rows; i++){// 置信度float confidence = detectionMat.at<float>(i, 2);if (confidence > 0.2){// 两点坐标int l = static_cast<int>(detectionMat.at<float>(i, 3) * frameWidth);int t = static_cast<int>(detectionMat.at<float>(i, 4) * frameHeight);int r = static_cast<int>(detectionMat.at<float>(i, 5) * frameWidth);int b = static_cast<int>(detectionMat.at<float>(i, 6) * frameHeight);// 画框cv::rectangle(frame, cv::Point(l, t), cv::Point(r, b), cv::Scalar(0, 255, 0), 2);}}
}
// 图片测试
void imageTest()
{// 读取图片cv::Mat img = cv::imread("./media/test_face.jpg");// 推理detectDrawRect(img);// 显示cv::imshow("image test", img);// 保存cv::imwrite("./output/test_face_result.jpg", img);cv::waitKey(0);
}// 实时视频流检测
void videoTest()
{// =========== 摄像头 ===========// 先读取camera或文件视频流并显示// cv::VideoCapture cap(2);// // 设置指定摄像头的分辨率// int width = 640;// int height = 480;// // 设置摄像头宽度和高度// cap.set(cv::CAP_PROP_FRAME_WIDTH, width);// cap.set(cv::CAP_PROP_FRAME_HEIGHT, height);// =========== 文件 ===========// 先读取camera或文件视频流并显示cv::VideoCapture cap("./media/video.mp4");// 获取视频流的宽高int width = cap.get(cv::CAP_PROP_FRAME_WIDTH);int height = cap.get(cv::CAP_PROP_FRAME_HEIGHT);// 构造写入器// 写入MP4文件,参数分别是:文件名,编码格式,帧率,帧大小cv::VideoWriter writer("./output/record.mp4", cv::VideoWriter::fourcc('H', '2', '6', '4'), 25, cv::Size(width, height));if (!cap.isOpened()){std::cout << "Cannot open the video cam" << std::endl;// 退出exit(1);}cv::Mat frame;while (true){if (!cap.read(frame)){std::cout << "Cannot read a frame from video stream" << std::endl;break;}// flipcv::flip(frame, frame, 1);// 推理detectDrawRect(frame);// 写入writer.write(frame);// cv::imshow("MyVideo", frame);// if (cv::waitKey(1) == 27)// {//     std::cout << "esc key is pressed by user" << std::endl;//     break;// }}
}int main(int argc, char **argv)
{// 图片测试// imageTest();// 视频测试videoTest();return 0;
}

总结

opencv (C++)简单用法

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

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

相关文章

二、Java中SpringBoot组件集成接入【MySQL和MybatisPlus】

二、Java中SpringBoot组件集成接入【MySQL和MybatisPlus】 1.MySQL和MybatisPlus简介2.maven依赖3.配置1.在application.yaml配置中加入mysql配置2.新增Mybatis-Plus配置类 4.参考文章 1.MySQL和MybatisPlus简介 MySQL是一种开源的关系型数据库管理系统&#xff0c;被广泛应用…

Python——猜猜心里的数字(1)

首先呢&#xff0c;我们自定义一个数字&#xff0c;然后让对方猜一猜是否能猜中&#xff0c;接下来我们以10为例&#xff0c;给对方三次机会。 num10 if int(input("请猜一个数字:"))num:print("恭喜第一次就猜对了") elif int(input("猜错了&#x…

每日一题——LeetCode1128.等价多米诺骨牌对的数量

先尝试暴力解法&#xff1a; var numEquivDominoPairs function(dominoes) {var count0for(let i0;i<dominoes.length-1;i){for(let ji1;j<dominoes.length;j){if((dominoes[i][0]dominoes[j][0] && dominoes[i][1]dominoes[j][1]) || (dominoes[i][0]dominoes…

Mac下载Navicat premium提示文件损坏的解决方案

引用&#xff1a;https://blog.csdn.net/weixin_44898291/article/details/120879508 sudo xattr -r -d com.apple.quarantine

js:使用canvas画一个半圆

背景 需求需要画一个半圆&#xff0c;或者多半圆&#xff0c;其实一下子就能想到 canvas 中的圆弧&#xff0c;核心使用 context.arc context.arc(x,y,r,sAngle,eAngle,counterclockwise)接下来我们看看示例 例一 <!DOCTYPE html> <html lang"en"> &…

【野火i.MX6NULL开发板】GCC 和 Hello World

0、前言 参考资料&#xff1a; 《野火 Linux 基础与应用开发实战指南基于 i.MX6ULL 系列》PDF 第23章 1、教程

2024美赛数学建模思路 - 复盘:校园消费行为分析

文章目录 0 赛题思路1 赛题背景2 分析目标3 数据说明4 数据预处理5 数据分析5.1 食堂就餐行为分析5.2 学生消费行为分析 建模资料 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 赛题背景 校园一卡通是集…

Linux学习记录——사십이 高级IO(3)--- Poll型服务器

文章目录 1、认识poll接口2、实现3、特点 1、认识poll接口 #include <poll.h> int poll(struct pollfd *fds, nfds_t nfds, int timeout);// pollfd结构 struct pollfd {int fd; /* file descriptor */short events; /* requested events */short revents; /* returned…

BitMap源码解析

文章目录 前言数据结构添加与删除操作 JDK中BitSet源码解析重要成员属性初始化添加数据清除数据获取数据size和length方法集合操作&#xff1a;与、或、异或优缺点 前言 为什么称为bitmap&#xff1f; bitmap不仅仅存储介质以及数据结构不同于hashmap&#xff0c;存储的key和v…

5.3 Verilog 带参数例化

5.3 Verilog 带参数例化 分类 Verilog 教程 关键词&#xff1a; defparam&#xff0c;参数&#xff0c;例化&#xff0c;ram 当一个模块被另一个模块引用例化时&#xff0c;高层模块可以对低层模块的参数值进行改写。这样就允许在编译时将不同的参数传递给多个相同名字的模块…

element:日历 / 使用记录

一、预期效果 Element - The worlds most popular Vue UI framework element默认样式 目标样式 二、Calendar 属性 参数说明类型可选值默认值value / v-model绑定值Date/string/number——range时间范围&#xff0c;包括开始时间与结束时间。开始时间必须是周一&#xff0c;…

c语言线性方式初始化二维数组

线性方式初始化二维数组&#xff0c;只需要利用/与%的关系即可。具体细节文章下面会有程序的流程分析 问题起源 想要用线性方式初始化二维数组 问题分析 例如a[3][4] a[0][0] a[0][1] a[0][2] a[0][3] a[1][0] a[1][1] a[1][2] a[1][3] a[2][0] a[2][1] a[2][2] a[2][3]如…

Flutter-Web从0到部署上线(实践+埋坑)

本文字数&#xff1a;7743字 预计阅读时间&#xff1a;60分钟 01 前言 首先说明一下&#xff0c;这篇文章是给具备Flutter开发经验的客户端同学看的。Flutter 的诞生虽然来自 Google 的 Chrome 团队&#xff0c;但大家都知道 Flutter 最先支持的平台是 Android 和 iOS&#xff…

PHP在线文档管理系统源码

PHP在线文档管理系统源码 系统功能与介绍 在数据持续、快速增长背景下&#xff0c;企业面临海量非结构化数据处理需求&#xff0c;企业现有架构 通常无法应对海量非结构化数据的管理与应用。 支持私有化部署&#xff0c;完全内网环境下也可正常使用。 Windows、Linux、Mac等全平…

7个向量数据库对比:Milvus、Pinecone、Vespa、Weaviate、Vald、GSI 和 Qdrant

本文简要总结了当今市场上正在积极开发的7个向量数据库&#xff0c;Milvus、Pinecone、Vespa、Weaviate、Vald、GSI 和 Qdrant 的详细比较。 我们已经接近在搜索引擎体验的基础层面上涉及机器学习&#xff1a;在多维多模态空间中编码对象。这与传统的关键字查找不同&#xff08…

通过代理连接sftp

通过nginx代理连接sftp 1.问题描述2.代码实现3.nginx配置3.1 创建sftp.stream文件3.2 修改nginx配置 4.重启nginx生效 1.问题描述 问题是这样的。我们现在需要在微服务所在内网的A机器连接到外网的sftp&#xff0c;但是网络又不能直接到达。然后A机器到B机器是通过的&#xff…

【SAP】如何删除控制范围

经历就是财富&#xff0c;可你终将遗忘。期望文字打败时间。 本周心惊胆战地在配置系统删除了一个控制范围&#xff0c;还是有些收获&#xff0c;特此记录一下。 背景&#xff1a;在删除控制范围之前&#xff0c;我主要做了如下配置。 定义控制范围&#xff08;自动生成了成本…

【UEFI基础】EDK网络框架(IP4)

IP4 IP4协议说明 IP全称Internet Protocol&#xff0c;它属于网络层&#xff0c;对其下各种类型的数据链路层进行了包装&#xff0c;这样网络层可以跨越不同的数据链路&#xff0c;即使是在不同的数据链路上也能实现两端节点之间的数据包传输。 IP层的主要作用就是“实现终端…

C++|19.C++类与结构体对比

类和结构体 类和结构体本质上并没有太大区别。 但两者在默认上有所区别。 类默认成员变量是私有的&#xff0c;而结构体默认成员变量是公有的。 也就是说&#xff0c;对于一个类来说&#xff0c;会默认使用private去保护其内部成员变量使得无法直接访问到其内部的变量。 同时从…

代码随想录算法训练营第27天 | 39. 组合总和 40.组合总和II 131.分割回文串

目录 39. 组合总和 &#x1f4a1;解题思路 &#x1f4bb;实现代码 40.组合总和II &#x1f4a1;解题思路 &#x1f4bb;实现代码 131.分割回文串 &#x1f4a1;解题思路 # 判断回文子串 &#x1f4bb;实现代码 39. 组合总和 题目链接&#xff1a;39. 组合总和 给定…