Object Tracking using OpenCV (C++/Python)(使用OpenCV进行目标跟踪)

本博客翻译搬运自https://www.learnopencv.com/object-tracking-using-opencv-cpp-python,用于初入目标跟踪的新手学习,转贴请注明!

使用OpenCV进行目标跟踪(C++/Python)

在本教程里,我们将学习OpenCV3.0中引入的OpenCV跟踪API。我们将学习如何以及何时使用OpenCV3.4.1中提供的7中不同的跟踪器——BOOSTING,MIL,KCF,TLD,MEDIANFLOW,GOTURN和MOSSE。我们还将学习现代跟踪算法背后的一般理论。

我的朋友Boris Babenko完美的解决了这个问题,正如下面的这个完美的实时人脸跟踪器所示!开玩笑的说,下面的这个GIF描述了我们想要的理想物体跟踪器——速度,准确性和面对遮挡的鲁棒性。

OpenCV目标跟踪样例:

如果你没有时间阅读整个教程,那就看看下面这个视频并了解一下用法。但是如果你想系统学习一下目标跟踪,那就完整读下去。

视频地址(需FQ):https://www.youtube.com/watch?reload=9&v=61QjSz-oLr8&feature=youtu.be

什么是目标跟踪?

简单的说,在一个视频的连续帧中定位目标就称之为跟踪。

这个定义听起来很直接但是在计算机视觉和机器学习领域,跟踪是一个非常广泛的术语,涵盖概念上相似但技术上不同的想法。举个例子,下面所有不同的但却相关的方法均是可用在目标跟踪的研究领域的。

1.密集光流法:这类算法有助于估计视频帧中每个像素的运动矢量。

2.稀疏光流法:这类算法,如Kanade-Lucas-Tomashi(KLT)特征跟踪器,跟踪图像中几个特征点的位置。

3.卡尔曼滤波:这是一个非常流行的信号处理算法,用于根据先前的运动信息预测运动物体的位置。这种算法的早期应用之一是导弹制导!

4.Meanshift和Camshift:这些是用于定位密度函数的最大值的算法。它们也用于跟踪领域。

5.单目标跟踪器:在此类跟踪器中,第一帧使用矩形标记来指示我们要跟踪的对象的位置。然后使用跟踪算法在后续帧中跟踪对象。在大多数实际应用中,这些跟踪器与物体检测器结合使用。

6.多目标跟踪器:在我们有快速物体探测器的情况下,检测每个帧中的多个物体然后运行轨迹查找算法来识别一帧中的哪个矩形对应于下一帧中的矩形是有意义的。

跟踪VS检测

如果你曾经使用OpenCV做过面部检测,你就明白它可以实时工作,你可以轻松地检测每一帧中的脸部。那么,你为什么需要首先进行跟踪?让我们探讨一下你可能想要跟踪视频中对象的不同原因,而不仅仅是重复检测。

1.跟踪比检测快:通常跟踪算法比检测算法快。理由很简单。当你跟踪在前一帧中检测到的对象时,你对该目标的外观了解很多。你还知道前一帧的位置以及运动的方向和速度。因此在下一帧中,您可以使用所有这些信息来预测下一帧中目标的位置,并围绕目标的预期位置进行小搜索,以准确定位目标。 一个好的跟踪算法将使用它所拥有的关于该目标的所有信息,而检测算法总是从头开始。因此,在设计有效系统时,通常在每第n帧上运行目标检测,而在其间的n-1帧中采用跟踪算法。为什么我们不直接检测第一帧中的目标并随后跟踪?确实,跟踪可以从它拥有的额外信息中获益,但是当它们长时间在障碍物后面或者如果它们移动速度太快以至于跟踪算法无法赶上时,你也可能失去对目标的跟踪。跟踪算法累积错误也很常见,跟踪目标的边界框会慢慢偏离其正在跟踪的目标。为了通过跟踪算法解决这些问题,每隔一段时间运行一次检测算法。检测算法在目标的大量示例上进行训练。因此,他们对目标的一般类有更多的了解。另一方面,跟踪算法更多地了解他们正在跟踪的类的特定实例。

