原文链接
本文只是调整了代码格式

一、Python OpenCV 入门

欢迎阅读系列教程,内容涵盖 OpenCV,它是一个图像和视频处理库,包含 C ++,C,Python 和 Java 的绑定。 OpenCV 用于各种图像和视频分析,如面部识别和检测,车牌阅读,照片编辑,高级机器人视觉,光学字符识别等等。

你将需要两个主要的库,第三个可选:python-OpenCV,Numpy 和 Matplotlib。

Windows 用户:

python-OpenCV:有其他的方法,但这是最简单的。 下载相应的 wheel(.whl)文件,然后使用pip进行安装。 观看视频来寻求帮助。

pip install numpypip install matplotlib
不熟悉使用pip? 请参阅pip安装教程来获得帮助。

Linux/Mac 用户

pip3 install numpy
或者

apt-get install python3-numpy
你可能需要apt-get来安装python3-pip。

pip3 install matplotlib
或者

apt-get install python3-matplotlibapt-get install python-OpenCV
Matplotlib 是用于展示来自视频或图像的帧的可选选项。 我们将在这里展示几个使用它的例子。 Numpy 被用于“数值和 Python”的所有东西。 我们主要利用 Numpy 的数组功能。 最后,我们使用python-OpenCV,它是 Python 特定的 OpenCV 绑定。

OpenCV 有一些操作,如果没有完整安装 OpenCV (大小约 3GB),你将无法完成,但是实际上你可以用 python-OpenCV 最简安装。 我们将在本系列的后续部分中使用 OpenCV 的完整安装,如果你愿意的话,你可以随意获得它,但这三个模块将使我们忙碌一段时间!

通过运行 Python 并执行下列命令来确保你安装成功:

import cv2import matplotlibimport numpy
如果你没有错误,那么你已经准备好了。好了嘛?让我们下潜吧!

首先,在图像和视频分析方面,我们应该了解一些基本的假设和范式。对现在每个摄像机的记录方式来说,记录实际上是一帧一帧地显示,每秒 30-60 次。但是,它们的核心是静态帧,就像图像一样。因此,图像识别和视频分析大部分使用相同的方法。有些东西,如方向跟踪,将需要连续的图像(帧),但像面部检测或物体识别等东西,在图像和视频中代码几乎完全相同。

接下来,大量的图像和视频分析归结为尽可能简化来源。这几乎总是起始于转换为灰度,但也可以是彩色滤镜,渐变或这些的组合。从这里,我们可以对来源执行各种分析和转化。一般来说,这里发生的事情是转换完成,然后是分析,然后是任何覆盖,我们希望应用在原始来源上,这就是你可以经常看到,对象或面部识别的“成品”在全色图像或视频上显示。然而,数据实际上很少以这种原始形式处理。有一些我们可以在基本层面上做些什么的例子。所有这些都使用基本的网络摄像头来完成,没有什么特别的:

背景提取

颜色过滤

边缘检测

用于对象识别的特征匹配

一般对象识别

在边缘检测的情况下,黑色对应于(0,0,0)的像素值,而白色线条是(255,255,255)。视频中的每个图片和帧都会像这样分解为像素,并且像边缘检测一样,我们可以推断,边缘是基于白色与黑色像素对比的地方。然后,如果我们想看到标记边缘的原始图像,我们记录下白色像素的所有坐标位置,然后在原始图像或视频上标记这些位置。

到本教程结束时,你将能够完成上述所有操作,并且能够训练你的机器识别你想要的任何对象。就像我刚开始说的,第一步通常是转换为灰度。在此之前,我们需要加载图像。因此,我们来做吧!在整个教程中,我极力鼓励你使用你自己的数据来玩。如果你有摄像头,一定要使用它,否则找到你认为很有趣的图像。如果你有麻烦,这是一个手表的图像:

import cv2import numpy as npfrom matplotlib import pyplot as pltimg = cv2.imread(‘watch.jpg’,cv2.IMREAD_GRAYSCALE)cv2.imshow(‘image’,img)cv2.waitKey(0)cv2.destroyAllWindows()
首先,我们正在导入一些东西,我已经安装了这三个模块。接下来,我们将img定义为cv2.read(image file, parms)。默认值是IMREAD_COLOR,这是没有任何 alpha 通道的颜色。如果你不熟悉,alpha 是不透明度(与透明度相反)。如果你需要保留 Alpha 通道,也可以使用IMREAD_UNCHANGED。很多时候,你会读取颜色版本,然后将其转换为灰度。如果你没有网络摄像机,这将是你在本教程中使用的主要方法,即加载图像。

你可以不使用IMREAD_COLOR …等,而是使用简单的数字。你应该熟悉这两种选择,以便了解某个人在做什么。对于第二个参数,可以使用-1,0或1。颜色为1,灰度为0,不变为-1。因此,对于灰度,可以执行cv2.imread(‘watch.jpg’, 0)。

一旦加载完成,我们使用cv2.imshow(title,image)来显示图像。从这里,我们使用cv2.waitKey(0)来等待,直到有任何按键被按下。一旦完成,我们使用cv2.destroyAllWindows()来关闭所有的东西。

正如前面提到的,你也可以用 Matplotlib 显示图像,下面是一些如何实现的代码:

import cv2import numpy as npfrom matplotlib import pyplot as pltimg = cv2.imread(‘watch.jpg’,cv2.IMREAD_GRAYSCALE)plt.imshow(img, cmap = ‘gray’, interpolation = ‘bicubic’)plt.xticks([]), plt.yticks([]) # to hide tick values on X and Y axisplt.plot([200,300,400],[100,200,300],‘c’, linewidth=5)plt.show()
请注意,你可以绘制线条,就像任何其他 Matplotlib 图表一样,使用像素位置作为坐标的。 不过,如果你想绘制你的图片,Matplotlib 不是必需的。 OpenCV 为此提供了很好的方法。 当你完成修改后,你可以保存,如下所示:

cv2.imwrite(‘watchgray.png’,img)
将图片导入 OpenCV 似乎很容易,加载视频源如何? 在下一个教程中,我们将展示如何加载摄像头或视频源。

二、加载视频源

在这个 Python OpenCV 教程中,我们将介绍一些使用视频和摄像头的基本操作。 除了起始行,处理来自视频的帧与处理图像是一样的。 我们来举例说明一下:

import numpy as npimport cv2cap = cv2.VideoCapture(0) while(True): ret, frame = cap.read() gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) cv2.imshow(‘frame’,gray) if cv2.waitKey(1) & 0xFF == ord(‘q’): breakcap.release()cv2.destroyAllWindows()

首先,我们导入numpy和cv2,没有什么特别的。 接下来,我们可以cap = cv2.VideoCapture(0)。 这将从你计算机上的第一个网络摄像头返回视频。 如果你正在观看视频教程,你将看到我正在使用1,因为我的第一个摄像头正在录制我,第二个摄像头用于实际的教程源。

while(True): ret, frame = cap.read()
这段代码启动了一个无限循环(稍后将被break语句打破),其中ret和frame被定义为cap.read()。 基本上,ret是一个代表是否有返回的布尔值,frame是每个返回的帧。 如果没有帧,你不会得到错误,你会得到None。

gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
在这里,我们定义一个新的变量gray,作为转换为灰度的帧。 注意这个BGR2GRAY。 需要注意的是,OpenCV 将颜色读取为 BGR(蓝绿色红色),但大多数计算机应用程序读取为 RGB(红绿蓝)。 记住这一点。

cv2.imshow(‘frame’,gray)
请注意,尽管是视频流,我们仍然使用imshow。 在这里,我们展示了转换为灰色的源。 如果你想同时显示,你可以对原始帧和灰度执行imshow,将出现两个窗口。

if cv2.waitKey(1) & 0xFF == ord(‘q’): break
这个语句每帧只运行一次。 基本上,如果我们得到一个按键,那个键是q,我们将退出while循环,然后运行:

cap.release()cv2.destroyAllWindows()
这将释放网络摄像头,然后关闭所有的imshow()窗口。

在某些情况下,你可能实际上需要录制,并将录制内容保存到新文件中。 以下是在 Windows 上执行此操作的示例:

import numpy as npimport cv2cap = cv2.VideoCapture(1)fourcc = cv2.VideoWriter_fourcc(*‘XVID’)out = cv2.VideoWriter(‘output.avi’,fourcc, 20.0, (640,480))while(True): ret, frame = cap.read() gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) out.write(frame) cv2.imshow(‘frame’,gray) if cv2.waitKey(1) & 0xFF == ord(‘q’): breakcap.release()out.release()cv2.destroyAllWindows()
这里主要要注意的是正在使用的编解码器,以及在while循环之前定义的输出信息。 然后,在while循环中,我们使用out.write()来输出帧。 最后,在while循环之外,在我们释放摄像头之后,我们也释放out。

太好了,现在我们知道如何操作图像和视频。 如果你没有网络摄像头,你可以使用图像甚至视频来跟随教程的其余部分。 如果你希望使用视频而不是网络摄像头作为源,则可以为视频指定文件路径,而不是摄像头号码。

现在我们可以使用来源了,让我们来展示如何绘制东西。 此前你已经看到,你可以使用 Matplotlib 在图片顶部绘制,但是 Matplotlib 并不真正用于此目的,特别是不能用于视频源。 幸运的是,OpenCV 提供了一些很棒的工具,来帮助我们实时绘制和标记我们的源,这就是我们将在下一个教程中讨论的内容。

三、在图像上绘制和写字

在这个 Python OpenCV 教程中,我们将介绍如何在图像和视频上绘制各种形状。 想要以某种方式标记检测到的对象是相当普遍的,所以我们人类可以很容易地看到我们的程序是否按照我们的希望工作。 一个例子就是之前显示的图像之一:

对于这个临时的例子,我将使用下面的图片:

鼓励你使用自己的图片。 像往常一样,我们的起始代码可以是这样的:

import numpy as npimport cv2img = cv2.imread(‘watch.jpg’,cv2.IMREAD_COLOR)
下面,我们可以开始绘制,这样:

cv2.line(img,(0,0),(150,150),(255,255,255),15)cv2.imshow(‘image’,img)cv2.waitKey(0)cv2.destroyAllWindows()
cv2.line()接受以下参数:图片,开始坐标,结束坐标,颜色(bgr),线条粗细。

结果在这里:

好吧,很酷,让我们绘制更多形状。 接下来是一个矩形:

cv2.rectangle(img,(15,25),(200,150),(0,0,255),15)
这里的参数是图像,左上角坐标,右下角坐标,颜色和线条粗细。

圆怎么样?

cv2.circle(img,(100,63), 55, (0,255,0), -1)
这里的参数是图像/帧,圆心,半径,颜色和。 注意我们粗细为-1。 这意味着将填充对象,所以我们会得到一个圆。

线条,矩形和圆都很酷,但是如果我们想要五边形,八边形或十八边形? 没问题!

pts = np.array([[10,5],[20,30],[70,20],[50,10]], np.int32)# OpenCV documentation had this code, which reshapes the array to a 1 x 2. I did not # find this necessary, but you may:#pts = pts.reshape((-1,1,2))cv2.polylines(img, [pts], True, (0,255,255), 3)
首先,我们将坐标数组称为pts(点的简称)。 然后,我们使用cv2.polylines来画线。 参数如下:绘制的对象,坐标,我们应该连接终止的和起始点,颜色和粗细。

你可能想要做的最后一件事是在图像上写字。 这可以这样做:

font = cv2.FONT_HERSHEY_SIMPLEXcv2.putText(img,‘OpenCV Tuts!’,(0,130), font, 1, (200,255,155), 2, cv2.LINE_AA)
目前为止的完整代码:

import numpy as npimport cv2img = cv2.imread(‘watch.jpg’,cv2.IMREAD_COLOR)cv2.line(img,(0,0),(200,300),(255,255,255),50)cv2.rectangle(img,(500,250),(1000,500),(0,0,255),15)cv2.circle(img,(447,63), 63, (0,255,0), -1)pts = np.array([[100,50],[200,300],[700,200],[500,100]], np.int32)pts = pts.reshape((-1,1,2))cv2.polylines(img, [pts], True, (0,255,255), 3)font = cv2.FONT_HERSHEY_SIMPLEXcv2.putText(img,‘OpenCV Tuts!’,(10,500), font, 6, (200,255,155), 13, cv2.LINE_AA)cv2.imshow(‘image’,img)cv2.waitKey(0)cv2.destroyAllWindows()
结果:

在下一个教程中,我们将介绍我们可以执行的基本图像操作。

四、图像操作

在 OpenCV 教程中,我们将介绍一些我们可以做的简单图像操作。 每个视频分解成帧。 然后每一帧,就像一个图像,分解成存储在行和列中的,帧/图片中的像素。 每个像素都有一个坐标位置,每个像素都由颜色值组成。 让我们列举访问不同的位的一些例子。

我们将像往常一样读取图像(如果可以,请使用自己的图像,但这里是我在这里使用的图像):

import cv2import numpy as npimg = cv2.imread(‘watch.jpg’,cv2.IMREAD_COLOR)
现在我们可以实际引用特定像素,像这样:

px = img[55,55]
下面我们可以实际修改像素:

img[55,55] = [255,255,255]
之后重新引用:

px = img[55,55]print(px)
现在应该不同了,下面我们可以引用 ROI,图像区域:

px = img[100:150,100:150]print(px)
我们也可以修改 ROI,像这样:

img[100:150,100:150] = [255,255,255]
我们可以引用我们的图像的特定特征:

print(img.shape)print(img.size)print(img.dtype)
我们可以像这样执行操作:

watch_face = img[37:111,107:194]img[0:74,0:87] = watch_facecv2.imshow(‘image’,img)cv2.waitKey(0)cv2.destroyAllWindows()
这会处理我的图像,但是可能不能用于你的图像,取决于尺寸。这是我的输出:

这些是一些简单的操作。 在下一个教程中,我们将介绍一些我们可以执行的更高级的图像操作。

五、图像算术和逻辑运算

欢迎来到另一个 Python OpenCV 教程,在本教程中,我们将介绍一些简单算术运算,我们可以在图像上执行的,并解释它们的作用。 为此,我们将需要两个相同大小的图像来开始,然后是一个较小的图像和一个较大的图像。 首先,我将使用:

首先,让我们看看简单的加法会做什么:

import cv2import numpy as np# 500 x 250img1 = cv2.imread(‘3D-Matplotlib.png’)img2 = cv2.imread(‘mainsvmimage.png’)add = img1+img2cv2.imshow(‘add’,add)cv2.waitKey(0)cv2.destroyAllWindows()
结果:

史上最全的OpenCV入门教程!这篇够你学习半个月了!万字长文入门
你不可能想要这种混乱的加法。 OpenCV 有一个“加法”方法,让我们替换以前的“加法”,看看是什么:

add = cv2.add(img1,img2)
结果:

史上最全的OpenCV入门教程!这篇够你学习半个月了!万字长文入门
这里可能不理想。 我们可以看到很多图像是非常“白色的”。 这是因为颜色是 0-255,其中 255 是“全亮”。 因此,例如:(155,211,79) + (50, 170, 200) = 205, 381, 279…转换为(205, 255,255)。

接下来,我们可以添加图像,并可以假设每个图像都有不同的“权重”。 这是如何工作的:

import cv2import numpy as npimg1 = cv2.imread(‘3D-Matplotlib.png’)img2 = cv2.imread(‘mainsvmimage.png’)weighted = cv2.addWeighted(img1, 0.6, img2, 0.4, 0)cv2.imshow(‘weighted’,weighted)cv2.waitKey(0)cv2.destroyAllWindows()
对于addWeighted方法,参数是第一个图像,权重,第二个图像,权重,然后是伽马值,这是一个光的测量值。 我们现在就把它保留为零。

史上最全的OpenCV入门教程!这篇够你学习半个月了!万字长文入门
这些是一些额外的选择,但如果你真的想将一个图像添加到另一个,最新的重叠在哪里? 在这种情况下,你会从最大的开始,然后添加较小的图像。 为此,我们将使用相同的3D-Matplotlib.png图像,但使用一个新的 Python 标志:

史上最全的OpenCV入门教程!这篇够你学习半个月了!万字长文入门
现在,我们可以选取这个标志,并把它放在原始图像上。 这很容易(基本上使用我们在前一个教程中使用的相同代码,我们用一个新的东西替换了图像区域(ROI)),但是如果我们只想要标志部分而不是白色背景呢? 我们可以使用与之前用于 ROI 替换相同的原理,但是我们需要一种方法来“去除”标志的背景,使得白色不会不必要地阻挡更多背景图像。 首先我将显示完整的代码,然后解释:

import cv2import numpy as np# Load two imagesimg1 = cv2.imread(‘3D-Matplotlib.png’)img2 = cv2.imread(‘mainlogo.png’)# I want to put logo on top-left corner, So I create a ROIrows,cols,channels = img2.shaperoi = img1[0:rows, 0:cols ]# Now create a mask of logo and create its inverse maskimg2gray = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)# add a thresholdret, mask = cv2.threshold(img2gray, 220, 255, cv2.THRESH_BINARY_INV)mask_inv = cv2.bitwise_not(mask)# Now black-out the area of logo in ROIimg1_bg = cv2.bitwise_and(roi,roi,mask = mask_inv)# Take only region of logo from logo image.img2_fg = cv2.bitwise_and(img2,img2,mask = mask)dst = cv2.add(img1_bg,img2_fg)img1[0:rows, 0:cols ] = dstcv2.imshow(‘res’,img1)cv2.waitKey(0)cv2.destroyAllWindows()
这里发生了很多事情,出现了一些新的东西。 我们首先看到的是一个新的阈值:ret, mask = cv2.threshold(img2gray, 220, 255, cv2.THRESH_BINARY_INV)。

我们将在下一个教程中介绍更多的阈值,所以请继续关注具体内容,但基本上它的工作方式是根据阈值将所有像素转换为黑色或白色。 在我们的例子中,阈值是 220,但是我们可以使用其他值,或者甚至动态地选择一个,这是ret变量可以使用的值。 接下来,我们看到:mask_inv = cv2.bitwise_not(mask)。 这是一个按位操作。 基本上,这些操作符与 Python 中的典型操作符非常相似,除了一点,但我们不会在这里触及它。 在这种情况下,不可见的部分是黑色的地方。 然后,我们可以说,我们想在第一个图像中将这个区域遮住,然后将空白区域替换为图像 2 的内容。

史上最全的OpenCV入门教程!这篇够你学习半个月了!万字长文入门
下个教程中,我们深入讨论阈值。

六、阈值

欢迎阅读另一个 OpenCV 教程。在本教程中,我们将介绍图像和视频分析的阈值。阈值的思想是进一步简化视觉数据的分析。首先,你可以转换为灰度,但是你必须考虑灰度仍然有至少 255 个值。阈值可以做的事情,在最基本的层面上,是基于阈值将所有东西都转换成白色或黑色。比方说,我们希望阈值为 125(最大为 255),那么 125 以下的所有内容都将被转换为 0 或黑色,而高于 125 的所有内容都将被转换为 255 或白色。如果你像平常一样转换成灰度,你会变成白色和黑色。如果你不转换灰度,你会得到二值化的图片,但会有颜色。

虽然这听起来不错,但通常不是。我们将在这里介绍多个示例和不同类型的阈值来说明这一点。我们将使用下面的图片作为我们的示例图片,但可以随意使用你自己的图片:

史上最全的OpenCV入门教程!这篇够你学习半个月了!万字长文入门
这个书的图片就是个很好的例子,说明为什么一个人可能需要阈值。 首先,背景根本没有白色,一切都是暗淡的,而且一切都是变化的。 有些部分很容易阅读,另一部分则非常暗,需要相当多的注意力才能识别出来。 首先,我们尝试一个简单的阈值:

retval, threshold = cv2.threshold(img, 10, 255, cv2.THRESH_BINARY)
二元阈值是个简单的“是或不是”的阈值,其中像素为 255 或 0。在很多情况下,这是白色或黑色,但我们已经为我们的图像保留了颜色,所以它仍然是彩色的。 这里的第一个参数是图像。 下一个参数是阈值,我们选择 10。下一个是最大值,我们选择为 255。最后是阈值类型,我们选择了THRESH_BINARY。 通常情况下,10 的阈值会有点差。 我们选择 10,因为这是低光照的图片,所以我们选择低的数字。 通常 125-150 左右的东西可能效果最好。

import cv2import numpy as npimg = cv2.imread(‘bookpage.jpg’)retval, threshold = cv2.threshold(img, 12, 255, cv2.THRESH_BINARY)cv2.imshow(‘original’,img)cv2.imshow(‘threshold’,threshold)cv2.waitKey(0)cv2.destroyAllWindows()
结果:

史上最全的OpenCV入门教程!这篇够你学习半个月了!万字长文入门
现在的图片稍微更便于阅读了,但还是有点乱。 从视觉上来说,这样比较好,但是仍然难以使用程序来分析它。 让我们看看我们是否可以进一步简化。

首先,让我们灰度化图像,然后使用一个阈值:

import cv2import numpy as npgrayscaled = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)retval, threshold = cv2.threshold(grayscaled, 10, 255, cv2.THRESH_BINARY)cv2.imshow(‘original’,img)cv2.imshow(‘threshold’,threshold)cv2.waitKey(0)cv2.destroyAllWindows()
史上最全的OpenCV入门教程!这篇够你学习半个月了!万字长文入门
更简单,但是我们仍然在这里忽略了很多背景。 接下来,我们可以尝试自适应阈值,这将尝试改变阈值,并希望弄清楚弯曲的页面。

import cv2import numpy as npth = cv2.adaptiveThreshold(grayscaled, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 115, 1)cv2.imshow(‘original’,img)cv2.imshow(‘Adaptive threshold’,th)cv2.waitKey(0)cv2.destroyAllWindows()
史上最全的OpenCV入门教程!这篇够你学习半个月了!万字长文入门
还有另一个版本的阈值,可以使用,叫做大津阈值。 它在这里并不能很好发挥作用,但是:

retval2,threshold2 = cv2.threshold(grayscaled,125,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)cv2.imshow(‘original’,img)cv2.imshow(‘Otsu threshold’,threshold2)cv2.waitKey(0)cv2.destroyAllWindows()
七、颜色过滤

在这个 Python OpenCV 教程中,我们将介绍如何创建一个过滤器,回顾按位操作,其中我们将过滤特定的颜色,试图显示它。或者,你也可以专门筛选出特定的颜色,然后将其替换为场景,就像我们用其他方法替换ROI(图像区域)一样,就像绿屏的工作方式。

为了像这样过滤,你有几个选项。通常,你可能会将你的颜色转换为 HSV,即“色调饱和度纯度”。例如,这可以帮助你根据色调和饱和度范围,使用变化的值确定一个更具体的颜色。如果你希望的话,你可以实际生成基于 BGR 值的过滤器,但是这会有点困难。如果你很难可视化 HSV,不要感到失落,查看维基百科页面上的 HSV,那里有一个非常有用的图形让你可视化它。我最好亲自描述颜色的色调饱和度和纯度。现在让我们开始:

import cv2import numpy as npcap = cv2.VideoCapture(0)while(1): _, frame = cap.read() hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) lower_red = np.array([30,150,50]) upper_red = np.array([255,255,180]) mask = cv2.inRange(hsv, lower_red, upper_red) res = cv2.bitwise_and(frame,frame, mask= mask) cv2.imshow(‘frame’,frame) cv2.imshow(‘mask’,mask) cv2.imshow(‘res’,res) k = cv2.waitKey(5) & 0xFF if k == 27: breakcv2.destroyAllWindows()cap.release()
史上最全的OpenCV入门教程!这篇够你学习半个月了!万字长文入门
这只是一个例子,以红色为目标。 它的工作方式是,我们所看到的是我们范围内的任何东西,基本上是 30-255,150-255 和 50-180。 它用于红色,但可以随便尝试找到自己的颜色。 HSV 在这里效果最好的原因是,我们想要范围内的颜色,这里我们通常需要相似的颜色。 很多时候,典型的红色仍然会有一些绿色和蓝色分量,所以我们必须允许一些绿色和蓝色,但是我们会想要几乎全红。 这意味着我们会在这里获得所有颜色的低光混合。

为了确定 HSV 的范围,我认为最好的方法就是试错。 OpenCV 内置了将 BGR 转换为 HSV 的方法。 如果你想挑选单一的颜色,那么 BGR 到 HSV 将会很好用。 为了教学,下面是这个代码的一个例子:

dark_red = np.uint8([[[12,22,121]]]) dark_red = cv2.cvtColor(dark_red,cv2.COLOR_BGR2HSV)
这里的结果是一个 HSV 值,与dark_red值相同。这很棒…但是,同样…你遇到了颜色范围和 HSV 范围的基本问题。他们根本不同。你可能合理使用 BGR 范围,它们仍然可以工作,但是对于检测一种“颜色”,则无法正常工作。

回到主代码,然而,我们首先要把帧转换成 HSV。那里没什么特别的。接下来,我们为红色指定一些 HSV 值。我们使用inRange函数,为我们的特定范围创建掩码。这是真或假,黑色或白色。接下来,我们通过执行按位操作来“恢复”我们的红色。基本上,我们显示了frame and mask。掩码的白色部分是红色范围,被转换为纯白色,而其他一切都变成黑色。最后我们展示所有东西。我选择了显示原始真,掩码和最终结果,以便更好地了解发生的事情。

在下一个教程中,我们将对这个主题做一些介绍。你可能看到了,我们在这里还是有一些“噪音”。东西有颗粒感,红色中的黑点很多,还有许多其他的小色点。我们可以做一些事情,试图通过模糊和平滑来缓解这个问题,接下来我们将讨论这个问题。

八、模糊和平滑

在这个 Python OpenCV 教程中,我们将介绍如何尝试从我们的过滤器中消除噪声,例如简单的阈值,或者甚至我们以前的特定的颜色过滤器:

史上最全的OpenCV入门教程!这篇够你学习半个月了!万字长文入门
正如你所看到的,我们有很多黑点,其中我们喜欢红色,还有很多其他的色点散落在其中。 我们可以使用各种模糊和平滑技术来尝试弥补这一点。 我们可以从一些熟悉的代码开始:

import cv2import numpy as npcap = cv2.VideoCapture(0)while(1): _, frame = cap.read() hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) lower_red = np.array([30,150,50]) upper_red = np.array([255,255,180]) mask = cv2.inRange(hsv, lower_red, upper_red) res = cv2.bitwise_and(frame,frame, mask= mask)
现在,让我们应用一个简单的平滑,我们计算每个像素块的均值。 在我们的例子中,我们使用15x15正方形,这意味着我们有 225 个总像素。

kernel = np.ones((15,15),np.float32)/225 smoothed = cv2.filter2D(res,-1,kernel) cv2.imshow(‘Original’,frame) cv2.imshow(‘Averaging’,smoothed) k = cv2.waitKey(5) & 0xFF if k == 27: breakcv2.destroyAllWindows()cap.release()
史上最全的OpenCV入门教程!这篇够你学习半个月了!万字长文入门
这个很简单,但是结果牺牲了很多粒度。 接下来,让我们尝试一些高斯模糊:

blur = cv2.GaussianBlur(res,(15,15),0) cv2.imshow(‘Gaussian Blurring’,blur)
史上最全的OpenCV入门教程!这篇够你学习半个月了!万字长文入门
另一个选项是中值模糊:

median = cv2.medianBlur(res,15) cv2.imshow(‘Median Blur’,median)
史上最全的OpenCV入门教程!这篇够你学习半个月了!万字长文入门
最后一个选项是双向模糊:

bilateral = cv2.bilateralFilter(res,15,75,75) cv2.imshow(‘bilateral Blur’,bilateral)
所有模糊的对比:

史上最全的OpenCV入门教程!这篇够你学习半个月了!万字长文入门
至少在这种情况下,我可能会使用中值模糊,但是不同的照明,不同的阈值/过滤器,以及其他不同的目标和目标可能会决定你使用其中一个。

在下一个教程中,我们将讨论形态变换。

九、形态变换

在这个 Python OpenCV 教程中,我们将介绍形态变换。 这些是一些简单操作,我们可以基于图像形状执行。

我们要谈的第一对是腐蚀和膨胀。 腐蚀是我们将“腐蚀”边缘。 它的工作方式是使用滑块(核)。 我们让滑块滑动,如果所有的像素是白色的,那么我们得到白色,否则是黑色。 这可能有助于消除一些白色噪音。 另一个版本是膨胀,它基本上是相反的:让滑块滑动,如果整个区域不是黑色的,就会转换成白色。 这是一个例子:

import cv2import numpy as npcap = cv2.VideoCapture(0)while(1): _, frame = cap.read() hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) lower_red = np.array([30,150,50]) upper_red = np.array([255,255,180]) mask = cv2.inRange(hsv, lower_red, upper_red) res = cv2.bitwise_and(frame,frame, mask= mask) kernel = np.ones((5,5),np.uint8) erosion = cv2.erode(mask,kernel,iterations = 1) dilation = cv2.dilate(mask,kernel,iterations = 1) cv2.imshow(‘Original’,frame) cv2.imshow(‘Mask’,mask) cv2.imshow(‘Erosion’,erosion) cv2.imshow(‘Dilation’,dilation) k = cv2.waitKey(5) & 0xFF if k == 27: breakcv2.destroyAllWindows()cap.release()
结果:

史上最全的OpenCV入门教程!这篇够你学习半个月了!万字长文入门
下一对是“开放”和“关闭”。 开放的目标是消除“假阳性”。 有时在背景中,你会得到一些像素“噪音”。 “关闭”的想法是消除假阴性。 基本上就是你检测了你的形状,例如我们的帽子,但物体仍然有一些黑色像素。 关闭将尝试清除它们。

cap = cv2.VideoCapture(1)while(1): _, frame = cap.read() hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) lower_red = np.array([30,150,50]) upper_red = np.array([255,255,180]) mask = cv2.inRange(hsv, lower_red, upper_red) res = cv2.bitwise_and(frame,frame, mask= mask) kernel = np.ones((5,5),np.uint8) opening = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel) closing = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel) cv2.imshow(‘Original’,frame) cv2.imshow(‘Mask’,mask) cv2.imshow(‘Opening’,opening) cv2.imshow(‘Closing’,closing) k = cv2.waitKey(5) & 0xFF if k == 27: breakcv2.destroyAllWindows()cap.release()
史上最全的OpenCV入门教程!这篇够你学习半个月了!万字长文入门
另外两个选项是tophat和blackhat,对我们的案例并不有用:

It is the difference between input image and Opening of the image cv2.imshow(‘Tophat’,tophat) # It is the difference between the closing of the input image and input image. cv2.imshow(‘Blackhat’,blackhat)

在下一个教程中,我们将讨论图像渐变和边缘检测。

十、边缘检测和渐变

欢迎阅读另一个 Python OpenCV 教程。 在本教程中,我们将介绍图像渐变和边缘检测。 图像渐变可以用来测量方向的强度,边缘检测就像它所说的:它找到了边缘! 我敢打赌你肯定没看到。

首先,我们来展示一些渐变的例子:

import cv2import numpy as npcap = cv2.VideoCapture(1)while(1): # Take each frame _, frame = cap.read() hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) lower_red = np.array([30,150,50]) upper_red = np.array([255,255,180]) mask = cv2.inRange(hsv, lower_red, upper_red) res = cv2.bitwise_and(frame,frame, mask= mask) laplacian = cv2.Laplacian(frame,cv2.CV_64F) sobelx = cv2.Sobel(frame,cv2.CV_64F,1,0,ksize=5) sobely = cv2.Sobel(frame,cv2.CV_64F,0,1,ksize=5) cv2.imshow(‘Original’,frame) cv2.imshow(‘Mask’,mask) cv2.imshow(‘laplacian’,laplacian) cv2.imshow(‘sobelx’,sobelx) cv2.imshow(‘sobely’,sobely) k = cv2.waitKey(5) & 0xFF if k == 27: breakcv2.destroyAllWindows()cap.release()
史上最全的OpenCV入门教程!这篇够你学习半个月了!万字长文入门
如果你想知道什么是cv2.CV_64F,那就是数据类型。 ksize是核大小。 我们使用 5,所以每次查询5×5的渔区。

虽然我们可以使用这些渐变转换为纯边缘,但我们也可以使用 Canny 边缘检测!

import cv2import numpy as npcap = cv2.VideoCapture(0)while(1): _, frame = cap.read() hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) lower_red = np.array([30,150,50]) upper_red = np.array([255,255,180]) mask = cv2.inRange(hsv, lower_red, upper_red) res = cv2.bitwise_and(frame,frame, mask= mask) cv2.imshow(‘Original’,frame) edges = cv2.Canny(frame,100,200) cv2.imshow(‘Edges’,edges) k = cv2.waitKey(5) & 0xFF if k == 27: breakcv2.destroyAllWindows()cap.release()
史上最全的OpenCV入门教程!这篇够你学习半个月了!万字长文入门
这真是太棒了! 但是,这并不完美。 注意阴影导致了边缘被检测到。 其中最明显的是蓝狗窝发出的阴影。

在下一个 OpenCV 教程中,我们将讨论如何在其他图像中搜索和查找相同的图像模板。

十一、模板匹配

欢迎阅读另一个 Python OpenCV 教程,在本教程中,我们将介绍对象识别的一个基本版本。 这里的想法是,给出一定的阈值,找到匹配我们提供的模板图像的相同区域。 对于具体的对象匹配,具有精确的照明/刻度/角度,这可以工作得很好。 通常会遇到这些情况的例子就是计算机上的任何 GUI。 按钮等东西总是相同的,所以你可以使用模板匹配。 结合模板匹配和一些鼠标控制,你已经实现了一个基于 Web 的机器人!

首先,你需要一个主要图像和一个模板。 你应该从你正在图像中查找的“东西”选取你的模板。 我将提供一个图像作为例子,但随意使用你最喜爱的网站的图像或类似的东西。

主要图像:

史上最全的OpenCV入门教程!这篇够你学习半个月了!万字长文入门
我们要搜索的模板:

史上最全的OpenCV入门教程!这篇够你学习半个月了!万字长文入门
这只是其中一个端口,但我们很好奇,看看我们是否可以匹配任何其他端口。 我们确实要选择一个阈值,其中某种东西可能是 80% 匹配,那么我们说这就匹配。 所以,我们将开始加载和转换图像:

import cv2import numpy as npimg_rgb = cv2.imread(‘opencv-template-matching-python-tutorial.jpg’)img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)template = cv2.imread(‘opencv-template-for-matching.jpg’,0)w, h = template.shape[::-1]
到目前为止,我们加载了两个图像,转换为灰度。 我们保留原始的 RGB 图像,并创建一个灰度版本。 我之前提到过这个,但是我们这样做的原因是,我们在灰度版本上执行所有的处理,然后在彩色图像上使用相同的标签来标记。

对于主要图像,我们只有彩色版本和灰度版本。 我们加载模板并记下尺寸。

res = cv2.matchTemplate(img_gray,template,cv2.TM_CCOEFF_NORMED)threshold = 0.8loc = np.where( res >= threshold)
在这里,我们用img_gray(我们的主图像),模板,和我们要使用的匹配方法调用matchTemplate,并将返回值称为res。 我们指定一个阈值,这里是 80%。 然后我们使用逻辑语句,找到res大于或等于 80% 的位置。

最后,我们使用灰度图像中找到的坐标,标记原始图像上的所有匹配:

for pt in zip(*loc[::-1]): cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0,255,255), 2)cv2.imshow(‘Detected’,img_rgb)
史上最全的OpenCV入门教程!这篇够你学习半个月了!万字长文入门
所以我们得到了几个匹配。也许需要降低阈值?我们试试 0.7。

史上最全的OpenCV入门教程!这篇够你学习半个月了!万字长文入门
这里有一些假阳性。 你可以继续调整门槛,直到你达到 100%,但是如果没有假阳性,你可能永远不会达到它。 另一个选择就是使用另一个模板图像。 有时候,使用相同对象的多个图像是有用的。 这样,你可以使阈值足够高的,来确保你的结果准确。

在下一个教程中,我们将介绍前景提取。

十二、GrabCut 前景提取

欢迎阅读 Python OpenCV 前景提取教程。 这里的想法是找到前景,并删除背景。 这很像绿屏,只是这里我们实际上不需要绿屏。

首先,我们将使用一个图像:

史上最全的OpenCV入门教程!这篇够你学习半个月了!万字长文入门
随意使用你自己的。

让我们加载图像并定义一些东西:

import numpy as npimport cv2from matplotlib import pyplot as pltimg = cv2.imread(‘opencv-python-foreground-extraction-tutorial.jpg’)mask = np.zeros(img.shape[:2],np.uint8)bgdModel = np.zeros((1,65),np.float64)fgdModel = np.zeros((1,65),np.float64)rect = (161,79,150,150)
到目前为止,我们已经导入了cv2,numpy和matplotlib。 然后我们加载图像,创建一个掩码,指定算法内部使用的背景和前景模型。 真正重要的部分是我们定义的矩形。 这是rect = (start_x, start_y, width, height)。

这是包围我们的主要对象的矩形。 如果你正在使用我的图片,那就是要使用的矩阵。 如果你使用自己的,找到适合你的图像的坐标。

下面:

cv2.grabCut(img,mask,rect,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_RECT)mask2 = np.where((mask2)|(mask0),0,1).astype(‘uint8’)img = img*mask2[:,:,np.newaxis]plt.imshow(img)plt.colorbar()plt.show()
所以在这里我们使用了cv2.grabCut,它用了很多参数。 首先是输入图像,然后是掩码,然后是主要对象的矩形,背景模型,前景模型,要运行的迭代量以及使用的模式。

这里改变了掩码,使得所有像素 0 和 2 转换为背景,而像素 1 和 3 现在是前景。 从这里,我们乘以输入图像,得到我们的最终结果:

史上最全的OpenCV入门教程!这篇够你学习半个月了!万字长文入门
下个教程中,我们打算讨论如何执行角点检测。

十三、角点检测

欢迎阅读 Python OpenCV 角点检测教程。 检测角点的目的是追踪运动,做 3D 建模,识别物体,形状和角色等。

对于本教程,我们将使用以下图像:

史上最全的OpenCV入门教程!这篇够你学习半个月了!万字长文入门
我们的目标是找到这个图像中的所有角点。 我会注意到,在这里我们有一些别名问题(斜线的锯齿),所以,如果我们允许的话,会发现很多角点,而且是正确的。 和往常一样,OpenCV 已经为我们完成了难题,我们需要做的就是输入一些参数。 让我们开始加载图像并设置一些参数:

import numpy as npimport cv2img = cv2.imread(‘opencv-corner-detection-sample.jpg’)gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)gray = np.float32(gray)corners = cv2.goodFeaturesToTrack(gray, 100, 0.01, 10)corners = np.int0(corners)
到目前为止,我们加载图像,转换为灰度,然后是float32。 接下来,我们用goodFeaturesToTrack函数检测角点。 这里的参数是图像,检测到的最大角点数量,品质和角点之间的最小距离。 如前所述,我们在这里的锯齿问题将允许找到许多角点,所以我们对其进行了限制。 下面:

for corner in corners: x,y = corner.ravel() cv2.circle(img,(x,y),3,255,-1) cv2.imshow(‘Corner’,img)
现在我们遍历每个角点,在我们认为是角点的每个点上画一个圆。

史上最全的OpenCV入门教程!这篇够你学习半个月了!万字长文入门
在下一个教程中,我们将讨论功能匹配/单映射。

十四、特征匹配(单映射)爆破

欢迎阅读 Python OpenCV 特征匹配教程。 特征匹配将是稍微更令人印象深刻的模板匹配版本,其中需要一个完美的,或非常接近完美的匹配。

我们从我们希望找到的图像开始,然后我们可以在另一幅图像中搜索这个图像。 这里的完美是图像不需要相同的光照,角度,旋转等。 特征只需要匹配。

首先,我们需要一些示例图像。 我们的“模板”,或者我们将要尝试匹配的图像:

史上最全的OpenCV入门教程!这篇够你学习半个月了!万字长文入门
之后是我们用于搜索这个模板的图像:

史上最全的OpenCV入门教程!这篇够你学习半个月了!万字长文入门
在这里,我们的模板图像在模板中,比在我们要搜索的图像中要小一些。 它的旋转也不同,阴影也有些不同。

现在我们将使用一种“爆破”匹配的形式。 我们将在这两个图像中找到所有特征。 然后我们匹配这些特征。 然后,我们可以绘制我们想要的,尽可能多的匹配。 但是要小心。 如果你绘制 500 个匹配,你会有很多误报。 所以只绘制绘制前几个。

import numpy as npimport cv2import matplotlib.pyplot as pltimg1 = cv2.imread(‘opencv-feature-matching-template.jpg’,0)img2 = cv2.imread(‘opencv-feature-matching-image.jpg’,0)
到目前为止,我们已经导入了要使用的模块,并定义了我们的两个图像,即模板(img1)和用于搜索模板的图像(img2)。

orb = cv2.ORB_create()
这是我们打算用于特征的检测器。

kp1, des1 = orb.detectAndCompute(img1,None)kp2, des2 = orb.detectAndCompute(img2,None)
在这里,我们使用orb探测器找到关键点和他们的描述符。

bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
这就是我们的BFMatcher对象。

matches = bf.match(des1,des2)matches = sorted(matches, key = lambda x:x.distance)
这里我们创建描述符的匹配,然后根据它们的距离对它们排序。

img3 = cv2.drawMatches(img1,kp1,img2,kp2,matches[:10],None, flags=2)plt.imshow(img3)plt.show()
这里我们绘制了前 10 个匹配。输出:

史上最全的OpenCV入门教程!这篇够你学习半个月了!万字长文入门
十五、MOG 背景减弱

在这个 Python OpenCV 教程中,我们将要讨论如何通过检测运动来减弱图像的背景。 这将要求我们回顾视频的使用,或者有两个图像,一个没有你想要追踪的人物/物体,另一个拥有人物/物体。 如果你希望,你可以使用你的摄像头,或者使用如下的视频:

人们行走的样例视频

这里的代码实际上很简单,就是我们现在知道的:

import numpy as npimport cv2cap = cv2.VideoCapture(‘people-walking.mp4’)fgbg = cv2.createBackgroundSubtractorMOG2()while(1): ret, frame = cap.read() fgmask = fgbg.apply(frame) cv2.imshow(‘fgmask’,frame) cv2.imshow(‘frame’,fgmask) k = cv2.waitKey(30) & 0xff if k == 27: break cap.release()cv2.destroyAllWindows()
结果:

pythonprogramming.net/static/imag…

这里的想法是从静态背景中提取移动的前景。 你也可以使用这个来比较两个相似的图像,并立即提取它们之间的差异。

在我们的例子中,我们可以看到我们确实已经检测到了一些人,但是我们确实有一些“噪音”,噪音实际上是树叶在周围的风中移动了一下。 只要我们知道一种减少噪音的方法。 等一下! 我们的确知道! 一个疯狂的挑战已经出现了你面前!

接下来的教程开始让我们远离滤镜或变换的应用,并让我们使用 Haar Cascades 来检测一般对象,例如面部检测等等。

十六、Haar Cascade 面部检测

在这个 Python OpenCV 教程中,我们将讨论 Haar Cascades 对象检测。我们将从脸部和眼睛检测来开始。为了使用层叠文件进行对象识别/检测,首先需要层叠文件。对于非常流行的任务,这些已经存在。检测脸部,汽车,笑脸,眼睛和车牌等东西都是非常普遍的。

首先,我会告诉你如何使用这些层叠文件,然后我将告诉你如何开始创建你自己的层叠,这样你就可以检测到任何你想要的对象,这很酷!

你可以使用 Google 来查找你可能想要检测的东西的各种 Haar Cascades。对于找到上述类型,你应该没有太多的麻烦。我们将使用面部层叠和眼睛层叠。你可以在 Haar Cascades 的根目录找到更多。请注意用于使用/分发这些 Haar Cascades 的许可证。

让我们开始我们的代码。我假设你已经从上面的链接中下载了haarcascade_eye.xml和haarcascade_frontalface_default.xml,并将这些文件放在你项目的目录中。

import numpy as npimport cv2# multiple cascades: https://github.com/Itseez/opencv/tree/master/data/haarcascades#https://github.com/Itseez/opencv/blob/master/data/haarcascades/haarcascade_frontalface_default.xmlface_cascade = cv2.CascadeClassifier(‘haarcascade_frontalface_default.xml’)#https://github.com/Itseez/opencv/blob/master/data/haarcascades/haarcascade_eye.xmleye_cascade = cv2.CascadeClassifier(‘haarcascade_eye.xml’)cap = cv2.VideoCapture(0)
在这里,我们从导入cv2和numpy开始,然后加载我们的脸部和眼部的层叠。 目前为止很简单。

while 1: ret, img = cap.read() gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) faces = face_cascade.detectMultiScale(gray, 1.3, 5)
现在我们开始我们的典型循环,这里唯一的新事物就是脸部的创建。 更多信息请访问detectMultiScale函数的文档。 基本上,它找到了面部! 我们也想找到眼睛,但是在一个假阳性的世界里,在面部里面寻找眼睛,从逻辑上来说是不是很明智? 我们希望我们不寻找不在脸上的眼睛! 严格来说,“眼睛检测”可能不会找到闲置的眼球。 大多数眼睛检测使用周围的皮肤,眼睑,眼睫毛,眉毛也可以用于检测。 因此,我们的下一步就是先去拆分面部,然后才能到达眼睛:

for (x,y,w,h) in faces: cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2) roi_gray = gray[y:y+h, x:x+w] roi_color = img[y:y+h, x:x+w]
在这里,我们找到了面部,它们的大小,绘制矩形,并注意 ROI。 接下来,我们找了一些眼睛:

eyes = eye_cascade.detectMultiScale(roi_gray) for (ex,ey,ew,eh) in eyes: cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),2)
如果我们找到这些,我们会继续绘制更多的矩形。 接下来我们完成:

cv2.imshow(‘img’,img) k = cv2.waitKey(30) & 0xff if k == 27: breakcap.release()cv2.destroyAllWindows()
完整代码:

import numpy as npimport cv2# multiple cascades: https://github.com/Itseez/opencv/tree/master/data/haarcascades#https://github.com/Itseez/opencv/blob/master/data/haarcascades/haarcascade_frontalface_default.xmlface_cascade = cv2.CascadeClassifier(‘haarcascade_frontalface_default.xml’)#https://github.com/Itseez/opencv/blob/master/data/haarcascades/haarcascade_eye.xmleye_cascade = cv2.CascadeClassifier(‘haarcascade_eye.xml’)cap = cv2.VideoCapture(0)while 1: ret, img = cap.read() gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) faces = face_cascade.detectMultiScale(gray, 1.3, 5) for (x,y,w,h) in faces: cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2) roi_gray = gray[y:y+h, x:x+w] roi_color = img[y:y+h, x:x+w] eyes = eye_cascade.detectMultiScale(roi_gray) for (ex,ey,ew,eh) in eyes: cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),2) cv2.imshow(‘img’,img) k = cv2.waitKey(30) & 0xff if k == 27: breakcap.release()cv2.destroyAllWindows()
史上最全的OpenCV入门教程!这篇够你学习半个月了!万字长文入门
不错。你可能会注意到我不得不取下我的眼镜。这些造成了一些麻烦。我的嘴也经常被检测为眼睛,有时甚至是一张脸,但你明白了。面部毛发和其他东西经常可以欺骗基本面部检测,除此之外,皮肤的颜色也会造成很大的麻烦,因为我们经常试图尽可能简化图像,从而失去了很多颜色值。甚至还有一个小型行业,可以避免人脸检测和识别。CVDazzle 网站就是一个例子。其中有些非常古怪,但他们很有效。你也可以总是走完整的面部重建手术的路线,以避免自动跟踪和检测,所以总是这样,但是这更永久。做个发型比较短暂也容易做到。

