opencv dnn模块 示例(24) 目标检测 object_detection 之 yolov8-pose 和 yolov8-obb

前面博文【opencv dnn模块 示例(23) 目标检测 object_detection 之 yolov8】 已经已经详细介绍了yolov8网络和测试。本文继续说明使用yolov8 进行 人体姿态估计 pose旋转目标检测 OBB

文章目录

  • 1、Yolov8-pose 简单使用
  • 2、Yolov8-OBB
    • 2.1、python 命令行测试
    • 2.2、opencv dnn测试
      • 2.2.1、onnx导出
      • 2.2.2、opencv dnn 中的预处理
      • 2.2.3、opencv dnn 中的后处理
      • 2.2.4、完整代码

1、Yolov8-pose 简单使用

人体姿态估计,使用coco数据集标注格式,17个关键点。

yolov8m-pose.pt 转换得到onnx如下,

(yolo_pytorch) E:\DeepLearning\yolov8-ultralytics>yolo pose export model=yolov8m-pose.pt format=onnx  batch=1 imgsz=640
Ultralytics YOLOv8.0.154  Python-3.9.16 torch-1.13.1+cu117 CPU (Intel Core(TM) i7-7700K 4.20GHz)
YOLOv8m-pose summary (fused): 237 layers, 26447596 parameters, 0 gradients, 81.0 GFLOPsPyTorch: starting from 'yolov8m-pose.pt' with input shape (1, 3, 640, 640) BCHW and output shape(s) (1, 56, 8400) (50.8 MB)ONNX: starting export with onnx 1.14.0 opset 16...
ONNX: export success  3.3s, saved as 'yolov8m-pose.onnx' (101.2 MB)Export complete (7.1s)
Results saved to E:\DeepLearning\yolov8-ultralytics
Predict:         yolo predict task=pose model=yolov8m-pose.onnx imgsz=640
Validate:        yolo val task=pose model=yolov8m-pose.onnx imgsz=640 data=/usr/src/app/ultralytics/datasets/coco-pose.yaml
Visualize:       https://netron.app

输入为640时输出纬度为 (56,8400),56维数据格式定义为 4 + 1 + 17*3:
矩形框box[x,y,w,h],目标置信度conf, 17组关键点 (x, y, conf)。

在后处理中,添加一个保存关键点的数据,一个显示关键点的函数

void postprocess(Mat& frame, cv::Size inputSz, const std::vector<Mat>& outs, Net& net)
{// yolov8-pose has an output of shape (batchSize, 56, 8400) (  box[x,y,w,h] + conf + 17*(x,y,conf) )...std::vector<cv::Mat> keypoints;for(int i = 0; i < rows; ++i) {float confidence = data[4];if(confidence >= confThreshold) {...boxes.push_back(cv::Rect(left, top, width, height));cv::Mat keypoint(1, dimensions - 5, CV_32F, tmp.ptr<float>(i, 5));for(int i = 0; i < 17; i++) {keypoint.at<float>(i * 3 + 0) *= x_factor;keypoint.at<float>(i * 3 + 1) *= y_factor;}keypoints.push_back(keypoint);}data += dimensions;}std::vector<int> indices;NMSBoxes(boxes, confidences, scoreThreshold, nmsThreshold, indices);for(size_t i = 0; i < indices.size(); ++i) {...drawSkelton(keypoints[idx], frame);}
}std::vector<cv::Scalar> kptcolors = {{255, 0, 0}, {255, 85, 0}, {255, 170, 0}, {255, 255, 0}, {170, 255, 0}, {85, 255, 0},{0, 255, 0}, {0, 255, 85}, {0, 255, 170}, {0, 255, 255}, {0, 170, 255}, {0, 85, 255},{0, 0, 255}, {255, 0, 170}, {170, 0, 255}, {255, 0, 255}, {85, 0, 255},
};std::vector<std::vector<int>> keypairs = {{15, 13},{13, 11},{16, 14},{14, 12},{11, 12},{5, 11},{6, 12},{5, 6},{5, 7},{6, 8},{7, 9},{8, 10},{1, 2},{0, 1},{0, 2},{1, 3},{2, 4},{3, 5},{4, 6}
};std::vector<std::vector<int>> keypairs = {{15, 13},{13, 11},{16, 14},{14, 12},{11, 12},{5, 11},{6, 12},{5, 6},{5, 7},{6, 8},{7, 9},{8, 10},{1, 2},{0, 1},{0, 2},{1, 3},{2, 4},{3, 5},{4, 6}
};void drawSkelton(const Mat& keypoints , Mat& frame)
{for(auto& pair : keypairs) {auto& pt1 = keypoints.at<cv::Point3f>(pair[0]);auto& pt2 = keypoints.at<cv::Point3f>(pair[1]);if(pt1.z > 0.5 && pt2.z > 0.5) {cv::line(frame, cv::Point(pt1.x, pt1.y), cv::Point(pt2.x, pt2.y), {255,255,0}, 2);}}for(int i = 0; i < 17; i++) {Point3f pt = keypoints.at<cv::Point3f>(i);if(pt.z < 0.5) continue;   	cv::circle(frame, cv::Point(pt.x, pt.y), 3, kptcolors[i], -1);cv::putText(frame, cv::format("%d", i), cv::Point(pt.x, pt.y), 1, 1, {255,0,0});}
}