2.检测失败时跟踪可以提供帮助:如果你在视频上运行人脸检测器并且人脸被物体遮挡,那么人脸检测大概率会失败。另一方面,优秀的跟踪算法可以解决某种程度的遮挡。在下面的视频中,你可以看到MIL跟踪器的作者Boris Bakenko博士演示MIL跟踪器如何在遮挡下工作

视频地址(需FQ):https://www.youtube.com/watch?v=n4QA3shA8Yw

3.跟踪保留身份:目标检测的输出是包含目标的矩形数组。但是,目标没有附加标识。例如,在下面的视频中,检测红点的检测器将输出对应于它在帧中检测到的所有点的矩形。在下一帧中,它将输出另一个矩形数组。在第一帧中,特定点可以由阵列中位置10处的举行表示,并且在第二帧中,它可以在位置17处。当在帧上使用检测时,我们不知道哪个矩形对应于哪个目标。另一方面,跟踪提供了一种字面连接点的方法。

视频地址(需FQ):https://www.youtube.com/watch?v=SsiHH_wrwDg

OpenCV 跟踪API

OpenCV3附带了新的跟踪API,其中包括许多单目标跟踪算法的实现。OpenCV 3.4.1中有7种不同的跟踪器——BOOSTING,MIL,KCF,TLD,MEDIANFLOW,GOTURN和MOSSE。

注意:OpenCV 3.2包括6种跟踪器——BOOSTING,MIL,TLD,MEDIANFLOW和MOSSE。OpenCV 3.1有5种跟踪器——BOOSTING,MIL,KCF,TLD,MEDIANFLOW。OpenCV 3.0包括4种跟踪器——BOOSTING,MIL,TLD,MEDIANFLOW。

更新:在OpenCV 3.3种,跟踪API已更改。请检查代码版本然后使用相应的API。

在我们提供算法的简单描述之前,让我们看看设置和用法。在下面的注释代码中,我们首先通过选择跟踪器类型来设置跟踪器——BOOSTING,MIL,KCF,TLD,MEDIANFLOW,GOTURN或MOSSE。然后我们打开一个视频并读取一帧。我们定义一个包含第一帧目标的边界框,并用第一帧和边界框初始化跟踪器。最后,我们从视频中读取帧并仅在循环中更新跟踪器以获得当前帧的新边界框。随后显示结果。

C++

#include <opencv2/opencv.hpp>
#include <opencv2/tracking.hpp>
#include <opencv2/core/ocl.hpp>using namespace cv;
using namespace std;// Convert to string
#define SSTR( x ) static_cast< std::ostringstream & >( \
( std::ostringstream() << std::dec << x ) ).str()int main(int argc, char **argv)
{// List of tracker types in OpenCV 3.4.1string trackerTypes[7] = {"BOOSTING", "MIL", "KCF", "TLD","MEDIANFLOW", "GOTURN", "MOSSE"};// vector <string> trackerTypes(types, std::end(types));// Create a trackerstring trackerType = trackerTypes[2];Ptr<Tracker> tracker;#if (CV_MINOR_VERSION < 3){tracker = Tracker::create(trackerType);}#else{if (trackerType == "BOOSTING")tracker = TrackerBoosting::create();if (trackerType == "MIL")tracker = TrackerMIL::create();if (trackerType == "KCF")tracker = TrackerKCF::create();if (trackerType == "TLD")tracker = TrackerTLD::create();if (trackerType == "MEDIANFLOW")tracker = TrackerMedianFlow::create();if (trackerType == "GOTURN")tracker = TrackerGOTURN::create();if (trackerType == "MOSSE")tracker = TrackerMOSSE::create();}#endif// Read videoVideoCapture video("videos/chaplin.mp4");// Exit if video is not openedif(!video.isOpened()){cout << "Could not read video file" << endl; return 1; } // Read first frame Mat frame; bool ok = video.read(frame); // Define initial boundibg box Rect2d bbox(287, 23, 86, 320); // Uncomment the line below to select a different bounding box bbox = selectROI(frame, false); // Display bounding box. rectangle(frame, bbox, Scalar( 255, 0, 0 ), 2, 1 ); imshow("Tracking", frame); tracker->init(frame, bbox);while(video.read(frame)){     // Start timerdouble timer = (double)getTickCount();// Update the tracking resultbool ok = tracker->update(frame, bbox);// Calculate Frames per second (FPS)float fps = getTickFrequency() / ((double)getTickCount() - timer);if (ok){// Tracking success : Draw the tracked objectrectangle(frame, bbox, Scalar( 255, 0, 0 ), 2, 1 );}else{// Tracking failure detected.putText(frame, "Tracking failure detected", Point(100,80), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(0,0,255),2);}// Display tracker type on frameputText(frame, trackerType + " Tracker", Point(100,20), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(50,170,50),2);// Display FPS on frameputText(frame, "FPS : " + SSTR(int(fps)), Point(100,50), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(50,170,50), 2);// Display frame.imshow("Tracking", frame);// Exit if ESC pressed.int k = waitKey(1);if(k == 27){break;}}
}

