opencv c++ 光流法、稀疏光流法、稠密光流法、均值迁移追踪(meanshift、camshift)

news2025/1/16 5:12:12

1、概念

参考:

(70条消息) 什么是光流法_张年糕慢慢走的博客-CSDN博客_光流法

 (70条消息) 计算机视觉--光流法(optical flow)简介_T-Jhon的博客-CSDN博客_光流法

此外,还有基于均值迁移的目标追踪方法:

camshift:

(75条消息) opencv3中camshift详解(一)camshiftdemo代码详解_夏言谦的博客-CSDN博客

meanshift:

(75条消息) Opencv——用均值平移法meanshift做目标追踪_走过,莫回头的博客-CSDN博客

2、API

 光流法:

void cv::calcOpticalFlowPyrLK	(	InputArray 	prevImg,
                                    InputArray 	nextImg,
                                    InputArray 	prevPts,
                                    InputOutputArray 	nextPts,
                                    OutputArray 	status,
                                    OutputArray 	err,
                                    Size 	winSize = Size(21, 21),
                                    int 	maxLevel = 3,
                                    TermCriteria 	criteria 
                                    int 	flags = 0,
                                    double 	minEigThreshold = 1e-4 
                                    )		

criteria = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 0.01)

 
prevImg ——前一帧图像。
nextImg ——后一帧图像。
prevPts ——前一帧的角点vector,初始需要输入预获取的角点。
nextPts ——后一帧的角点vector
status——output status vector (of unsigned chars); each element of the vector is set to 1 if the flow for the corresponding features has been found, otherwise, it is set to 0.
err ——输出的角点的错误信息。
winSize ——光流法窗口大小。
maxLevel——光流层数,0只有1层,1为2层,以此类推
criteria ——停止条件
flags ——operation flags:
OPTFLOW_USE_INITIAL_FLOW uses initial estimations, stored in nextPts; if the flag is not set, then prevPts is copied to nextPts and is considered the initial estimate.
OPTFLOW_LK_GET_MIN_EIGENVALS use minimum eigen values as an error measure (see minEigThreshold description); if the flag is not set, then L1 distance between patches around the original and a moved point, divided by number of pixels in a window, is used as a error measure.
minEigThreshold——the algorithm calculates the minimum eigen value of a 2x2 normal matrix of optical flow equations (this matrix is called a spatial gradient matrix in [25]), divided by number of pixels in a window; if this value is less than minEigThreshold, then a corresponding feature is filtered out and its flow is not processed, so it allows to remove bad points and get a performance boost.

定义停止条件:当迭代10次不需要计算,两次的计算结果差小于0.01也不需要计算
    TermCriteria criteria = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 10, 0.01); 

 稠密光流法:


void cv::calcOpticalFlowFarneback	(	InputArray 	prev,
                                        InputArray 	next,
                                        InputOutputArray 	flow,
                                        double 	pyr_scale,
                                        int 	levels,
                                        int 	winsize,
                                        int 	iterations,
                                        int 	poly_n,
                                        double 	poly_sigma,
                                        int 	flags 
                                        )	

flow——输出的光流场数据Mat_<Point2f>对象
pyr_scale——金字塔前后层大小之比,一般取0.5.
levels ——光流金字塔层数,一般取3.
iterations ——迭代次数。
poly_n ——多项式阶数 , typically poly_n =5 or 7.
poly_sigma ——standard deviation of the Gaussian that is used to smooth derivatives used as a basis for the polynomial expansion; for poly_n=5, you can set poly_sigma=1.1, for poly_n=7, a good value would be poly_sigma=1.5.

 camshift:


RotatedRect cv::CamShift	(	InputArray 	probImage,
                                Rect & 	window,
                                TermCriteria 	criteria 
                                )	

window——Initial search window. 

 meanshift:


int cv::meanShift	(	InputArray 	probImage,
                        Rect & 	window,
                        TermCriteria 	criteria 
                        )		

3、代码

 光流法:

void QuickDemo::shade_flow()
{
	VideoCapture capture("https://vd4.bdstatic.com/mda-nm67dtz2afxmwat7/sc/cae_h264/1670390212002064886/mda-nm67dtz2afxmwat7.mp4?v_from_s=hkapp-haokan-hbf&auth_key=1670484546-0-0-792e5c9ffc23b54e025e91106b771e99&bcevod_channel=searchbox_feed&cd=0&pd=1&pt=3&logid=3546818474&vid=6396276202448861552&abtest=104960_2&klogid=3546818474");
	if (capture.isOpened()) {
		cout << "ok!" << endl;
	}
	//获取合适帧率
	int fps = capture.get(CAP_PROP_FPS);
	cout << "fps" << fps << endl;

	Mat old_frame, old_gray;
	capture.read(old_frame);
	cvtColor(old_frame, old_gray, COLOR_BGR2GRAY);
	//角点获取
	vector<Point2f> feature_pts;
	goodFeaturesToTrack(old_gray, feature_pts, 100, 0.01,10,Mat(),3,false);

	Mat frame, gray;
	vector<Point2f> pts[2];
	pts[0].insert(pts[0].end(), feature_pts.begin(), feature_pts.end());

	vector<uchar> status;
	vector<float> err;
	//定义停止条件,当迭代10次不需要计算,两次的计算结果差小于0.01也不需要计算
	TermCriteria criteria = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 10, 0.01);

	while (true)
	{
		//capture >> frame;//尽量不用
		//逐帧传入视频
		bool ret = capture.read(frame);
		if (!ret)break;

		cvtColor(frame, gray, COLOR_BGR2GRAY);
		//光流法函数
		calcOpticalFlowPyrLK(old_frame, frame, pts[0], pts[1], status, err, Size(21, 21), 3, criteria, 0);
		//检测是否出错
		size_t i = 0, k = 0;
		RNG rng(12345);
		for (i = 0; i < pts[1].size(); ++i) {
			//距离与状态检测
			if (status[i]) {
				pts[0][k] = pts[0][i];
				pts[1][k++] = pts[1][i];
				int b = rng.uniform(0, 255);
				int g = rng.uniform(0, 255);
				int r = rng.uniform(0, 255);
				circle(frame, pts[1][i], 3, Scalar(b, g, r), 3, 8);
				line(frame, pts[0][i], pts[1][i], Scalar(b, g, r), 3, 8);
			}
		}
		//更新角点vector容量
		pts[0].resize(k);
		pts[1].resize(k);

		imshow("frame", frame);
		char c = waitKey(fps+10);
		if (c == 27)
			break;

		//更换帧图像,帧角点信息
		swap(pts[1], pts[0]);
		swap(old_gray, gray);
	}
	capture.release();
}

 稀疏光流法:

void QuickDemo::poor_shade_flow()
{
	VideoCapture capture("https://vd4.bdstatic.com/mda-nm67dtz2afxmwat7/sc/cae_h264/1670390212002064886/mda-nm67dtz2afxmwat7.mp4?v_from_s=hkapp-haokan-hbf&auth_key=1670484546-0-0-792e5c9ffc23b54e025e91106b771e99&bcevod_channel=searchbox_feed&cd=0&pd=1&pt=3&logid=3546818474&vid=6396276202448861552&abtest=104960_2&klogid=3546818474");
	if (capture.isOpened()) {
		cout << "ok!" << endl;
	}
	//获取合适帧率
	int fps = capture.get(CAP_PROP_FPS);
	cout << "fps" << fps << endl;

	Mat old_frame, old_gray;
	capture.read(old_frame);
	cvtColor(old_frame, old_gray, COLOR_BGR2GRAY);

	//角点光源初始化
	vector<Point2f> feature_pts;
	goodFeaturesToTrack(old_gray, feature_pts, 50, 0.01, 50, Mat(), 3, false);
	vector<Point2f> pts[2];
	pts[0].insert(pts[0].end(), feature_pts.begin(), feature_pts.end());

	vector<Point2f> initial_points;
	initial_points.insert(initial_points.end(), feature_pts.begin(), feature_pts.end());

	Mat frame, gray;
	vector<uchar> status;
	vector<float> err;
	//定义停止条件,当迭代10次不需要计算,两次的计算结果差小于0.01也不需要计算
	TermCriteria criteria = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 10, 0.01);

	while (true)
	{
		//capture >> frame;//尽量不用
		//逐帧传入视频
		bool ret = capture.read(frame);
		if (!ret)break;

		cvtColor(frame, gray, COLOR_BGR2GRAY);
		//光流法函数
		calcOpticalFlowPyrLK(old_frame, frame, pts[0], pts[1], status, err, Size(21, 21), 3, criteria, 0);
		//检测是否出错
		size_t i = 0, k = 0;
		RNG rng(12345);
		for (i = 0; i < pts[1].size(); ++i) {
			//距离与状态检测
			double dist = abs(pts[0][i].x - pts[1][i].x) + abs(pts[0][i].y - pts[1][i].y);
			if (status[i] && dist >2) {
				pts[0][k] = pts[0][i];
				pts[1][k++] = pts[1][i];
				initial_points[k] = initial_points[i];
				int b = rng.uniform(0, 255);
				int g = rng.uniform(0, 255);
				int r = rng.uniform(0, 255);
				circle(frame, pts[1][i], 3, Scalar(b, g, r), 3, 8);
				line(frame, pts[0][i], pts[1][i], Scalar(b, g, r), 3, 8);
			}
		}
		//更新角点vector容量
		pts[0].resize(k);
		pts[1].resize(k);
		initial_points.resize(k);

		//绘制跟踪线
		draw_line(frame,pts[0],pts[1]);
		imshow("frame", frame);
		char c = waitKey(fps + 10);
		if (c == 27)
			break;

		//更换帧图像,帧角点信息
		swap(pts[1], pts[0]);
		swap(old_gray, gray);

		//在稀疏光源法还要重新初始化,当角点数小于40时,重新初始化
		if (pts[0].size()<40) {
			goodFeaturesToTrack(old_gray, feature_pts, 50, 0.01, 50, Mat(), 3, false);
			pts[0].insert(pts[0].end(), feature_pts.begin(), feature_pts.end());
			initial_points.insert(initial_points.end(), feature_pts.begin(), feature_pts.end());
		}
	}
	capture.release();
}