结果如下:
在这里插入图片描述

2、Yolov8-OBB

2024年1月10号ultralytics发布了 v8.1.0 - YOLOv8 Oriented Bounding Boxes (OBB)。

YOLOv8框架在在支持分类、对象检测、实例分割、姿态评估的基础上更近一步,现支持旋转对象检测(OBB),基于DOTA数据集,支持航拍图像的15个类别对象检测,包括车辆、船只、典型各种场地等。包含2800多张图像、18W个实例对象。

0: plane
1: baseball-diamond
2: bridge
3: ground-track-field
4: small-vehicle
5: large-vehicle
6: ship
7: tennis-court
8: basketball-court
9: storage-tank
10: soccer-ball-field
11: roundabout
12: harbor
13: swimming-pool

Obb模型在含有15个类别的 DOTAv1 上训练,不同尺度的YOLOv8 OBB模型的精度与输入格式列表如下:

Modelsize
(pixels)
mAPtest
50
Speed
CPU ONNX
(ms)
Speed
A100 TensorRT
(ms)
params
(M)
FLOPs
(B)
YOLOv8n-obb102478.0204.773.573.123.3
YOLOv8s-obb102479.5424.884.0711.476.3
YOLOv8m-obb102480.5763.487.6126.4208.6
YOLOv8l-obb102480.71278.4211.8344.5433.8
YOLOv8x-obb102481.361759.1013.2369.5676.7

官方的船体、车辆检测示例图如下
在这里插入图片描述

2.1、python 命令行测试

例如,使用yolov8m-obb模型进行测试

yolo obb predict model=yolov8m-obb.pt source=t.jpgUltralytics YOLOv8.1.19 🚀 Python-3.9.16 torch-1.13.1+cu117 CUDA:0 (NVIDIA GeForce GTX 1080 Ti, 11264MiB)
YOLOv8m-obb summary (fused): 237 layers, 26408752 parameters, 0 gradients, 80.9 GFLOPsimage 1/1 E:\DeepLearning\yolov8-ultralytics\DJI_0390.JPG: 768x1024 36.0ms
Speed: 6.0ms preprocess, 36.0ms inference, 130.5ms postprocess per image at shape (1, 3, 768, 1024)
Results saved to runs\obb\predict2
💡 Learn more at https://docs.ultralytics.com/modes/predict

网络图片 测试如下
在这里插入图片描述

2.2、opencv dnn测试

2.2.1、onnx导出