Python

import cv2
import sys(major_ver, minor_ver, subminor_ver) = (cv2.__version__).split('.')if __name__ == '__main__' :# Set up tracker.# Instead of MIL, you can also usetracker_types = ['BOOSTING', 'MIL','KCF', 'TLD', 'MEDIANFLOW', 'GOTURN', 'MOSSE']tracker_type = tracker_types[2]if int(minor_ver) < 3:tracker = cv2.Tracker_create(tracker_type)else:if tracker_type == 'BOOSTING':tracker = cv2.TrackerBoosting_create()if tracker_type == 'MIL':tracker = cv2.TrackerMIL_create()if tracker_type == 'KCF':tracker = cv2.TrackerKCF_create()if tracker_type == 'TLD':tracker = cv2.TrackerTLD_create()if tracker_type == 'MEDIANFLOW':tracker = cv2.TrackerMedianFlow_create()if tracker_type == 'GOTURN':tracker = cv2.TrackerGOTURN_create()if tracker_type == 'MOSSE':tracker = cv2.TrackerMOSSE_create()# Read videovideo = cv2.VideoCapture("videos/chaplin.mp4")# Exit if video not opened.if not video.isOpened():print "Could not open video"sys.exit()# Read first frame.ok, frame = video.read()if not ok:print 'Cannot read video file'sys.exit()# Define an initial bounding boxbbox = (287, 23, 86, 320)# Uncomment the line below to select a different bounding boxbbox = cv2.selectROI(frame, False)# Initialize tracker with first frame and bounding boxok = tracker.init(frame, bbox)while True:# Read a new frameok, frame = video.read()if not ok:break# Start timertimer = cv2.getTickCount()# Update trackerok, bbox = tracker.update(frame)# Calculate Frames per second (FPS)fps = cv2.getTickFrequency() / (cv2.getTickCount() - timer);# Draw bounding boxif ok:# Tracking successp1 = (int(bbox[0]), int(bbox[1]))p2 = (int(bbox[0] + bbox[2]), int(bbox[1] + bbox[3]))cv2.rectangle(frame, p1, p2, (255,0,0), 2, 1)else :# Tracking failurecv2.putText(frame, "Tracking failure detected", (100,80), cv2.FONT_HERSHEY_SIMPLEX, 0.75,(0,0,255),2)# Display tracker type on framecv2.putText(frame, tracker_type + " Tracker", (100,20), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (50,170,50),2);# Display FPS on framecv2.putText(frame, "FPS : " + str(int(fps)), (100,50), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (50,170,50), 2);# Display resultcv2.imshow("Tracking", frame)# Exit if ESC pressedk = cv2.waitKey(1) & 0xffif k == 27 : break

目标跟踪算法

在本节中,我们将深入研究不同的跟踪算法。目标并不是要对每个跟踪器都有深入的理论理解,而是从实际的角度理解它们。

首先让我解释一下跟踪背后的一些一般原则。 在跟踪中,我们的目标是在当前帧中找到一个对象,因为我们已经在所有(或几乎所有)前一帧中成功跟踪了对象。