好吧,检测面部,眼睛和汽车是可以的,但我们是程序员。我们希望能够做任何事情。事实证明,事情会变得相当混乱,建立自己的 Haar Cascades 有一定的难度,但是其他人也这么做…你也可以!这就是在下一个教程中所讨论的。

十七、创建自己的 Haar Cascade

欢迎使用 Python OpenCV 对象检测教程。在本教程中,你将看到如何创建你自己的 Haar Cascades,以便你可以跟踪任何你想要的对象。由于这个任务的本质和复杂性,本教程将比平时稍长一些,但奖励是巨大的。

虽然你可以在 Windows 中完成,我不会建议这样。因此,对于本教程,我将使用 Linux VPS,并且我建议你也这样做。你可以尝试使用 Amazon Web Services 提供的免费套餐,但对你来说可能太痛苦了,你可能需要更多的内存。你还可以从 Digital Ocean 获得低至五美元/月的 VPS。我推荐至少 2GB 的内存用于我们将要做的事情。现在大多数主机按小时收费,包括 DO。因此,你可以购买一个 20 美元/月的服务器,使用它一天,获取你想要的文件,然后终止服务器,并支付很少的钱。你需要更多的帮助来设置服务器?如果是的话,看看这个具体的教程。

一旦你的服务器准备就绪,你会打算获取实际的 OpenCV 库。

将目录更改到服务器的根目录,或者你想放置工作区的地方:

cd ~sudo apt-get updatesudo apt-get upgrade
首先,让我们为自己制作一个漂亮的工作目录:

mkdir opencv_workspacecd opencv_workspace
既然我们完成了,让我们获取 OpenCV。

sudo apt-get install gitgit clone https://github.com/Itseez/opencv.git
我们这里克隆了 OpenCV 的最新版本。现在获取一些必需品。

编译器:sudo apt-get install build-essential

库:sudo apt-get install cmake git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev

Python 绑定:sudo apt-get install python-dev python-numpy libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev libjasper-dev libdc1394-22-dev

最后,让我们获取 OpenCV 开发库:

sudo apt-get install libopencv-dev
现在,我们该如何完成这个过程呢?所以当你想建立一个 Haar Cascade 时,你需要“正片”图像和“底片”图像。 “正片”图像是包含要查找的对象的图像。这可以是具有对象的主要图像,也可以是包含对象的图像,并指定对象所在的 ROI(兴趣区域)。有了这些正片图像,我们建立一个矢量文件,基本上是所有这些东西放在一起。正片图像的一个好处是,你可以实际只有一个你想要检测的对象的图像,然后有几千个底片图像。是的,几千。底片图像可以是任何东西,除了他们不能包含你的对象。

在这里,使用你的底片图像,你可以使用opencv_createsamples命令来创建一堆正片的示例。你的正片图像将叠加在这些底片上,而且会形成各种各样的角度。它实际上可以工作得很好,特别是如果你只是在寻找一个特定的对象。但是,如果你正在寻找所有螺丝刀,则需要拥有数千个螺丝刀的独特图像,而不是使用opencv_createsamples为你生成样品。我们将保持简单,只使用一个正片图像,然后用我们的底片创建一堆样本。

我们的正片图像:

这是另外一个场景,如果你使用自己的图像,你可能会更喜欢这个。如果事情出错了,试试看我的,但是我建议你自己画一下。保持较小。 50x50像素应该可以。

好吧,获得正片图像是没有问题的!只有一个问题。我们需要成千上万的底片图像。可能在未来,我们也可能需要成千上万的正片图像。我们可以在世界的哪个地方实现它?基于 WordNet 的概念,有一个非常有用的站点叫做 ImageNet。从这里,你可以找到几乎任何东西的图像。我们这里,我们想要手表,所以搜索手表,你会发现大量种类的手表。让我们检索电子表。真棒!看看下载标签!存在用于所有电子表手表的 URL!很酷。好吧,但我说过我们只会使用一个正片,所以我们只是检测一个手表。如果你想检测“全部”手表,需要准备获取多余 50,000 个手表图像,至少 25000 个“底片”的图像。之后,准备足够的服务器,除非你想要你的 Haar Cascade 训练花一个星期。那么我们如何得到底片? ImageNet 的全部重点是图像训练,所以他们的图像非常具体。因此,如果我们搜索人,汽车,船只,飞机…无论什么,都不会有手表。你可能会看到一些人或类似的东西,但你明白了。既然你可能看到人周围或上面的手表,我其实认为你也会得到人的图像。我的想法是寻找做运动的人,他们可能没有戴电子表。所以,我们来找一些批量图片的 URL 链接。我发现体育/田径链接有 1,888 张图片,但你会发现很多这些都是完全损坏的。让我们再来找一个:

好吧,我们拥有所有这些图片,现在呢?那么,首先,我们希望所有这些大小都相同,而且要小很多!天哪,只要我们知道一个方法来操作图像…嗯…哦,这是一个 OpenCV 教程!我们可以处理它。所以,首先,我们要做的就是编写一个简单的脚本,访问这些 URL 列表,获取链接,访问链接,拉取图像,调整大小,保存它们,然后重复,直到完成。当我们的目录充满图像时,我们还需要一种描述图像的描述文件。对于正片,手动创建这个文件特别痛苦,因为你需要指定你的对象,每个图像的具体的兴趣区域。幸运的是,create_samples方法将图像随机放置,并为我们做了所有工作。我们只需要一个用于底片的简单描述符,但是这不是问题,在拉伸和操作图像时我们可以实现。

www.youtube.com/embed/z_6fP…

在任何你喜欢的地方随意运行这个代码。 我要在我的主机上运行它,因为它应该快一点。 你可以在你的服务器上运行。 如果你想使用cv2模块,请执行sudo apt-get install python-OpenCV。 目前,我不知道在 Linux 上为 Python 3 获得这些绑定的好方法。 我将要写的脚本是 Python 3,所以记住这一点。 主要区别是Urllib处理。

download-image-by-link.pyimport urllib.requestimport cv2import numpy as npimport osdef store_raw_images(): neg_images_link = ‘//image-net.org/api/text/imagenet.synset.geturls?wnid=n00523513’ neg_image_urls = urllib.request.urlopen(neg_images_link).read().decode() pic_num = 1 if not os.path.exists(‘neg’): os.makedirs(‘neg’) for i in neg_image_urls.split(’ '): try: print(i) urllib.request.urlretrieve(i, “neg/”+str(pic_num)+".jpg") img = cv2.imread(“neg/”+str(pic_num)+".jpg",cv2.IMREAD_GRAYSCALE) # should be larger than samples / pos pic (so we can place our image on it) resized_image = cv2.resize(img, (100, 100)) cv2.imwrite(“neg/”+str(pic_num)+".jpg",resized_image) pic_num += 1 except Exception as e: print(str(e))

很简单,这个脚本将访问链接,抓取网址,并继续访问它们。从这里,我们抓取图像,转换成灰度,调整大小,然后保存。我们使用一个简单的计数器来命名图像。继续运行它。你可能看到,有很多确实的图片等。没关系。这些错误图片中的一些更有问题。基本上都是白色,带有一些文本,说他们不再可用,而不是服务和 HTTP 错误。现在,我们有几个选择。我们可以忽略它们,或者修复它。嘿,这是一个没有手表的图像,所以什么是对的呢?当然,你可以采取这种观点,但如果你为正片使用这种拉取方式的话,这肯定是一个问题。你可以手动删除它们…或者我们可以使用我们新的图像分析知识,来检测这些愚蠢的图像,并将其删除!

我继续生成了一个新的目录,称之为“uglies(丑陋)”。在那个目录中,我点击并拖动了所有丑陋的图像版本(只是其中之一)。在底片中我只发现了一个主犯,所以我只有一个。让我们编写一个脚本来查找这个图像的所有实例并删除它。

www.youtube.com/embed/t0HOV…

def find_uglies(): match = False for file_type in [‘neg’]: for img in os.listdir(file_type): for ugly in os.listdir(‘uglies’): try: current_image_path = str(file_type)+’/’+str(img) ugly = cv2.imread(‘uglies/’+str(ugly)) question = cv2.imread(current_image_path) if ugly.shape == question.shape and not(np.bitwise_xor(ugly,question).any()): print(‘That is one ugly pic! Deleting!’) print(current_image_path) os.remove(current_image_path) except Exception as e: print(str(e))
现在我们只有底片,但是我留下了空间让你轻易在那里添加’pos’(正片)。 你可以运行它来测试,但我不介意先抓住更多的底片。 让我们再次运行图片提取器,仅仅使用这个 url://image-net.org/api/text/imagenet.synset.geturls?wnid=n07942152。 最后一张图像是#952,所以让我们以 953 开始pic_num,并更改网址。

def store_raw_images(): neg_images_link = ‘//image-net.org/api/text/imagenet.synset.geturls?wnid=n07942152’ neg_image_urls = urllib.request.urlopen(neg_images_link).read().decode() pic_num = 953 if not os.path.exists(‘neg’): os.makedirs(‘neg’) for i in neg_image_urls.split(’ '): try: print(i) urllib.request.urlretrieve(i, “neg/”+str(pic_num)+".jpg") img = cv2.imread(“neg/”+str(pic_num)+".jpg",cv2.IMREAD_GRAYSCALE) # should be larger than samples / pos pic (so we can place our image on it) resized_image = cv2.resize(img, (100, 100)) cv2.imwrite(“neg/”+str(pic_num)+".jpg",resized_image) pic_num += 1 except Exception as e: print(str(e))
现在我们有超过2000张照片。 最后一步是,我们需要为这些底片图像创建描述符文件。 我们将再次使用一些代码!