yolo export model=yolov8s-obb.pt format=onnx

使用netron查看输入输出
在这里插入图片描述

2.2.2、opencv dnn 中的预处理

预处理和yolov5之后基本一致,letterbox处理,

cv::Mat formatToSquare(const cv::Mat &source)
{int col = source.cols;int row = source.rows;int _max = MAX(col, row);cv::Mat result = cv::Mat(_max, _max, CV_8UC3, {114,114,114});source.copyTo(result(cv::Rect(0, 0, col, row)));return result;
}

之后就是将WHC的图片frame转换为NCWH的blob数据,使用函数 dnn::blobFromImages,完整如下

float scale = 1 / 255.0;  //0.00392
Scalar mean = {0,0,0};
bool swapRB = true;
inpWidth = 1024;
inpHeight = 1024;
Mat blob;// Create a 4D blob from a frame.
cv::Mat modelInput = frame;
if(letterBoxForSquare && inpWidth == inpHeight)modelInput = formatToSquare(modelInput);blobFromImages(std::vector<cv::Mat>{modelInput}, blob, scale, cv::Size2f(inpWidth, inpHeight), mean, swapRB, false);   

2.2.3、opencv dnn 中的后处理

前面通过可视化看到YOLOv8-OBB 网络输入为 1024x1024, 输出为 1x20x21504,也就是预测框为21504个(三个尺度128x128、64x64、32x32),每个预测框的纬度是 20(针对DOTAv1的数据集15个类别)。详细可以表示为如下公式
21504 × 20 = 128 × 128 × 20 + 64 × 64 × 20 + 32 × 32 × 20 = 128 × 128 × ( 1 + 15 + 4 ) + 128 × 64 × ( 1 + 15 + 4 ) + 32 × 32 × ( 1 + 15 + 4 ) \begin{aligned} 21504\times 20 &= 128\times 128\times 20+64\times 64\times 20+32\times 32\times 20 \\ &= 128\times 128\times (1+15+4) + 128\times 64\times (1+15+4) + 32\times 32\times (1+15+4) \end{aligned} 21504×20=128×128×20+64×64×20+32×32×20=128×128×(1+15+4)+128×64×(1+15+4)+32×32×(1+15+4)

其中的 4 对应的是 cx, cy, w, h,分别代表的含义是边界框中心点坐标、宽高;15 对应的是 DOTAv1 数据集中的 15 个类别置信度;1 对应的是旋转框的旋转角度 angle,其取值范围是在 [-pi/4, 3pi/4] 之间。

在yolov8解码基础上修改,后处理主要改变2个地方,目标框从Rect 改变为 RotatedRect,nms的的对象也相应调整。

(1)RotatedRect 的解码
已知矩形框 cx, cy, w, h 和 角度 angle,首先需要计算旋转之后旋转矩形框的新的四个顶点坐标
在这里插入图片描述
这里数学推导坐标系y轴线上,逆时针旋转。对比图像坐标系y轴线下,yolov8-OBB 角度为顺时针,两者其实是统一的。

参考上面原理,得到旋转目标框的4个顶点在原图上的坐标点计算如下

const float cos_value = cos(angle);
const float sin_value = sin(angle);std::vector<Point2f> pts = {  // 未旋转前顺时针四个点 左上、右上、右下、左下Point2f(cx - w / 2,cy - h / 2),  Point2f(cx + w / 2,cy - h / 2), Point2f(cx + w / 2,cy + h / 2), Point2f(cx - w / 2,cy + h / 2), 
};for(auto& pt : pts) {auto x = pt.x;auto y = pt.y;pt.x = cx + (x - cx) * cos_value - (y - cy) * sin_value;pt.y = cy + (x - cx) * sin_value + (y - cy) * cos_value;
}

4个顶点的构造和最终变换结果可以简化为:

const cv::Point2f vec1 = { w / 2 * cos_value,w / 2 * sin_value};
const cv::Point2f vec2 = {-h / 2 * sin_value,h / 2 * cos_value};
std::vector<Point2f> pts{  // 按顺序即可Point2f(cx,cy) + vec1 + vec2,Point2f(cx,cy) + vec1 - vec2,Point2f(cx,cy) - vec1 - vec2,Point2f(cx,cy) - vec1 + vec2,
};

(2)RotatedRect 的nms

在前面解码基础上,使用参数为 cv::RotatedRect 的 NMSBoxes 重载版本

std::vector<int> class_ids;
std::vector<float> confidences;
//std::vector<cv::Rect> boxes
std::vector<cv::RotatedRect> boxes;for(....) {... 获取当前目标框数据const cv::Point2f vec1 = { w / 2 * cos_value,w / 2 * sin_value};const cv::Point2f vec2 = {-h / 2 * sin_value,h / 2 * cos_value};std::vector<Point2f> pts{Point2f(cx,cy) + vec1 + vec2,Point2f(cx,cy) + vec1 - vec2,Point2f(cx,cy) - vec1 - vec2,Point2f(cx,cy) - vec1 + vec2,};boxes.emplace_back(pts[0], pts[1], pts[2]);
}std::vector<int> indices;
NMSBoxes(boxes, confidences, scoreThreshold, nmsThreshold, indices);

注意:
这里cv::RotatedRect的构造使用了按顺序排列的3个顶点,实际内存保存的是 rect的中线、宽高和旋转角度。 从cv::RotatedRect对象中提取4个顶点需要重新计算。

(3)绘制代码
在前面绘制Rect可以直接使用 cv::retangle函数, 但是 RotatedRect 只能通过四个顶点进行连线绘制

cv::RotatedRect rrect = ...;cv::Point2f pts[4];
rrect.points(&pts[0]);for(int i = 0; i < 4; i++) {cv::line(frame, pts[i] ,pts[(i+1)%4], color, 2);
}
//cv::circle(frame, pts[0], 3, {0,0,255}, -1);  // 期望绘制解码后的第一个点顶

2.2.4、完整代码