由于我们已经跟踪了当前帧的目标,因此我们知道它是如何移动的。 换句话说,我们知道运动模型的参数。 运动模型只是一种奇特的方式,表示你知道前一帧中物体的位置和速度(速度+运动方向)。如果你对该目标一无所知,则可以根据当前运动模型预测新位置,并且你将非常接近目标的新位置。

我们有更多的信息,但是它们仅仅是关于目标的运动的。我们知道目标在每个先前帧中的外观。换句话说,我们可以构建一个外观模型来编码目标的外观。该外观模型可用于在运动模型预测的位置的小领域中搜索,以更准确地预测目标的位置。

运动模型预测目标的大致位置,外观模型精细调整该估计以基于外观提供更准确的估计。

如果目标非常简单并且没有更改它的外观,我们可以使用一个简单的模板作为外观模型并查找该模板。然而,显示并非那么简单。目标的外观可能会发生巨大的变化,为了解决这个问题,在许多现代跟踪器中,外观模型是以在线方式训练的分类器。别怕,让我用简单的术语解释一下。分类器的工作是将图像的矩形区域分类为目标或背景。分类器将图像作为输入,并返回0和1之间的分数,以指示图像块包含目标的概率。当绝对确定图像块是背景时得分为0,当绝对确定图像块是目标时得分为1。在机器学习中,我们使用“在线”一词来指代在运行时即时训练的算法。 离线分类器可能需要数千个示例来训练分类器,但是在线分类器通常在运行时使用极少数示例进行训练。通过将其分为正(目标)和负(目标)示例来训练分类器。 如果你想建立一个用于检测猫的分类器,你可以使用包含猫的数千个图像和数千个不包含猫的图像来训练它。 通过这种方式,分类器学会区分什么是猫而什么不是。 你可以在此处详细了解图像分类。 在构建在线分类器的过程中,我们没有数千个正面和负面类的例子。

让我们看看不同的跟踪算法如何解决在线训练的这个问题。

BOOSTING跟踪器

这个跟踪器基于AdaBoost的在线版本——基于HAAR面部检测器在内部使用的算法。需要在运行时使用目标的正面和负面示例训练此分类器。由用户(或另一个目标检测算法)提供的初始边界框被视为对象的正例,并且边界框外的许多图像块被视为背景。 给定新帧,分类器在先前位置的邻域中的每个像素上运行,并且记录分类器的分数。 目标的新位置是得分最大的位置。 所以现在我们又有了一个分类器的正面例子。 随着更多帧进入,分类器将使用此附加数据进行更新

优点:没有。 这个算法已有十年历史了,虽然工作正常,但我找不到使用它的好理由,特别是当其他基于类似原理的高级跟踪器(MIL,KCF)可用时。

缺点:跟踪性能平庸。且它无法可靠地知道跟踪失败的时间。

MIL跟踪器

该跟踪器在概念上类似于上述的BOOSTING跟踪器。 最大的区别在于,不是仅考虑目标的当前位置作为正例,而是在当前位置周围的小邻域中查找以产生若干潜在的正例。 你可能认为这是一个坏主意,因为在大多数这些“积极”的例子中,目标不是居中的。这正是MIL拯救的地方。在MIL中,你没有指定正面和负面的例子,而是正面和负面的“包”。 正面“包”中的图像集合并非都是正面的例子。 相反,只有正面包中的一个图像需要是一个正面的例子! 在我们的示例中,正面包包含以目标当前位置为中心的补丁,以及在其周围的小邻域中的补丁。 即使被跟踪目标的当前位置不准确,当来自当前位置附近的样本被放入正面包中时,该包很可能包含至少一个图像,其中目标很好地居中。 MIL项目主页为喜欢深入了解MIL跟踪器内部工作原理的人提供了更多信息。

MIL项目主页:http://vision.ucsd.edu/~bbabenko/new/project_miltrack.shtml