def create_pos_n_neg(): for file_type in [‘neg’]: for img in os.listdir(file_type): if file_type == ‘pos’: line = file_type+’/’+img+’ 1 0 0 50 50 ’ with open(‘info.dat’,‘a’) as f: f.write(line) elif file_type == ‘neg’: line = file_type+’/’+img+’ ’ with open(‘bg.txt’,‘a’) as f: f.write(line)
运行它,你有了个bg.txt文件。 现在,我知道有些人的互联网连接可能不是最好的,所以我做个好人,在这里上传底片图片和描述文件。 你应该通过这些步骤。 如果你对本教程感到困扰,则需要知道如何执行这部分。 好吧,所以我们决定我们将一个图像用于正片前景图像。 因此,我们需要执行create_samples。 这意味着,我们需要将我们的neg目录和bg.txt文件移动到我们的服务器。 如果你在服务器上运行所有这些代码,不要担心。

www.youtube.com/embed/eay7C…

如果你是一个术士,并已经想出了如何在 Windows 上运行create_samples等,恭喜! 回到服务器的领地,我的文件现在是这样的:

opencv_workspace–neg----negimages.jpg–opencv–info–bg.txt–watch5050.jpg
你可能没有info目录,所以继续并mkdir info。 这是我们放置所有正片图像的地方。

我们现在准备根据watch5050.jpg图像创建一些正片样本。 为此,请在工作区中通过终端运行以下命令:

opencv_createsamples -img watch5050.jpg -bg bg.txt -info info/info.lst -pngoutput info -maxxangle 0.5 -maxyangle 0.5 -maxzangle 0.5 -num 1950
这样做是基于我们指定的img创建样本,bg是背景信息,我们将输出info.list(很像bg.txt文件)的信息,然后-pngoutput就是我们想要放置新生成的图像的任何地方。 最后,我们有一些可选的参数,使我们的原始图像更加动态一些,然后用= num来表示我们想要创建的样本数量。 太棒了,让我们来运行它。 现在你的info目录应该有约 2,000 个图像,还有一个名为info.lst的文件。 这个文件基本上是你的“正片”文件。 打开它,并且看看它怎么样:

0001_0014_0045_0028_0028.jpg 1 14 45 28 28
首先你有文件名,之后是图像中有多少对象,其次是它们的所有位置。 我们只有一个,所以它是图像中对象矩形的x,y,宽度和高度。 这是一个图像:

很难看到它,但如果你很难看到,手表就是这个图像。 图像中最左侧人物的左下方。 因此,这是一个“正片”图像,从另外一个“底片”图像创建,底片图像也将用于训练。 现在我们有了正片图像,现在我们需要创建矢量文件,这基本上是一个地方,我们将所有正片图像拼接起来。我们会再次为此使用opencv_createsamples!

opencv_createsamples -info info/info.lst -num 1950 -w 20 -h 20 -vec positives.vec
这是我们的矢量文件。 在这里,我们只是让它知道信息文件的位置,我们想要在文件中包含多少图像,在这个矢量文件中图像应该是什么尺寸,然后才能输出结果。 如果你愿意的话,你可以做得更大一些,20×20可能足够好了,你做的越大,训练时间就会越长。 继续,我们现在只需要训练我们的层叠。

首先,我们要把输出放在某个地方,所以让我们创建一个新的数据目录:

mkdir data,你的工作空间应该如下所示:

opencv_workspace–neg----negimages.jpg–opencv–info–data–positives.vec --bg.txt–watch5050.jpg
现在让我们运行训练命令:

opencv_traincascade -data data -vec positives.vec -bg bg.txt -numPos 1800 -numNeg 900 -numStages 10 -w 20 -h 20
在这里,我们表明了,我们想要数据去的地方,矢量文件的位置,背景文件的位置,要使用多少个正片图像和底片图像,多少个阶段以及宽度和高度。请注意,我们使用的numPos比我们少得多。这是为了给阶段腾出空间。

有更多的选择,但这些就够了。这里主要是正片和底片的数量。一般认为,对于大多数实践,你需要 2:1 比例的正片和底片图像。有些情况可能会有所不同,但这是人们似乎遵循的一般规则。接下来,我们拥有阶段。我们选择了 10 个。你至少要 10-20 个,越多需要的时间越长,而且是指数级的。第一阶段通常很快,第五阶段要慢得多,第五十个阶段永远不会做完!所以,我们现在执行 10 个阶段。这里不错的事情是你可以训练 10 个阶段,稍后再回来,把数字改成 20,然后在你离开的地方继续。同样的,你也可以放一些像 100 个阶段的东西,上床睡觉,早上醒来,停下来,看看你有多远,然后用这些阶段“训练”,你会立即得到一个层叠文件。你可能从最后一句话中得出,这个命令的结果确实很棒,是个不错的层叠文件。我们希望能检测到我的手表,或者你决定检测的任何东西。我所知道的是,在输出这一段的时候,我还没有完成第一阶段的工作。如果你真的想要在一夜之间运行命令,但不想让终端打开,你可以使用nohup:

nohup opencv_traincascade -data data -vec positives.vec -bg bg.txt -numPos 1800 -numNeg 900 -numStages 10 -w 20 -h 20 &
这使命令即使在关闭终端之后也能继续运行。 你可以使用更多,但你可能会或可能不会用完你的 2GB RAM。

www.youtube.com/embed/-Mhy-…

在我的 2GB DO 服务器上,10 个阶段花了不到 2 个小时的时间。 所以,要么有一个cascade.xml文件,要么停止脚本运行。 如果你停止运行,你应该在你的data目录下有一堆stageX.xml文件。 打开它,看看你有多少个阶段,然后你可以使用这些阶段,再次运行opencv_traincascade,你会立即得到一个cascade.xml文件。 这里,我只想说出它是什么,以及有多少个阶段。 对我来说,我做了 10 个阶段,所以我将它重命名为watchcascade10stage.xml。 这就是我们所需的,所以现在将新的层次文件传回主计算机,放在工作目录中,让我们试试看!

import numpy as npimport cv2face_cascade = cv2.CascadeClassifier(‘haarcascade_frontalface_default.xml’)eye_cascade = cv2.CascadeClassifier(‘haarcascade_eye.xml’)#this is the cascade we just made. Call what you wantwatch_cascade = cv2.CascadeClassifier(‘watchcascade10stage.xml’)cap = cv2.VideoCapture(0)while 1: ret, img = cap.read() gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) faces = face_cascade.detectMultiScale(gray, 1.3, 5) # add this # image, reject levels level weights. watches = watch_cascade.detectMultiScale(gray, 50, 50) # add this for (x,y,w,h) in watches: cv2.rectangle(img,(x,y),(x+w,y+h),(255,255,0),2) for (x,y,w,h) in faces: cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2) roi_gray = gray[y:y+h, x:x+w] roi_color = img[y:y+h, x:x+w] eyes = eye_cascade.detectMultiScale(roi_gray) for (ex,ey,ew,eh) in eyes: cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),2) cv2.imshow(‘img’,img) k = cv2.waitKey(30) & 0xff if k == 27: breakcap.release()cv2.destroyAllWindows()
史上最全的OpenCV入门教程!这篇够你学习半个月了!万字长文入门
你可能注意到,手表的方框很小。 它似乎并没有达到整个手表。 回想一下我们的训练规模是20x20。 因此,我们最多有个20x20的方框。 你可以做100x100,但是,要小心,这将需要很长时间来训练。 因此,我们不绘制方框,而是,为什么不在手表上写字或什么东西? 这样做相对简单。 我们不在手表上执行cv2.rectangle(img,(x,y),(x+w,y+h),(0,0,255),2),我们可以执行:

font = cv2.FONT_HERSHEY_SIMPLEX cv2.putText(img,‘Watch’,(x-w,y-h), font, 0.5, (11,255,255), 2, cv2.LINE_AA)
史上最全的OpenCV入门教程!这篇够你学习半个月了!万字长文入门
很酷! 所以你可能没有使用我的手表,你是怎么做的? 如果遇到麻烦,请尝试使用与我完全相同的所有内容。 检测图像,而不是检测摄像头,这里是一个:

史上最全的OpenCV入门教程!这篇够你学习半个月了!万字长文入门
在图像上运行检测会给你:

史上最全的OpenCV入门教程!这篇够你学习半个月了!万字长文入门

Haar Cascades 往往是 100-2000 KB 的大小。大于等于 2,000 KB 的 Haar Cascades 应该非常准确。考虑你的情况,你可能会遇到约 5000 个一般物体。考虑 Haar Cascades 平均可能是约 500 KB。我们需要:0.5 MB * 5,000 = 2,500 MB或 2.5 GB。你需要 2.5 GB 的内存来识别 5000 个对象,并且可能是你在一天中遇到的最多对象。这让我着迷。考虑到我们可以访问所有的 image-net,并可以立即拉取很大范围的对象的一般图像。考虑 image-net 上的大多数图像,基本上都是 100% 的“跟踪”对象,因此,你可以通过手动标注位置,并仅使用 0,0 和图像的全部大小来得到正确的结果。

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