#pragma once#include "opencv2/opencv.hpp"#include <fstream>
#include <sstream>#include <random>
#include <numeric>namespace YOLOv8_OBB {using namespace cv;
using namespace dnn;float inpWidth;
float inpHeight;
float confThreshold, scoreThreshold, nmsThreshold;
std::vector<std::string> classes;
std::vector<cv::Scalar> colors;bool letterBoxForSquare = true;cv::Mat formatToSquare(const cv::Mat &source);void postprocess(Mat& frame, cv::Size inputSz, const std::vector<Mat>& out, Net& net);// void drawPred(int classId, float conf, const cv::Rect& rect, Mat& frame);
void drawPred(int classId, float conf, const std::vector<cv::Point2f>& pts, Mat& frame);std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<int> dis(100, 255);int test()
{// 根据选择的检测模型文件进行配置 confThreshold = 0.25;scoreThreshold = 0.45;nmsThreshold = 0.5;float scale = 1 / 255.0;  //0.00392Scalar mean = {0,0,0};bool swapRB = true;inpWidth = 1024;inpHeight = 1024;String modelPath = R"(E:\DeepLearning\yolov8-ultralytics\yolov8m-obb.onnx)";String configPath;String framework = "";//int backendId = cv::dnn::DNN_BACKEND_OPENCV;//int targetId = cv::dnn::DNN_TARGET_CPU;//int backendId = cv::dnn::DNN_BACKEND_OPENCV;//int targetId = cv::dnn::DNN_TARGET_OPENCL;int backendId = cv::dnn::DNN_BACKEND_CUDA;int targetId = cv::dnn::DNN_TARGET_CUDA;// Open file with classes names.//if(!classesFile.empty()) {//    const std::string& file = classesFile;//    std::ifstream ifs(file.c_str());//    if(!ifs.is_open())//        CV_Error(Error::StsError, "File " + file + " not found");//    std::string line;//    while(std::getline(ifs, line)) {//        classes.push_back(line);//        colors.push_back(cv::Scalar(dis(gen), dis(gen), dis(gen)));//    }//}for(int i = 0; i< 15; i++){classes.push_back(std::to_string(i));colors.push_back(cv::Scalar(dis(gen), dis(gen), dis(gen)));}// Load a model.Net net = readNet(modelPath, configPath, framework);net.setPreferableBackend(backendId);net.setPreferableTarget(targetId);std::vector<String> outNames = net.getUnconnectedOutLayersNames();//std::vector<String> outNames{"output"};if(backendId == cv::dnn::DNN_BACKEND_CUDA) {int dims[] = {1,3,inpHeight,inpWidth};cv::Mat tmp = cv::Mat::zeros(4, dims, CV_32F);std::vector<cv::Mat> outs;net.setInput(tmp);for(int i = 0; i < 10; i++)net.forward(outs, outNames); // warmup}// Create a windowstatic const std::string kWinName = "Deep learning object detection in OpenCV";//cv::namedWindow(kWinName, 0);// Open a video file or an image file or a camera stream.VideoCapture cap;//cap.open(0);//cap.open(R"(E:\DeepLearning\darknet-yolo3-master\build\darknet\x64\dog.jpg)");//cap.open("http://live.cooltv.top/tv/aishang.php?id=cctv1hd");//cap.open(R"(F:\测试视频\路口俯拍\snap1.mkv)");//cap.open(R"(E:\DeepLearning\yolov5\data\images\bus.jpg)");//cap.open(R"(F:\1、交通事故素材\筛选后素材1\DJI_0014.JPG)");cap.open(R"(C:\Users\wanggao\Desktop\aa.jpg)"); // t.jpeg   aaa.jpegcv::TickMeter tk;// Process frames.Mat frame, blob;while(waitKey(1) < 0) {cap >> frame;if(frame.empty()) {waitKey();break;}// Create a 4D blob from a frame.cv::Mat modelInput = frame;if(letterBoxForSquare && inpWidth == inpHeight)modelInput = formatToSquare(modelInput);blobFromImages(std::vector<cv::Mat>{modelInput}, blob, scale, cv::Size2f(inpWidth, inpHeight), mean, swapRB, false);// Run a model.net.setInput(blob);std::vector<Mat> outs;auto tt1 = cv::getTickCount();net.forward(outs, outNames);auto tt2 = cv::getTickCount();postprocess(frame, modelInput.size(), outs, net);std::string label = format("Inference time: %.2f ms", (tt2 - tt1) / cv::getTickFrequency() * 1000);cv::putText(frame, label, Point(0, 15), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 255, 0));cv::imshow(kWinName, frame);}return 0;
}cv::Mat formatToSquare(const cv::Mat &source)
{int col = source.cols;int row = source.rows;int _max = MAX(col, row);cv::Mat result = cv::Mat(_max, _max, CV_8UC3, {114,114,114});source.copyTo(result(cv::Rect(0, 0, col, row)));return result;
}void postprocess(Mat& frame, cv::Size inputSz, const std::vector<Mat>& outs, Net& net)
{// yolov8 has an output of shape (batchSize, 84, 8400) (Num classes + box[x,y,w,h] + confidence[c])// yolov8-obb has an output of shape (batchSize, 20, 2150) (box[x,y,w,h] + confidence[c] + angle)auto tt1 = cv::getTickCount();float x_factor = inputSz.width / inpWidth;float y_factor = inputSz.height / inpHeight;std::vector<int> class_ids;std::vector<float> confidences;//std::vector<cv::Rect> boxes;  // 2150std::vector<cv::RotatedRect> boxes;std::vector<std::vector<Point2f>> boxesPoints; // 减少计算量// [1, 84, 8400] -> [8400,84]int rows = outs[0].size[2];int dimensions = outs[0].size[1];auto tmp = outs[0].reshape(1, dimensions);cv::transpose(tmp, tmp);float *data = (float *)tmp.data;for(int i = 0; i < rows; ++i) {float *classes_scores = data + 4;cv::Mat scores(1, classes.size(), CV_32FC1, classes_scores);cv::Point class_id;double max_class_score;minMaxLoc(scores, 0, &max_class_score, 0, &class_id);if(max_class_score > scoreThreshold) {confidences.push_back(max_class_score);class_ids.push_back(class_id.x);//float x = data[0];//float y = data[1];//float w = data[2];//float h = data[3];//int left = int((x - 0.5 * w) * x_factor);//int top = int((y - 0.5 * h) * y_factor);//int width = int(w * x_factor);//int height = int(h * y_factor);//boxes.push_back(cv::Rect(left, top, width, height));       const float cx = data[0] * x_factor;const float cy = data[1] * y_factor;const float w = data[2] * x_factor;const float h = data[3] * y_factor;const float angle = data[19];    const float cos_value = cos(angle);const float sin_value = sin(angle);const cv::Point2f vec1 = { w / 2 * cos_value,w / 2 * sin_value};const cv::Point2f vec2 = {-h / 2 * sin_value,h / 2 * cos_value};std::vector<Point2f> pts{Point2f(cx,cy) + vec1 + vec2,Point2f(cx,cy) + vec1 - vec2,Point2f(cx,cy) - vec1 - vec2,Point2f(cx,cy) - vec1 + vec2,};boxes.emplace_back(pts[0], pts[1], pts[2]);boxesPoints.emplace_back(pts);}data += dimensions;}std::vector<int> indices;NMSBoxes(boxes, confidences, scoreThreshold, nmsThreshold, indices);auto tt2 = cv::getTickCount();std::string label = format("NMS time: %.2f ms", (tt2 - tt1) / cv::getTickFrequency() * 1000);cv::putText(frame, label, Point(0, 30), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 255, 0));for(size_t i = 0; i < indices.size(); ++i) {int idx = indices[i];//drawPred(class_ids[idx], confidences[idx], boxes[idx], frame);drawPred(class_ids[idx], confidences[idx], boxesPoints[idx], frame);}
}void drawPred(int classId, float conf, const std::vector<cv::Point2f>& pts, Mat& frame)
{std::string label = format("%.2f", conf);Scalar color = Scalar::all(255);if(!classes.empty()) {CV_Assert(classId < (int)classes.size());label = classes[classId] + ": " + label;color = colors[classId];}/*rectangle(frame, Point(left, top), Point(right, bottom), Scalar(0, 255, 0));*/for(int i = 0; i < 4; i++) {cv::line(frame, pts[i], pts[(i + 1) % 4], color, 2);}cv::circle(frame, pts[0], 3, {0,0,255}, -1);int baseLine;Size labelSize = getTextSize(label, FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);int left = pts[0].x;int top = std::max((int)pts[0].y, labelSize.height);rectangle(frame, Point(left, top - labelSize.height),Point(left + labelSize.width, top + baseLine), color, FILLED);cv::putText(frame, label, Point(left, top), FONT_HERSHEY_SIMPLEX, 0.5, Scalar());
}

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

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