优点:表现非常好,它不会像BOOSTING跟踪器那样漂移,并且在部分遮挡下可以完成合理的工作,如果你使用的是OpenCV3.0,这可能是你可以使用的最佳跟踪器。但是如果你是用的是更高版本,请考虑使用KCF。

缺点:不能可靠的报告跟踪失败,以及无法从完全遮挡中恢复。

KCF跟踪器

KCF表示核相关滤波器,该跟踪器基于前两个跟踪器中提出的想法,利用MIL跟踪器中使用的多个正样本具有大的重叠区域的事实,这种重叠的数据导致一些很好的数学属性,这个跟踪器利用这些属性可以使跟踪更快更准确。

优点:精度和速度都优于MIL,它报告跟踪失败比BOOSTING和MIL更好。 如果你使用的是OpenCV 3.1及更高版本,我建议你在大多数应用程序中使用它。

缺点:无法从完全遮挡中恢复。 未在OpenCV 3.0中实现。

BUG警告OpenCV 3.1(仅限Python)中存在一个错误,因为返回了错误的边界框。 查看错误报告。 感谢Andrei Cheremskoy指出这一点。

错误报告:https://github.com/opencv/opencv_contrib/issues/640

TLD跟踪器

TLD代表tracking,learning和detection。顾名思义,该跟踪器将长期跟踪任务分解为三个部分——(短期)跟踪,学习和检测。作者的论文中指出,“跟踪器在帧与帧之间跟踪对象。检测器定位到目前为止观察到的所有外观,并在必要时纠正跟踪器。 学习估计检测器的错误并更新它以避免将来出现这些错误。“这个跟踪器的输出往往会跳跃一下。 例如,如果你正在跟踪行人并且场景中还有其他行人,则此跟踪器有时可以临时跟踪与你要跟踪的行人不同的行人。 从积极的方面来看,这个跟踪器似乎可以在更大的大小,运动和遮挡上跟踪物体。 如果你有一个视频序列,其中目标隐藏在另一个目标后面,则此跟踪器可能是一个不错的选择。

优点:在多个帧的遮挡下工作效果最佳。 此外,在目标大小变化时跟踪效果最佳。

缺点:很多误报使它几乎无法使用。

MEDIANFLOW跟踪器

在内部,该跟踪器及时向前和向后跟踪目标,并测量这两个轨迹之间的差异。 最小化此前向后向错误使他们能够可靠地检测跟踪失败并选择视频序列中的可靠轨迹。

在我的测试中,我发现当动作可预测且很小时,这个跟踪器效果最好。 与其他即使在跟踪明显失败时继续运行的跟踪器不同,此跟踪器也知道跟踪失败的时间。

优点:出色的跟踪失败报告。当运动可预测且没有遮挡时,效果很好。

缺点:目标动作大时跟踪失败。

GOTURN跟踪器

在跟踪器类的所有跟踪算法中,这是唯一基于卷积神经网络(CNN)的跟踪算法。 从OpenCV文档中,我们知道它“对视点变化,光照变化和变形具有鲁棒性”。 但它不能很好地处理遮挡。

注意:GOTURN是基于CNN的跟踪器,使用caffe模型进行跟踪。 Caffe模型和原始文本文件必须存在于代码所在的目录中。 这些文件也可以从opencv_extra存储库下载,在使用前连接并解压缩。

MOSSE跟踪器

误差最小平方和滤波器(MOSSE)使用自适应相关进行目标跟踪,当使用单个帧初始化时产生稳定的相关滤波器。 MOSSE跟踪器对照明,比例,姿势和非刚性变形的变化非常稳健。 它还根据峰值与旁瓣比率检测遮挡,这使得跟踪器能够暂停并在对象重新出现时从中断处继续。 MOSSE跟踪器也以更高的fps(450 fps甚至更高)运行。 为了增加积极性,它也很容易实现,与其他复杂的跟踪器一样准确,速度更快。 但是,在性能方面,它落后于基于深度学习的跟踪器。

订阅&下载代码

如果你喜欢这篇文章并想下载此文章中使用的代码(C++和Python)和示例图片,请订阅我的栏目。你还将收到免费的计算机视觉资源指南。在我们的栏目里,我们还分享了用C++/Python编写的OpenCV教程和示例,以及计算机视觉和机器学习的算法和新闻。