相关文章

  1. 从北京近期沙尘过程看环境气象预报技术支撑体系的发展

    更多精彩,请点击上方蓝字关注我们! 5月11日,内蒙古中部、华北大部先后出现了大风沙尘天气,11日午后,北京的天空呈现浅棕色,呼吸中夹着泥土的气息,傍晚时分,沙尘更是混合着雨滴降落在北京,北京市民都惊呼下“泥雨”了。15日,京津冀及周边地区再次受到来自蒙古国沙尘侵…...

    2024/4/16 19:26:49
  2. docker序幕揭开篇

    推荐使用 vagrant + virtualbox 快速搭建 centos 环境来学习 docker。 使用Vagrant快速搭建centos虚拟机 解决vagrant中的centos主机无法远程连接的问题 什么是Docker Docker 属于 Linux 容器的一种封装,提供简单易用的容器使用接口。它是目前最流行的 Linux 容器解决方案。 D…...

    2024/4/16 19:26:55
  3. (Notes)OracleNet

    OracleNet 客户机要与服务器连接必须确定数据库名称、所在主机名、使用端口号以及网络通信协议等。不论在何种平台上,都需要这些基本信息。 Oracle网络体系结构1.在服务器端,监听器存在于Listener.ora文件中,随时监听来自客户端的请求。 2.如果客户端需要访问服务器端,客户…...

    2024/4/24 7:36:42
  4. HyperDeck Extreme 8K HDR硬盘录机

    描述秉承HyperDeck可靠品质的8K广播录机,结合了 先进的H.265记录、内部缓存、3D LUT、原生8K以及HDR支持等优秀功能。其大型触摸屏设有播放、停止以及记录按钮,外加可滚动查看记录内容的迷你时间线,在画面上左右点划即可快速搜索片段!LCD屏设有采用HUD设计的时间码、视频格…...

    2024/4/24 7:36:41
  5. 面试常见问题总结——网络工程师(先导篇)

    1.通信基础:1.设计企业网络的基本架构是什么?答:企业网络的基本架构由三个部分组成,分别是接入层、汇聚层和核心层。接入层的主要设备是接入交换机,用于接入企业终端设备,如PC、AP、IP电话、服务器等汇聚层的主要设备是路由器,用于将内网下层所有设备发送的流量汇聚,实…...

    2024/4/25 13:23:24
  6. HyperDeck Studio Pro录机

    描述HyperDeck Studio Pro是一款集强大兼容力和高新科技于一体的录机,它拥有更为先进的设计,搭载6G-SDI技术,支持SD、HD和Ultra HD格式,并且还配有类型广泛的视音频模拟和数字接口,让您可以极大程度地兼容各类新老设备。不论是上至1080p60的SD、HD格式,还是上至2160p30的…...

    2024/4/24 7:36:43
  7. 【原】Centos7部署RPA2

    搭建rap2全过程艰难的记录所需环境:node, mysql,redis,nginx一、准备工作1、创建文件夹,在/usr/local下创建rap2文件夹 (为图方便,我采用WinSCP可视化创建)2、以下进行相关环境查看,若不存在,则需自行准备:①.查看mysql是否具备service mysql status②.查看node是否具…...

    2024/4/24 7:36:38
  8. Codeforces Round 1344 简要题解

    A. Hilbert’s Hotel 略 B. Monopole Magnets 略 C. Quantifier Question 略 D. Rsum Review 设f(i,x)f(i,x)f(i,x)(0≤x<ai0\leq x<a_i0≤x<ai​)表示bib_ibi​由xxx变为x+1x+1x+1答案的增量,那么有fi(x)=(x+1)(ai−(x+1)2)−x(ai−x2)=−3x2−4x+(a−1)f_i(x)=(x…...

    2024/4/24 7:36:44
  9. NGINX平滑升级

    一、解释nginx的平滑升级 随着网站并发访问量越来越高,nginx web 服务器也越来越流行,nginx 版本换代越来越频繁,1.10.2版本的nginx更新了许多新功能,生产环境中版本升级必然的,但是线上业务不能停,此时nginx的升级就是运维的重要工作了。 二、nginx平滑升级原理 多进程模…...

    2024/4/24 7:36:36
  10. 浏览器变记事本或富文本-笔记

    浏览器变记事本或富文本-笔记 笔者用的是360极速版 在浏览器的地址栏输入如下代码,即可得到一个可编辑文本的编辑器<!-- 很基础版 之 基础版 --> data:text/html, <html contenteditable><!-- 很基础版 之 美化版 --> data:text/html, <textarea style…...

    2024/4/24 7:36:35
  11. Linux 6/7英文版改成中文版方法(2020)

    一、 Linux 61. 安装字体yum -y groupinstall chinese-support2. 设置字体# vi /etc/sysconfig/i18n //修改后内容如下:LANG="zh_CN.UTF-8"SUPPORTED="zh_CN:zh:en_US.UTF-8:en_US:en:zh_CN.GB18030"SYSFONT="latarcyrheb-sun…...

    2024/4/24 7:36:38
  12. 出神入化的枚举结构体函数声明

    瞻仰完大神改STM32中断向量表的代码,今天我们来看看“大神”写的枚举、结构、函数声明,还是一样的配方,一样的烧脑。少废话,先放代码。第一段是枚举,第二段是函数,第三段是对一个数组的初始化。//=====================================================================…...

    2024/4/24 7:36:33
  13. java基础梳理 一:什么是面向对象编程

    什么是面向对象编程?Object Oriented Programming,简称OOP,即面向对象编程。和面向对象编程相对的是面向过程编程。那么,什么才是面向对象编程?要想了解这个问题我们要先了解面向过程。举个最简单点的例子来区分面向过程和面向对象有一天你想吃鱼香肉丝了,怎么办呢?你有…...

    2024/4/24 7:36:32
  14. 剑指offer 58-翻转单词顺序 C++

    题目描述 牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“student. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I…...

    2024/4/24 7:36:34
  15. C语言读写二进制文件 fopen fwrite

    c语言读取文件:FILE *f = fopen("filename","wb");//w会导致二进制文件写错误,遇到换行符0A会强制写成回车换行符0D0Ac语言写文件:fwrite(buffer,buffersize,count,file);//分别是要写进文件的地址,写入内容大小,写入次数,被写文件eg:int * ints[]=…...

    2024/4/17 21:46:26
  16. POJ 1635 Subway tree systems G++ dfs 背

    #include <iostream> #include <cstdio> #include <string> #include <vector> #include <algorithm> using namespace std; //英语 抄博友程序 dfs 背 string s; string dfs(int l,int r) {vector<string> ve;int js=0;int wz=l…...

    2024/4/15 7:10:52
  17. 关于java连接inux虚拟机单机hbase数据库的操作过程(版本为0.98.24)

    首先说一下我的版本 centos7 hadoop :2.6.0 java:1,7 hbase:0.98.24-hadoop2 (由于是学校老师安排的实验,我是按照他提供的教程的版本安装的,当然这也为我带了很多麻烦) windows下的java版本1.8(版本不一致不会有影响) 一 确认hbase和windows主机能够互ping并且主机能够访问:60…...

    2024/4/16 19:27:37
  18. linux_驱动_V4l2层_camera_调用流程

    一、 摄像头基础介绍 1、摄像头结构和工作原理. 拍摄景物通过镜头,将生成的光学图像投射到传感器上,然后光学图像被转换成电信号,电信号再经过模数转换变为数字信号,数字信号经过DSP加工处理,再被送到电脑中进行处理,最终转换成手机屏幕上能够看到的图…...

    2024/4/16 19:27:55
  19. Charles抓包

    1、使用教程:https://www.jianshu.com/p/831c0114179f2、破解地址:https://www.zzzmode.com/mytools/charles/...

    2024/4/16 19:27:37
  20. 阿里P9精心编写高并发设计手册,来看大厂是如何进行系统设计

    在看这篇文章的应该都是IT圈的朋友吧,不知道你们有没有考虑过这样几件事:淘宝双11的剁手狂欢为什么天猫没崩掉?为什么滴滴打车高峰如何滴滴依旧可以平稳运行?为什么疫情期间,钉钉能支撑那么多人同时上课依旧平稳运行? 有的人可能会说,他们牛啊,后面有数据中心的支撑啊,…...

    2024/4/15 7:10:48

最新文章

  1. [C++ QT项目实战]----C++ QT系统登陆界面设计

    前言 在C QT项目开发过程中&#xff0c;设计系统登录界面可以使用QT框架来实现。以下是一个简单的系统登录界面设计示例&#xff1a; 创建登录界面UI&#xff1a;可以使用QT Designer来设计登录界面的UI&#xff0c;包括用户名输入框、密码输入框、登录按钮等。在QT Designer中…...

    2024/4/27 11:48:01
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. 第十二届蓝桥杯省赛真题(C/C++大学B组)

    目录 #A 空间 #B 卡片 #C 直线 #D 货物摆放 #E 路径 #F 时间显示 #G 砝码称重 #H 杨辉三角形 #I 双向排序 #J 括号序列 #A 空间 #include <bits/stdc.h> using namespace std;int main() {cout<<256 * 1024 * 1024 / 4<<endl;return 0; } #B 卡片…...

    2024/4/26 22:13:34
  4. 基于AI智能识别技术的智慧展览馆视频监管方案设计

    一、建设背景 随着科技的不断进步和社会安全需求的日益增长&#xff0c;展览馆作为展示文化、艺术和科技成果的重要场所&#xff0c;其安全监控系统的智能化升级已成为当务之急。为此&#xff0c;旭帆科技&#xff08;TSINGSEE青犀&#xff09;基于视频智能分析技术推出了展览…...

    2024/4/26 15:50:29
  5. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/4/26 18:09:39
  6. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/4/26 20:12:18
  7. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/4/26 23:05:52
  8. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/4/27 4:00:35
  9. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/4/25 18:39:22
  10. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/4/25 18:39:22
  11. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/4/26 21:56:58
  12. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/4/27 9:01:45
  13. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/4/26 16:00:35
  14. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/4/25 18:39:16
  15. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/4/25 18:39:16
  16. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/4/26 19:03:37
  17. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/4/26 22:01:59
  18. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/4/25 18:39:14
  19. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/4/26 23:04:58
  20. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/4/25 2:10:52
  21. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/4/25 18:39:00
  22. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/4/26 19:46:12
  23. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/4/27 11:43:08
  24. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/4/27 8:32:30
  25. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  26. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  27. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  28. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  29. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  30. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  31. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  32. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  33. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  34. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  35. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  36. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  37. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  38. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  39. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  40. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  41. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  42. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  43. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  44. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57