相关文章

css clip-path polygon属性实现直角梯形

2024.3.8今天我学习了如何用css实现直角梯形的效果&#xff0c; 效果&#xff1a; 具体实现原理&#xff1a; 一、需要三个div&#xff1a; 外面一个大的div&#xff0c;里面左右两个小的div 我们需要先把第一个div变成直角梯形&#xff1a; 大概是这样&#xff0c;设置好之…

visual studio 将编译后的dll等文件自动复制到指定目录

编译后的文件dll等总要手动复制到指定目录下&#xff0c;为了解决这一繁琐的操作&#xff0c;可以直接设置在编译完成后&#xff0c;自动复制到目标目录 - 在解决方案资源管理器&#xff0c;选中项目右键-》选中属性-》在弹出的面板选择生成事件 - 在后期生成事件命令行里填写…

PCM会重塑汽车OTA格局吗(1)

目录 1.汽车OTA概述 2.ST如何考虑OTA&#xff1f; 2.1 Stellar四大亮点 2.2 PCM技术视角下的OTA 3.小结 1.汽车OTA概述 随着智能网联汽车的飞速发展&#xff0c;汽车OTA也越来越盛行&#xff1b; 目前来讲OTA分为FOTA和SOTA(Software-over-the-air)两种&#xff0c;区别…

