Opencv-C++笔记 (18) : 轮廓和凸包
文章目录
- 一、轮廓
- findContours发现轮廓
- drawContours绘制轮廓
- 代码
- 二.几何及特性概括——凸包(Convex Hull)
- 凸包概念
- 凸包扫描算法介绍——Graham扫描算法
- 相关API介绍
- 程序示例
- 轮廓集合及特性性概括——轮廓周围绘制矩形框和圆形
- 相关理论介绍
- 轮廓周围绘制矩形 -API
- 绘制步骤
- 程序实例
- 四.图像矩(Image Moments)
- 1、相关理论
- 2、API介绍
- 计算轮廓面积cv::contourArea
- .计算轮廓长度cv::arcLength
- 例程
- 五、多边形测试
- 1.相关理论
- 2.相关API介绍
- 程序示例
一、轮廓
轮廓发现是基于图像边缘提取的基础寻找对象轮廓的方法。 所以边缘提取的阈值选定会影响最终轮廓发现结果
轮廓查找步骤:
- 输入图像转为灰度图像cvtColor
- 使用Canny进行边缘提取或者threshold阈值操作,得到二值图像
- 使用findContours寻找轮廓
- 使用drawContours绘制轮廓
findContours发现轮廓
在二值图像上发现轮廓使用
cv::findContours(
InputOutputArray binImg, 输入图像,非0的像素被看成1,0的像素值保持不变,8-bit
OutputArrayOfArrays contours, 全部发现的轮廓对象
OutputArray, hierachy 图该的拓扑结构 std::vector<cv::Vec4i>,可选,该轮廓发现算法正是基于图像拓扑结构实现。它的元素与轮廓的数量一样多。对于每个第 i 个轮廓轮廓[i],元素hierarchy[i][0]、hierarchy[i][1]
int mode, 轮廓返回的模式
int method, 发现方法
Point offset=Point() 轮廓像素的位移,默认(0, 0)没有位移
)
drawContours绘制轮廓
在二值图像上发现轮廓cv::findContours之后对发现的轮廓数据进行绘制显示
drawContours(
InputOutputArray binImg, 输出图像
OutputArrayOfArrays contours, 全部发现的轮廓对象
Int contourIdx 轮廓索引号
const Scalar & color, 绘制颜色
int thickness,/ 绘制线宽
int lineType , 线的类型LINE_8
InputArray hierarchy, 拓扑结构图
int maxlevel, 最大层数, 0只绘制当前的,1表示绘制绘制当前及其内嵌的轮廓
Point offset=Point() 轮廓位移,可选
代码
//轮廓发现:通过cv::fingContoursAPI查找轮廓,通过cv::drawContours绘制轮廓
#include <opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>
#include <iostream>using namespace cv;
using namespace std;int threshold_value = 100;
int threshold_max = 255;
RNG rng;
const char* output_win = "Demo_Contour";
void Demo_Contours(int, void*);
Mat src,dst;
int main(int argc, char** argv) {src = imread("D:/photos/45.png");if (src.empty()) {printf("could not load image...\n");return -1;}namedWindow("input image", CV_WINDOW_AUTOSIZE);namedWindow(output_win, CV_WINDOW_AUTOSIZE);imshow("input image", src);cvtColor(src, src, CV_BGR2GRAY);//灰度化图像,为Canny边缘检测做准备const char* trackbar_title = "threshold_value";createTrackbar(trackbar_title, output_win, &threshold_value, threshold_max, Demo_Contours);//动态调整Canny边缘检测的阈值Demo_Contours(0, 0);//使程序刚开始就有结果,与createTrackbar无关waitKey(0);return 0;
}void Demo_Contours(int, void*) {Mat canny_output;vector<vector<Point>> contours;vector<Vec4i> hierachy;Canny(src, canny_output, threshold_value, threshold_value * 2, 3, false);//Canny边缘检测,3代表算子尺寸imshow("canny image", canny_output);findContours(canny_output, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));//contours储存轮廓的点集,轮廓提取方式为RETR_TREE,轮廓表达为:CHAIN_APPROX_SIMPLEdst = Mat::zeros(src.size(), CV_8UC3);RNG rng(12345);for (size_t i = 0; i < contours.size(); i++) {//逐条绘制轮廓Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));drawContours(dst, contours, i, color, 2, 8, hierachy, 0, Point(0, 0));}imshow(output_win, dst);}
二.几何及特性概括——凸包(Convex Hull)
凸包概念
什么是凸包(Convex Hull),在一个多变形边缘或者内部任意两个点的连线都包含在多边形边界或者内部。
**正式定义:**包含点集合S中所有点的最小凸多边形称为凸包
凸包扫描算法介绍——Graham扫描算法
- 首先选择Y方向最低的点作为起始点p0。
- 从p0开始极坐标扫描,依次添加p1….pn(排序顺序是根据极坐标的角度大小,逆时针方向)。
- 对每个点pi来说,如果添加pi点到凸包中导致一个左转向(逆时针方法)则添加该点到凸包,
反之如果导致一个右转向(顺时针方向)删除该点从凸包中。
相关API介绍
convexHull(
InputArray points,// 输入候选点,来自findContours
OutputArray hull,// 凸包
bool clockwise,// default true, 顺时针方向
bool returnPoints)// true 表示返回点个数,如果第二个参数是 vector<Point>则自动忽略
}
凸包逼近实现步骤:
-
首先把图像从RGB转为灰度。
-
然后再转为二值图像。
-
在通过发现轮廓得到候选点。
-
凸包API调用。
-
绘制显示。
程序示例
#include <opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>
#include <iostream>using namespace cv;
using namespace std;int threshold_value = 100;
int threshold_max = 255;
RNG rng(12345);
const char* output_win = "Demo_convex hull";
void threshold_callback(int, void*);
Mat src, dst,dst2,gray_src;
int main(int argc, char** argv) {src = imread("D:/photos/45.png");if (src.empty()) {printf("could not load image...\n");return -1;}namedWindow("input image", CV_WINDOW_AUTOSIZE);namedWindow(output_win, CV_WINDOW_AUTOSIZE);const char* trackbar_label = "threshold:";imshow("input image", src);cvtColor(src, gray_src, CV_BGR2GRAY);blur(gray_src, gray_src, Size(3, 3), Point(-1, -1), BORDER_DEFAULT);//均值模糊进行降噪处理imshow("src_gray", gray_src);createTrackbar(trackbar_label, output_win, &threshold_value, threshold_max, threshold_callback);threshold_callback(0, 0);waitKey(0);return 0;
}
void threshold_callback(int, void*) {Mat bin_output;vector<vector<Point>> contours;vector<Vec4i> hierachy;threshold(gray_src, bin_output, threshold_value, threshold_max, THRESH_BINARY);findContours(bin_output, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));vector<vector<Point>> convexs(contours.size());dst = Mat::zeros(src.size(), CV_8UC3);dst2 = Mat::zeros(src.size(), CV_8UC3);for (size_t i = 0; i < contours.size(); i++) {Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));convexHull(contours[i], convexs[i], false, true);//drawContours(dst, contours, i, color, 2, 8, hierachy, 0, Point(0, 0));}vector<Vec4i> empty(0);for (size_t k = 0; k < contours.size(); k++) {Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));drawContours(dst2, contours, k, color, 2, LINE_8, hierachy,1, Point(0, 0));drawContours(dst, convexs, k, color, 2, LINE_8, empty, 0, Point(0, 0));//注意此时hieracgy选项填Mat()}imshow(output_win, dst);imshow("contours_Demo", dst2);return;
}
轮廓集合及特性性概括——轮廓周围绘制矩形框和圆形
相关理论介绍
轮廓周围绘制矩形 -API
approxPolyDP(InputArray curve, OutputArray approxCurve, double epsilon, bool closed)
基于RDP算法实现,目的是减少多边形轮廓点数。
cv::minEnclosingCircle(InputArray points, //得到最小区域圆形
Point2f& center, // 圆心位置
float& radius)// 圆的半径
cv::fitEllipse(InputArray points)得到最小椭圆
绘制步骤
首先将图像变为二值图像。
发现轮廓,找到图像轮廓。
通过相关API在轮廓点上找到最小包含矩形和圆,旋转矩形与椭圆。
绘制它们。
程序实例
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>using namespace std;
using namespace cv;
Mat src, gray_src, drawImg;
int threshold_v = 170;
int threshold_max = 255;
const char* output_win = "rectangle-demo";
RNG rng(12345);
void Contours_Callback(int, void*);
int main(int argc, char** argv) {src = imread("D:/photos/45.png");if (!src.data) {printf("could not load image...\n");return -1;}cvtColor(src, gray_src, CV_BGR2GRAY);blur(gray_src, gray_src, Size(3, 3), Point(-1, -1));const char* source_win = "input image";namedWindow(source_win, CV_WINDOW_AUTOSIZE);namedWindow(output_win, CV_WINDOW_AUTOSIZE);imshow(source_win, src);createTrackbar("Threshold Value:", output_win, &threshold_v, threshold_max, Contours_Callback);Contours_Callback(0, 0);waitKey(0);return 0;
}void Contours_Callback(int, void*) {Mat binary_output;vector<vector<Point>> contours;vector<Vec4i> hierachy;threshold(gray_src, binary_output, threshold_v, threshold_max, THRESH_BINARY);//imshow("binary image", binary_output);findContours(binary_output, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(-1, -1));vector<vector<Point>> contours_ploy(contours.size());vector<Rect> ploy_rects(contours.size());vector<Point2f> ccs(contours.size());vector<float> radius(contours.size());vector<RotatedRect> minRects(contours.size());vector<RotatedRect> myellipse(contours.size());for (size_t i = 0; i < contours.size(); i++) {approxPolyDP(Mat(contours[i]), contours_ploy[i], 3, true);ploy_rects[i] = boundingRect(contours_ploy[i]);minEnclosingCircle(contours_ploy[i], ccs[i], radius[i]);if (contours_ploy[i].size() > 5) {myellipse[i] = fitEllipse(contours_ploy[i]);minRects[i] = minAreaRect(contours_ploy[i]);}}// draw itdrawImg = Mat::zeros(src.size(), src.type());Point2f pts[4];for (size_t t = 0; t < contours.size(); t++) {Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));//rectangle(drawImg, ploy_rects[t], color, 2, 8);//circle(drawImg, ccs[t], radius[t], color, 2, 8);if (contours_ploy[t].size() > 5) {ellipse(drawImg, myellipse[t], color, 1, 8);minRects[t].points(pts);for (int r = 0; r < 4; r++) {line(drawImg, pts[r], pts[(r + 1) % 4], color, 1, 8);}}}imshow(output_win, drawImg);return;
}
运行效果:
四.图像矩(Image Moments)
1、相关理论
2、API介绍
1.计算矩cv::moments
moments(
InputArray array,//输入数据
bool binaryImage=false // 是否为二值图像
)
API介绍与使用 – cv::moments 计算生成数据
计算轮廓面积cv::contourArea
contourArea(
InputArray contour,//输入轮廓数据
bool oriented// 默认false、返回绝对值)
}
.计算轮廓长度cv::arcLength
arcLength(
InputArray curve,//输入曲线数据
bool closed// 是否是封闭曲线)
}
实现步骤:
提取图像边缘。
发现轮廓。
计算每个轮廓对象的矩。
计算每个对象的中心、弧长、面积
例程
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>using namespace std;
using namespace cv;Mat src, gray_src;
int threshold_value = 80;
int threshold_max = 255;
const char* output_win = "image moents demo";
RNG rng(12345);
void Demo_Moments(int, void*);
int main(int argc, char** argv) {src = imread("D:/photos/45.png");if (!src.data) {printf("could not load image...\n");return -1;}cvtColor(src, gray_src, CV_BGR2GRAY);GaussianBlur(gray_src, gray_src, Size(3, 3), 0, 0);char input_win[] = "input image";namedWindow(input_win, CV_WINDOW_AUTOSIZE);namedWindow(output_win, CV_WINDOW_AUTOSIZE);imshow(input_win, src);createTrackbar("Threshold Value : ", output_win, &threshold_value, threshold_max, Demo_Moments);Demo_Moments(0, 0);waitKey(0);return 0;
}void Demo_Moments(int, void*) {Mat canny_output;vector<vector<Point>> contours;vector<Vec4i> hierachy;Canny(gray_src, canny_output, threshold_value, threshold_value * 2, 3, false);findContours(canny_output, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));vector<Moments> contours_moments(contours.size());vector<Point2f> ccs(contours.size());for (size_t i = 0; i < contours.size(); i++) {contours_moments[i] = moments(contours[i]);ccs[i] = Point(static_cast<float>(contours_moments[i].m10 / contours_moments[i].m00), static_cast<float>(contours_moments[i].m01 / contours_moments[i].m00));}Mat drawImg;// = Mat::zeros(src.size(), CV_8UC3);src.copyTo(drawImg);for (size_t i = 0; i < contours.size(); i++) {if (contours[i].size() < 100) {continue;}Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));printf("center point x : %.2f y : %.2f\n", ccs[i].x, ccs[i].y);printf("contours %d area : %.2f arc length : %.2f\n", i, contourArea(contours[i]), arcLength(contours[i], true));drawContours(drawImg, contours, i, color, 2, 8, hierachy, 0, Point(0, 0));circle(drawImg, ccs[i], 2, color,2, 8);}imshow(output_win, drawImg);return;
}
五、多边形测试
1.相关理论
点多边形测试 : 测试一个点是否在给定的多边形内部,边缘或者外部。
2.相关API介绍
cv::pointPolygonTest
pointPolygonTest(
InputArray contour,// 输入的轮廓
Point2f pt, // 测试点
bool measureDist // 是否返回距离值,如果是false,1表示在内面,0表示在边界上,-1表示在外部,true返回实际距离
)
返回数据是double类型
程序示例
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>using namespace std;
using namespace cv;
int main(int argc, char** argv) {const int r = 100;Mat src = Mat::zeros(r * 4, r * 4, CV_8UC1);vector<Point2f> vert(6);vert[0] = Point(3 * r / 2, static_cast<int>(1.34*r)); vert[1] = Point(1 * r, 2 * r);vert[2] = Point(3 * r / 2, static_cast<int>(2.866*r)); vert[3] = Point(5 * r / 2, static_cast<int>(2.866*r));vert[4] = Point(3 * r, 2 * r); vert[5] = Point(5 * r / 2, static_cast<int>(1.34*r));for (int i = 0; i < 6; i++) {line(src, vert[i], vert[(i + 1) % 6], Scalar(255), 3, 8, 0);}vector<vector<Point>> contours;vector<Vec4i> hierachy;Mat csrc;src.copyTo(csrc);findContours(csrc, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));Mat raw_dist = Mat::zeros(csrc.size(), CV_32FC1);for (int row = 0; row < raw_dist.rows; row++) {for (int col = 0; col < raw_dist.cols; col++) {double dist = pointPolygonTest(contours[0], Point2f(static_cast<float>(col), static_cast<float>(row)), true);raw_dist.at<float>(row, col) = static_cast<float>(dist);}}double minValue, maxValue;minMaxLoc(raw_dist, &minValue, &maxValue, 0, 0, Mat());Mat drawImg = Mat::zeros(src.size(), CV_8UC3);for (int row = 0; row < drawImg.rows; row++) {for (int col = 0; col < drawImg.cols; col++) {float dist = raw_dist.at<float>(row, col);if (dist > 0) {drawImg.at<Vec3b>(row, col)[0] = (uchar)(abs(1.0 - (dist / maxValue)) * 255);}else if (dist < 0) {drawImg.at<Vec3b>(row, col)[2] = (uchar)(abs(1.0 - (dist / minValue)) * 255);} else {drawImg.at<Vec3b>(row, col)[0] = (uchar)(abs(255 - dist));drawImg.at<Vec3b>(row, col)[1] = (uchar)(abs(255 - dist));drawImg.at<Vec3b>(row, col)[2] = (uchar)(abs(255 - dist));}}}const char* output_win = "point polygon test demo";char input_win[] = "input image";namedWindow(input_win, CV_WINDOW_AUTOSIZE);namedWindow(output_win, CV_WINDOW_AUTOSIZE);imshow(input_win, src);imshow(output_win, drawImg);waitKey(0);return 0;
}
相关文章:

Opencv-C++笔记 (18) : 轮廓和凸包
文章目录 一、轮廓findContours发现轮廓drawContours绘制轮廓代码 二.几何及特性概括——凸包(Convex Hull)凸包概念凸包扫描算法介绍——Graham扫描算法 相关API介绍程序示例轮廓集合及特性性概括——轮廓周围绘制矩形框和圆形相关理论介绍轮廓周围绘制矩形 -API绘制步骤程序实…...

【半监督医学图像分割】2022-MedIA-UWI
【半监督医学图像分割】2022-MedIA-UWI 论文题目:Semi-supervise d me dical image segmentation via a triple d-uncertainty guided mean teacher model with contrastive learning 中文题目:基于对比学习的三维不确定性指导平均教师模型的半监督图像分…...
python发送邮件
为了安全起见,我们发送邮件需要使用tls,这样发送的内容都是加密的了,但是该工具批量发送带有自定义内容的邮件不方便,于是写了一个py脚本,使用--data参数,方便批量发送,我们的策略是每天随机发送…...

gitee上传本地项目bug
🤮这个破bug不知道浪费了多长时间,以前没有记录,每次都忘记,这次记下来 问题描述 gitee创建仓库,然后根据它提示的如下命令,但一直报错 原因分析: 把命令复制出来,粘贴到Sublime …...