void QuickDemo::draw_line(Mat& image, vector<Point2f> pts1, vector<Point2f> pts2)
{	
	vector<Scalar>lut;
	RNG rng(12345);
	for (auto i = 0; i < pts1.size(); ++i) {
		int b = rng.uniform(0, 255);
		int g = rng.uniform(0, 255);
		int r = rng.uniform(0, 255);
		lut.push_back(Scalar(b, g, r));
	}
	for (auto i = 0; i < pts1.size(); ++i) {
		line(image, pts1[i], pts2[i], Scalar(255, 0, 0), 2, 8);
	}
}

稠密光流法:

void QuickDemo::dense_shade_flow()
{
	VideoCapture capture("https://vd4.bdstatic.com/mda-nm67dtz2afxmwat7/sc/cae_h264/1670390212002064886/mda-nm67dtz2afxmwat7.mp4?v_from_s=hkapp-haokan-hbf&auth_key=1670484546-0-0-792e5c9ffc23b54e025e91106b771e99&bcevod_channel=searchbox_feed&cd=0&pd=1&pt=3&logid=3546818474&vid=6396276202448861552&abtest=104960_2&klogid=3546818474");
	if (!capture.isOpened())
		cout << "error" << endl;
	namedWindow("frame", WINDOW_FREERATIO);
	namedWindow("result", WINDOW_FREERATIO);

	int fps = capture.get(CAP_PROP_FPS);

	//定义当前帧,前一帧,并灰度转换
	Mat frame, preframe;
	Mat gray, pregray;
	capture.read(preframe);
	cvtColor(preframe, pregray, COLOR_BGR2GRAY);
	Mat hsv = Mat::zeros(preframe.size(), preframe.type());

	Mat mag = Mat::zeros(hsv.size(), CV_32FC1);
	Mat ang = Mat::zeros(hsv.size(), CV_32FC1);
	Mat xpts = Mat::zeros(hsv.size(), CV_32FC1);
	Mat ypts = Mat::zeros(hsv.size(), CV_32FC1);
	
	//输出光流场数据空间定义
	Mat_<Point2f> flow;

	//通道拆分
	vector<Mat> mv;
	split(hsv, mv);

	Mat bgr;
	while (true) {
		bool ret = capture.read(frame);
		char c = waitKey(fps + 5);
		if (c == 27)break;

		cvtColor(frame, gray, COLOR_BGR2GRAY);
		calcOpticalFlowFarneback(pregray, gray, flow, 0.5, 3, 15, 3, 5, 1.2, 0);

		for (int row = 0; row < flow.rows; ++row) {
			for (int col = 0; col < flow.cols; ++col) {
				const Point2f& flow_xy = flow.at<Point2f>(row, col);

				//取出对应x、y方向的光流场数据
				xpts.at<float>(row, col) = flow_xy.x;
				ypts.at<float>(row, col) = flow_xy.y;
			}

		}
		//转极坐标空间,并归一化到(0,255)
		cartToPolar(xpts, ypts, mag, ang);
		ang = ang * 180 / CV_PI/2.0;
		normalize(mag, mag, 0, 255, NORM_MINMAX);

		//绝对值处理
		convertScaleAbs(mag, mag);
		convertScaleAbs(ang,ang);

		//各通道图像更新,并融合通道
		mv[0] = ang;
		mv[1] = Scalar(255);
		mv[2] = mag;
		merge(mv, hsv);

		cvtColor(hsv, bgr, COLOR_HSV2BGR);
		imshow("frame", frame);
		imshow("result", bgr);

	}
	capture.release();
}