【博士每天一篇文献-综述】Modular Brain Networks

阅读时间&#xff1a;2023-11-27 1 介绍 年份&#xff1a;2016 作者&#xff1a;Olaf Sporns&#xff0c;Richard Betzel&#xff0c;印第安纳大学心理与脑科学杰出教授 期刊&#xff1a; Annual review of psychology 引用量&#xff1a;1205 详细介绍了模块化大脑网络及其如…

UE5 UE4 开发常用工具AssetDeveTool

AssetDeveTool工具&#xff0c;支持UE5 5.0-.5.3 UE4 4.26/4.27 下载链接&#xff1a; 面包多 https://mbd.pub/o/bread/ZZubkphu 工坊&#xff1a; https://gf.bilibili.com/item/detail/1104960041 包含功能&#xff1a; 自动化批量展UV功能 快速选择功能 自动化批量减面功能…

京津冀光伏展

京津冀光伏展是一个旨在推动京津冀地区光伏产业发展的展览会。光伏产业是指利用太阳能光电转换技术&#xff0c;将太阳能转化为电能的产业。京津冀地区是中国重要的经济区域&#xff0c;也是光伏产业发展潜力很大的地区之一。京津冀光伏展为光伏企业提供了一个展示产品和技术的…

Springboot+vue的物业管理系统(有报告)。Javaee项目,springboot vue前后端分离项目。

演示视频&#xff1a; Springbootvue的物业管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot vue前后端分离项目。 项目介绍&#xff1a; 本文设计了一个基于Springbootvue的物业管理系统&#xff0c;采用M&#xff08;model&#xff09;V&#xff…

【MapReduce】03.MapReduce框架原理

目录 1.InputFormat数据输入 1.1.切片与MapTask并行度决定机制 1.2.Job提交流程源码和切片源码 1.3.FileInputFormat切片机制 1.4.TextInputFormat 1.5.CombineTextInputFormat切片机制 1.6.CombineTextInputFormat 1.InputFormat数据输入 1.1.切片与MapTask并行度决定…

CSS盒子模型笔记

尚硅谷学习视频链接&#xff1a;117_CSS_盒子模型的组成部分_哔哩哔哩_bilibili 1、盒子组成 盒子组成 content内容 padding border &#xff08;margin不包含在盒子内&#xff09; 2、div样式width、height 当css3属性box-sizingcontent-box&#xff08;默认&#xff0…

0-hackbar最新版本(2.3.1)工具安装(超详细)

通过火狐搜索安装后&#xff0c;是需要收费的&#xff0c;获取url都是困难的 打开火狐浏览器右上角的三个横线-拓展和主题 百度界面按F12后的提示 修改过程&#xff1a; 按照如上一步步找到对应的文件&#xff0c;拖到桌面上 是一个xpi文件&#xff0c;以打开压缩包的方式打开…

漏洞复现-蓝凌LandrayOA系列

蓝凌OA系列 &#x1f52a; 是否利用过 优先级从高到低 发现日期从近到远 公司团队名_产品名_大版本号_特定小版本号_接口文件名_漏洞类型发现日期.载荷格式LandrayOA_Custom_SSRF_JNDI漏洞 LandrayOA_sysSearchMain_Rce漏洞 LandrayOA_Custom_FileRead漏洞