自然语言处理2-NLP
目录 自然语言处理2-NLP 如何把词转换为向量 如何让向量具有语义信息 在CBOW中 在Skip-gram中 skip-gram比CBOW效果更好 CBOW和Skip-gram的算法实现 Skip-gram的理想实现 Skip-gram的实际实现 自然语言处理2-NLP 在自然语言处理任务中,词向量(…...

穿上App外衣,保持Web灵魂——PWA温故
早在2015年,设计师弗朗西斯贝里曼和Google Chrome的工程师亚历克斯罗素提出“PWA(渐进式网络应用程序)”概念,将网络之长与应用之长相结合,其核心目标就是提升 Web App 的性能,改善 Web App以媲美Native的流…...
【跟小嘉学 Rust 编程】二十六、Rust的序列化解决方案(Serde)
系列文章目录 【跟小嘉学 Rust 编程】一、Rust 编程基础 【跟小嘉学 Rust 编程】二、Rust 包管理工具使用 【跟小嘉学 Rust 编程】三、Rust 的基本程序概念 【跟小嘉学 Rust 编程】四、理解 Rust 的所有权概念 【跟小嘉学 Rust 编程】五、使用结构体关联结构化数据 【跟小嘉学…...
菜鸟教程《Python 3 教程》笔记(14):函数
菜鸟教程《Python 3 教程》笔记(14) 14 函数14.1 参数传递14.1.1 可更改(mutable)与不可更改(immutable)对象14.1.2 python 传不可变对象实例 14.2 参数14.2.1 必需参数14.2.2 关键字参数14.2.3 默认参数14.2.4 不定长参数 14.3 匿名函数14.4 强制位置参…...

SEC推迟ETF,BTC跌破26k,十年之约#6逢跌加仓
今日荐读:8.31教链内参《美证监会推迟所有的BTC现货ETF申请》。刘教链Pro《BTC的流速》。 * * * 刘教链 原创 * * * 原本是9.2的截止日,美SEC昨晚就忙不迭地放出了话,所有现货比特币ETF的申请,推迟,统统推迟。不管你什…...
c++20 多线程并发 latch barrier semaphore
背景: c20 关于多线程并发新增了 latch, barrier, semaphore ,接下来就按照一个一个进行介绍 latch latch 是一次性使用的线程协调点, 一旦给定数量的线程达到latch点时, 所有线程都会解除阻塞, 并继续执行. 基本上它是一个计数器, 在每个线程到达latch点时倒数, 一旦计数器达…...

【8 排序】简单选择排序。
顺序表: void Swap(int &a,int &b){int temp;tempa;ab;btemp; } void SelectSort(int A[],int n){int min,i,j;for(i0;i<n-1;i){mini;for(ji1;j<n;j)if(A[j]<A[min])minj;if(min!i)Swap(A[i],A[min]);} } 单链表: void SelectSort…...

中国太保首席数据库专家林春:先难后易,核心系统数据库升级复盘
P17 是中国太平洋保险(以下简称太保)关联关系最为复杂、商业数据库绑定程度最深、业务影响最多的核心系统之一。但就是这样一个对太保业务至关重要的系统却被选为数据库升级的“实验品”。当然,说是“实验品”只是因为这是太保第一次对关键的…...

数字孪生智慧工厂:电缆厂 3D 可视化管控系统
近年来,我国各类器材制造业已经开始向数字化生产转型,使得生产流程变得更加精准高效。通过应用智能设备、物联网和大数据分析等技术,企业可以更好地监控生产线上的运行和质量情况,及时发现和解决问题,从而提高生产效率…...
使用WebSocket实现聊天功能
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、数据库设计二、实现代码1.SessionWrap2.websocket3.insertMessage4.清除未读 前言 使用WebSocket实现一对一的聊天功能与未读消息功能 一、数据库设计 会话…...

Ubuntu升级Cmake、gcc、g++
背景 最近要安装llvm,我选择的是从源码安装,所以要使用Cmake进行构建项目。但是服务器上的Cmake、gcc、g的版本都太低了,不符合要求,所以要对此进行升级。在本博客中采用的升级方法不一定是最好的方法(因为我也是参考…...

8月28日上课内容 第四章 MySQL备份与恢复
本章结构 前言:日志⭐⭐ MySQL 的日志默认保存位置为 /usr/local/mysql/data ##配置文件 vim /etc/my.cnf [mysqld] ##错误日志,用来记录当MySQL启动、停止或运行时发生的错误信息,默认已开启 log-error/usr/local/mysql/data/mysql_error.l…...
es字段查询加keyword和不加keyword的区别
在ES(Elasticsearch)中,查询字段名后面加上"keyword"和不加"keyword"有着不同的含义和用途。 当字段名后面加上"keyword"时,表示该字段是一个keyword类型的字段。Keyword类型的字段会将文本作为一…...
前端JavaScript将数据转换成JSON字符串以及将JSON字符串转换成对象的两个API
在前端 JavaScript 中,你可以使用 JSON.stringify() 方法将 JavaScript 数据转换成 JSON 字符串,以及使用 JSON.parse() 方法将 JSON 字符串转换成 JavaScript 对象。下面是这两个 API 的详细说明和示例: JSON.stringify(): 用于…...

Spring——Spring Boot基础
文章目录 第一个helloword项目新建 Spring Boot 项目Spring Boot 项目结构分析SpringBootApplication 注解分析新建一个 Controller大功告成,运行项目 简而言之,从本质上来说,Spring Boot 就是 Spring,它做了那些没有它你自己也会去做的 Spri…...

Python基础之基础语法(二)
Python基础之基础语法(二) 语言类型 静态语言 如:C C Java ina a 100 a 100 a abc # 不可以静态语言需要指定声明标识符的类型,之后不可以改变类型赋值。静态语言变异的时候要检查类型,编写源代码,编译时检查错误。 动态语…...

微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...

什么是库存周转?如何用进销存系统提高库存周转率?
你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...

2025盘古石杯决赛【手机取证】
前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来,实在找不到,希望有大佬教一下我。 还有就会议时间,我感觉不是图片时间,因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...

select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...

PHP 8.5 即将发布:管道操作符、强力调试
前不久,PHP宣布了即将在 2025 年 11 月 20 日 正式发布的 PHP 8.5!作为 PHP 语言的又一次重要迭代,PHP 8.5 承诺带来一系列旨在提升代码可读性、健壮性以及开发者效率的改进。而更令人兴奋的是,借助强大的本地开发环境 ServBay&am…...
区块链技术概述
区块链技术是一种去中心化、分布式账本技术,通过密码学、共识机制和智能合约等核心组件,实现数据不可篡改、透明可追溯的系统。 一、核心技术 1. 去中心化 特点:数据存储在网络中的多个节点(计算机),而非…...
xmind转换为markdown
文章目录 解锁思维导图新姿势:将XMind转为结构化Markdown 一、认识Xmind结构二、核心转换流程详解1.解压XMind文件(ZIP处理)2.解析JSON数据结构3:递归转换树形结构4:Markdown层级生成逻辑 三、完整代码 解锁思维导图新…...

ui框架-文件列表展示
ui框架-文件列表展示 介绍 UI框架的文件列表展示组件,可以展示文件夹,支持列表展示和图标展示模式。组件提供了丰富的功能和可配置选项,适用于文件管理、文件上传等场景。 功能特性 支持列表模式和网格模式的切换展示支持文件和文件夹的层…...

2025年- H71-Lc179--39.组合总和(回溯,组合)--Java版
1.题目描述 2.思路 当前的元素可以重复使用。 (1)确定回溯算法函数的参数和返回值(一般是void类型) (2)因为是用递归实现的,所以我们要确定终止条件 (3)单层搜索逻辑 二…...

数据分析六部曲?
引言 上一章我们说到了数据分析六部曲,何谓六部曲呢? 其实啊,数据分析没那么难,只要掌握了下面这六个步骤,也就是数据分析六部曲,就算你是个啥都不懂的小白,也能慢慢上手做数据分析啦。 第一…...