订阅栏目:https://bigvisionllc.leadpages.net/leadbox/143948b73f72a2%3A173c9390c346dc/5649050225344512/

 

 

 

 

 

 

 

 

 

 

 

 

 

转载于:https://www.cnblogs.com/annie22wang/p/9366610.html

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

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

相关文章

第7章-选择器+伪类

一.选择器 1.基础选择器 通配符选择器 标签/元素选择器 类选择器 id选择器 2.高级选择器 E,F (多元素选择器) 同时匹配所有E元素或F元素&#xff0c;E和F之间用逗号分隔 eg&#xff1a; div,p{width:100px;height:50px;} E F(后代选择器) 匹配所有属于E元素后代的F元…

[css] 什么是逐帧动画?

[css] 什么是逐帧动画&#xff1f; &#xff08;1&#xff09;相关联的不同图像&#xff0c;即动画帧&#xff1b;&#xff08;2&#xff09;连续播放。个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论…

第5章-css选择器初级和背景

一、ID选择器与Class选择器的区别 区别 1&#xff1a;ID选择器只能在文档中使用一次,. class类选择器可以多次使用。 区别 2&#xff1a; id的权重大于class类的权重 二.background背景样式 1.background-color:规定要使用的背景颜色十六进制值 #CC0066 #000英文单词…

POJ 4979 海贼王之伟大航路 【状压dp】【北大ACM/ICPC竞赛训练】

该死的题让我想起来艾斯之死... 首先想到dp(i)代表从1到【i表示的这些岛屿】所花的最小时间&#xff0c;然后每次枚举最后一个岛屿以此缩小范围&#xff0c;但发现枚举了最后一个岛屿后没有办法转移&#xff0c;因为不知道倒数第二个岛屿是什么&#xff0c;随着倒数第二个岛屿的…

[css] 举例说明BFC会与float元素相互覆盖吗?为什么?

[css] 举例说明BFC会与float元素相互覆盖吗&#xff1f;为什么&#xff1f; BFC的区域不会与float的元素区域重叠 计算BFC的高度时&#xff0c;浮动子元素也参与计算 BFC就是页面上的一个隔离的独立容器&#xff0c;容器里面的子元素不会影响到外面元素&#xff0c;反之亦然个…

Sublime Text 3 、WebStorm配置实时刷新