智能音箱技术解析

目录 前言智能音箱执行步骤解析1.1 探测唤醒词或触发词1.2 语音识别1.3 意图识别1.4 执行指令 2 典型的智能音箱2.1 百度小度音响2.2 小米小爱同学2.3 苹果 HomePod 3 功能应用举例3.1 设置计时器3.2 播放音乐 结语 前言 智能音箱已经成为日常生活中不可或缺的一部分&#xff…

飞驰云联CEO朱旭光荣获“科技领军人才”称号

2024年2月29日&#xff0c;苏州工业园区“优化营商环境暨作风效能建设大会”成功举办&#xff0c;会上公布了2023年度苏州工业园区第十七届第一批金鸡湖科技领军人才名单&#xff0c;Ftrans飞驰云联创始人兼CEO朱旭光先生凭借在数据安全以及文件交换领域取得的突出成果&#xf…

【完美实现】VITE + VUE3 + SVG图片解析+element-plus开发环境初始化(基于macos)

一、最终效果 废话少说&#xff0c;直接上效果 这是我的初始化程序提供的页面&#xff0c;在这个页面上实现了一下几个功能&#xff1a; 1、vite初始化之后的路由安装和初始化&#xff1b; 2、标准SVG的解析&#xff0c;并可调整大小、颜色&#xff1b; 3、element-plus的安…

【SpringMVC】响应数据 第二期

文章目录 一、handler方法分析二、页面跳转控制2.1 快速返回模板视图2.2 转发和重定向 三、返回JSON数据&#xff08;重点&#xff09;3.1 前置准备3.2 ResponseBody3.3 RestController 四、返回静态资源处理4.1 静态资源概念4.2 静态资源访问和问题解决 总结混合开发 与 前后端…

go go.mod file not found in current directory or any parent directory

场景&#xff1a; 安装好 liteide 之后创建了第一个 “hello world” 的golang 项目&#xff0c;却报了如下错误。 原因分析&#xff1a; go 的环境配置问题。与 golang 的包管理有关。 解决方案&#xff1a; 如果你是 Windows 系统&#xff0c;快捷键 “WinR”&#xff0c…

视频点播系统|基于SSM 框架+ Mysql+Java+B/S架构技术的视频点播系统设计与实现(可运行源码+数据库+设计文档+部署说明+视频演示)

目录 文末获取源码 系统功能实现 学生前台功能 学生登录、学生注册 个人中心 视频信息 我的收藏 系统公告 教师功能实现 管理员登录 管理员功能实现 视频分类管理 轮播图管理 数据库设计 系统的功能结构图 lumwen参考 概述 源码获取 文末获取源码 系统功能实…

NextJs教程系列(四):路由loading

loading加载 loading.js 可以帮助你使用React Suspense创建一个组件, 当你在加载路由内容时&#xff0c;它会显示该加载状态组件&#xff0c;渲染完成后&#xff0c;新的内容将会自动替换。 传统ssr渲染流程 传统的ssr渲染流程&#xff0c;当用户请求一个页面时&#xff0c;服…

荔枝派zero驱动开发06:GPIO操作(platform框架)

参考&#xff1a; 正点原子Linux第五十四章 platform设备驱动实验 一张图掌握 Linux platform 平台设备驱动框架 上一篇&#xff1a;荔枝派zero驱动开发05&#xff1a;GPIO操作&#xff08;使用GPIO子系统&#xff09; 下一篇&#xff1a;更新中… 概述 platform是一种分层思…

ELK介绍使用

文章目录 一、ELK介绍二、Elasticsearch1. ElasticSearch简介&#xff1a;2. Elasticsearch核心概念3. Elasticsearch安装4. Elasticsearch基本操作1. 字段类型介绍2. 索引3. 映射4. 文档 5. Elasticsearch 复杂查询 三、LogStash1. LogStash简介2. LogStash安装 四、kibana1. …