camshift:

Mat frame, gray; //源图像和源灰度图像
Mat framecopy;  //用于拷贝出的源图像
Mat framerect, framerecthsv;  //矩形选取后的图像
Rect rect;      //鼠标选取的矩形


//直方图
int histSize = 200;
float histR[] = { 0,255 };
const float* histRange = histR;
int channels[] = { 0,1 };
Mat dstHist;


//保存目标轨迹  
std::vector<Point> pt;


//鼠标控制
bool firstleftbutton = false;
bool leftButtonDownFlag = false; //左键单击后视频暂停播放的标志位 
Point rectstartPoint; //矩形框起点    
Point rectstopPoint; //矩形框终点    
void onMouse(int event, int x, int y, int flags, void* ustc); //鼠标回调函数    



void onMouse(int event, int x, int y, int flags, void* ustc)
{
	//鼠标左键按下
	if (event == EVENT_LBUTTONDOWN)
	{
		leftButtonDownFlag = true; //更新按下标志位
		rectstartPoint = Point(x, y); //设置矩形的开始点
		rectstopPoint = rectstartPoint;   //刚按下时结束点和开始点一样
	}
	//当鼠标按下并且开始移动时
	else if (event == EVENT_MOUSEMOVE && leftButtonDownFlag)
	{
		framecopy = frame.clone();  //复制源图像
		rectstopPoint = Point(x, y); //设置矩形的结束点
		if (rectstartPoint != rectstopPoint)
		{
			//当矩形的开始点和结束点不同后在复制的图像上绘制矩形
			rectangle(framecopy, rectstartPoint, rectstopPoint,
				Scalar(255, 255, 255));
		}
		imshow("srcvideo", framecopy);
	}
	//当鼠标抬起时
	else if (event == EVENT_LBUTTONUP)
	{
		leftButtonDownFlag = false;//按下鼠标标志位复位
		rect = Rect(rectstartPoint, rectstopPoint);//设置选中后的矩形
		framerect = frame(rect); //通过矩形获取到选取后的图像
		imshow("selectimg", framerect);//显示出来选择后的图像
		cvtColor(framerect, framerecthsv, COLOR_BGR2HSV);
		//直方图计算
		calcHist(&framerecthsv, 2, channels, Mat(), dstHist, 1, &histSize, &histRange, true, false);
		//归一化显示
		normalize(dstHist, dstHist, 0, 255, NORM_MINMAX);
	}


}
void Quick_Demo::object_follow_demo()
{

	VideoCapture cap(0);

	namedWindow("srcvideo", WINDOW_FREERATIO);

	//设置图像中鼠标事件
	setMouseCallback("srcvideo", onMouse, 0);
	bool first = false;
	while (true)
	{
		char ch = waitKey(50);
		//当鼠标左键没有按下时
		if (!leftButtonDownFlag)
		{
			cap >> frame;
		}
		//图像为空或Esc键按下退出播放    
		if (ch == 27)
			break;
		//如果已经截取了图像进行处理

		if (rectstartPoint != rectstopPoint && !leftButtonDownFlag)
		{
			Mat imageHSV;
			Mat calcBackImage;

			cvtColor(frame, imageHSV, COLOR_BGR2HSV);

			//反向投影
			calcBackProject(&imageHSV, 2, channels,
				dstHist, calcBackImage, &histRange);

			TermCriteria criteria(TermCriteria::MAX_ITER +
				TermCriteria::EPS, 10, 1);

			CamShift(calcBackImage, rect, criteria);
			//更新模板
			Mat imageROI = imageHSV(rect);
			framerecthsv = imageHSV(rect);
			calcHist(&imageROI, 2, channels, Mat(),
				dstHist, 1, &histSize, &histRange);

			normalize(dstHist, dstHist, 0.0, 1.0, NORM_MINMAX);   //归一化  
			rectangle(frame, rect, Scalar(255, 0, 0), 3);    //目标绘制    

			pt.push_back(Point(rect.x + rect.width / 2,
				rect.y + rect.height / 2));//储存roi区域的中心点
			for (int i = 0; i < pt.size() - 1; i++)
			{
				line(frame, pt[i], pt[i + 1], Scalar(0, 255, 0), 2.5);//绘制roi区域的中心点
			}
		}
		imshow("srcvideo", frame);
		
	}
	cap.release();
	waitKey(0);
	destroyAllWindows();
}

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

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