本文所用软件版本Sublime Text 3(Build 3143)、WebStorm 2017.2.4(Build #WS-172.4155.35)、Google Chrome v61.0.3163.100&#xff0c;其他版本软件配置过程可能不一样&#xff0c;请知悉&#xff01; 一.Google Chrome安装LiveReload插件 1.下载插件 LiveReload 2.1.0 链…

#0 scrapy爬虫学习中遇到的坑记录

python 基础学习中对于scrapy的使用遇到了一些问题。 首先进行的是对Amazon.cn的检索结果页进行爬取&#xff0c;很顺利&#xff0c;无碍。 下一个目标是对baidu的搜索结果进行爬取 1&#xff0c;反爬虫 1.1 我先对ROBOTSTXT_OBEY进行设置&#xff0c;结果找到了scrapy的默认参…

[css] 使用css如何设置背景虚化?

[css] 使用css如何设置背景虚化&#xff1f; filter: blur(5px);个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前端面试题

Sublime Text 3 、WebStorm配置护眼主题(浅绿色)

本文所用软件版本Sublime Text 3(Build 3143)、WebStorm 2017.2.4(Build #WS-172.4155.35)&#xff0c;其他版本软件配置过程可能不一样&#xff0c;请知悉&#xff01; 1.Sublime Text 3护眼主题 &#xff08;1&#xff09;下载配置文件 链接&#xff1a;http://pan.baidu.…

angular - 如何运行在起来 - 使用nginx

nginx下载地址&#xff0c;使用的是标准版的&#xff1a; 点击下载nginx nginx下载完后&#xff0c;解压 dist文件夹下面所有angular文件放入html文件夹中. 最后命令行cd到当前nginx.exe目录&#xff0c;启动命令&#xff1a;nginx 再配置一下conf文件夹下面的nginx.conf 再loc…

[css] 举例说明background-repeat的新属性值:round和space的作用是什么?

[css] 第 举例说明background-repeat的新属性值&#xff1a;round和space的作用是什么&#xff1f; space 背景图不会产生缩放&#xff0c;会被裁切 round 缩放背景图至容器大小&#xff08;非等比例缩放&#xff09;个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知…

Java学习资料汇总(JavaSE+JavaEE+数据库+框架+笔试题+面试题)

在写下这篇文章的时候&#xff0c;我还在找工作。理解每一个真正对编程感兴趣的小伙伴的转行不易&#xff0c;于是就把自己这几个月搜索到的学习资料一一分享给大家。 3.数据库 MySQL5.7 Reference Manual https://dev.mysql.com/doc/refman/5.7/en/ SQL中主键与外键的定义和…

2018 Multi-University Training Contest 1 Balanced Sequence(贪心)

题意&#xff1a; t组测试数据&#xff0c;每组数据有 n 个只由 ( 和 ) 构成的括号串。 要求把这 n 个串排序然后组成一个大的括号串&#xff0c;使得能够匹配的括号数最多。 如()()答案能够匹配的括号数是 4&#xff0c;(()) 也是 4。 例如&#xff1a; n 2 ) )(( 你可以将其…

[css] 举例说明with属性的fill-available有什么应用场景

[css] 举例说明with属性的fill-available有什么应用场景 一些 div 元素默认宽度 100% 父元素&#xff0c;这种充分利用可用空间的行为就称为 fill-available。个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一…

第一部分 Java:面向对象理解

Java&#xff1a;面向对象理解、集合、IO、NIO、并发、反射源码分析 一.面向对象 1.创建对象的5种方式 (1)使用new关键字(2)使用Class类的newInstance方法(3)使用构造函数类的newInstance方法(4)使用clone方法 --》未实现Cloneable会报错(5)使用反序列化5动态代理2.this、sup…

[css] width属性的min-content和max-content有什么作用

[css] width属性的min-content和max-content有什么作用 max-content 在一个父元素上设置该元素后&#xff0c;元素的宽度会以子元素内最长的一个为准&#xff0c;子元素表现得会好像设置了white-space:nowrap一样一行展示min-content 在一个父元素上设置该元素后&#xff0c;子…

js拖拽

function drag(cla1,cla2,index){//鼠标可拖拽区域的dom&#xff0c;被拖拽的dom元素,索引var disX 0; //鼠标到dom元素左边距离var disY 0; //鼠标到dom元素上边距离var oDiv1 document.getElementsByClassName(cla1)[index];var oDiv2 document.getElementsByClassName(c…

[css] 你用过outline属性吗?它有什么运用场景

[css] 你用过outline属性吗&#xff1f;它有什么运用场景 outline &#xff08;轮廓&#xff09;是绘制于元素周围的一条线&#xff0c;位于边框边缘的外围&#xff0c;可起到突出元素的作用。个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#x…

Centos7搭建Java环境,并设置项目自启动脚本、定时数据库备份/日志清理脚本

开发环境下载&#xff0c;提供nginx-1.12.2、jdk-8u162、Jenkins下载 建个文件夹&#xff0c;作为开发环境存放路径 cd /usr mkdir developmentEnvironment cd /一.java 1.解压包 tar -zxvf jdk-8u162-linux-x64.tar.gz -C /usr/developmentEnvironment2.配置环境变量 vi…

【nodejs】让nodejs像后端mvc框架(asp.net mvc)一样处理请求--参数自动映射篇(6/8)...

文章目录 前情概要 路由、action的扫描、发现、注册搞定之后&#xff0c;后来我发现在我们的action里面获取参数往往都是通过request对象来一个一个获取。同样的一行代码我们不厌其烦的重复写了无数次。遂想着那我们能不能像后端程序一样做得更自动化一些呢&#xff1f; 所以&a…