相关文章

【VC7升级VC8】将vCenter Server 7.X 升级为 vCenter Server 8 (上)—— VC 8系统要求与升级前的说明

目录1. 新 vCenter Server Appliance 8的系统要求1.1 确认升级路径1.2 硬件要求1.3 存储要求1.4 软件要求1.5 vSphere Client 软件要求2. 升级说明2.1 升级阶段介绍2.2 旧VC7虚拟机的信息2.3 打开升级用安装程序&#xff08;1&#xff09;进入vcsa镜像目录&#xff08;2&#x…

leetcode(力扣)算法刷题-160. 相交链表

描述&#xff1a; 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交&#xff1a; 题目数据保证整个链式结构中不存在环。 注意&#xff0c…

Java基础入门第三版黑马课后习题(编程部分)

第 1 章 Java 开发入门 第 2 章 Java 编程基础 1. 编写程序,计算13…99的值,要求如下&#xff1a; (1)使用循环语句实现1~99的遍历 (2)在遍历过程中,通过条件判断当前的数是否为奇数,如果是就累加,否则不加。 public class getSum { 2 public static void main(String[] ar…

vue elementui 多选级联组件 全选功能

Vue 封装 多选级联组件 支持全选功能 使用方式和elm官方一致&#xff0c;原参数一致主要参数&#xff1a; options&#xff1a;级联数菜单。多维数组mulSelectedVal&#xff1a;绑定值。id集合。且取值最后一层idcollapseTags&#xff1a;是否tag展示fieldNames&#xff1a;自…

酵母葡聚糖硫酸酯(SPS)|葡聚糖修饰异黄酮|右旋糖酐修饰Savinase蛋白酶

酵母葡聚糖硫酸酯(SPS)|葡聚糖修饰异黄酮|右旋糖酐修饰Savinase蛋白酶 酵母葡聚糖硫酸酯(SPS) 中文名称&#xff1a;酵母葡聚糖硫酸酯(SPS) 纯度&#xff1a;95% 存储条件&#xff1a;-20C&#xff0c;避光&#xff0c;避湿 外观:固体或粘性液体 包装&#xff1a;瓶装/袋…

C++ 函数重载的细节

前言&#xff1a;如果不想看论证&#xff0c;可以直接点击总结&#xff0c;跳转到最后 目录 总结 1、使用重载函数时&#xff0c;如果数据类型不匹配&#xff0c;C尝试使用类型转换与形参进行匹配&#xff0c;如果转换后有多个函数能匹配上&#xff0c;编译器将报错&#xff1…

【重识云原生】第六章容器基础6.4.12节——IPv4与IPv6双协议栈配置

1 IPv4/IPv6 双协议栈特性 Kubernetes v1.23 [stable] IPv4/IPv6 双协议栈网络能够将 IPv4 和 IPv6 地址分配给 Pod 和 Service。 从 1.21 版本开始&#xff0c;Kubernetes 集群默认启用 IPv4/IPv6 双协议栈网络&#xff0c; 以支持同时分配 IPv4 和 IPv6 地址。 1.1 支持的…

6 张配图通俗易懂说透 K8S 请求和限制

6 张配图通俗易懂说透 K8S 请求和限制 在 Kubernetes 中使用容器时&#xff0c;了解涉及的资源是什么以及为何需要它们很重要。有些进程比其他进程需要更多的 CPU 或内存。这很关键&#xff0c;永远不应该让进程挨饿。知道了这一点&#xff0c;我们应该正确配置容器和 Pod&…

ICV:L2级乘用车渗透率预计将在2025年超过50%

全球前沿科技咨询机构ICV近期发布了全球乘用车市场的分析报告。ICV在报告中指出&#xff0c;作为汽车消费大国之一的中国在2022年仍是乘用车销量第一的国家。目前L0和L1级别的自动驾驶乘用车仍占市场主导地位&#xff0c;但随着供应端在技术方面的不断突破以及需求端在认可度方…

让你的Python程序像C语言一样快

让你的Python程序像C语言也一样快 在《Python性能优化指南–让你的Python代码快x3倍的秘诀》中有提到很多加速Python程序的方法&#xff0c;在随后的系列文章中我也为大家专门介绍了用PyPy加速Python 和 用Numba&#xff1a;一行代码将Python程序运行速度提升100倍。但在所有方…

VM系列振弦读数模块通讯协议

通讯协议是上位机通过 VMXXX 模块支持的数字接口完成信息交互的数据格式、传输步骤、 通讯速率等的一系列预先约定。上位机必须按照本章描述的通讯协议规则来完成与 VMXXX 的数据交互工作。 寄存器机制 VMXXX 内部维护有若干寄存器&#xff0c;模块在寄存器参数值的控制下…

【LeetCode_字符串_逻辑分析】13. 罗马数字转整数

目录考察点第一次&#xff1a;2022年12月8日15:24:16解题思路代码展示优秀的解题思路1. 总结规律2. 字符串替换题目描述13. 罗马数字转整数 考察点 逻辑分析能力 第一次&#xff1a;2022年12月8日15:24:16 解题思路 分析能力有待提高 代码展示 class Solution {public i…

【HTML5期末作业】用HTML+CSS一个兰州交通大学官网网站

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

百度 Android 直播秒开体验优化

作者 | 任雪龙 导读 网络直播功能作为一项互联网基本能力已经越来越重要&#xff0c;手机中的直播功能也越来越完善&#xff0c;电商直播、新闻直播、娱乐直播等多种直播类型为用户提供了丰富的直播内容。随着直播的普及&#xff0c;为用户提供极速、流畅的直播观看体验也越来越…

外汇天眼:什么是外汇动量交易?新手指南

1. 什么是动量交易&#xff1f; 我们需要了解的第一件事是动量到底是什么。势头是字面意义上的趋势强度。动量交易策略涉及仅在强劲的价格趋势方向开仓&#xff0c;利用持续的价格变动&#xff0c;并在趋势逆转之前退出。 动量交易者通常不会担心趋势在哪里结束和开始&#x…

计算机毕业设计ssm+vue基本微信小程序的校园通知小程序系统 uniapp 小程序

项目介绍 随着互联网技术的发发展,计算机技术广泛应用在人们的生活中,逐渐成为日常工作、生活不可或缺的工具。在高校,各种管理系统层出不穷,为校园通知管理开发必要的系统,能够有效的提升管理效率。一直以来,校园通知一直没有进行系统化的管理,学生无法准确掌握高校通知状态,…

35岁以上的那些测试员何去何从?

人人都说IT行业&#xff1a;35岁就是一道坎&#xff01;跨不过就是一道中年危机&#xff0c;跨过了就成养老保险。那么35岁之后&#xff0c;软件测试从业者都去哪了&#xff1f;能力不行&#xff0c;中年危机很多刚入行的测试的新人&#xff0c;毫无经验&#xff0c;但是远远却…

数图互通高校房产管理——移动端微信小程序

数图互通房产管理系统在这方面做得比较全面&#xff1b; 随着移动智能手机功能的应用日益成熟&#xff0c;学校要求使用移动端微信小程序端进行房产清查、房产数据查询功能。可以利用手机等移动设备来现场查看房屋实际使用情况和清查房屋数据&#xff0c;也可以通过移动终端查…

日记:“实战深度学习”-第1天

机缘 说起来有点偶然&#xff0c;在某书APP中随手详细介绍了学习深度学习相关的历程&#xff0c;断断续续应该发了几百个笔记&#xff0c;持续时间有大概&#xff11;.5年左右&#xff0c;然后某一天清华出版社的赵编辑突然找到我&#xff0c;问我能否分享一下学习的过程&#…

Spring源码深度解析:十二、后处理器 BeanPostProcessor

一、前言 文章目录&#xff1a;Spring源码深度解析&#xff1a;文章目录 二、BeanPostProcessor 所谓的BeanPostProcessor翻译过来就是Bean后处理器。 1. 什么是 BeanPostProcessor BeanPostProcessor是 Spring提供给我们的一个非常重要的扩展接口&#xff0c;并且Spring内…