上一章:python open-cv 基础知识总结(二)

1. 轮廓中心计算

本教程的目标是

(1)  检测图像中每个形状的轮廓,

(2)  计算轮廓的中心 -也称为区域的  质心 。

为了实现这些目标,我们需要执行一些图像预处理,包括:

  • 转换为灰度
  • 进行模糊处理以减少高频噪声,从而使轮廓检测过程更加精确
  • 图像的二值化。通常,边缘检测和阈值化用于该过程。在这篇文章中,我们将应用阈值化
# import the necessary packages
import argparse
import imutils
import cv2# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True,help="path to the input image")
args = vars(ap.parse_args())# load the image, convert it to grayscale, blur it slightly,
# and threshold it
image = cv2.imread(args["image"])
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
thresh = cv2.threshold(blurred, 60, 255, cv2.THRESH_BINARY)[1]# find contours in the thresholded image
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)# loop over the contours
for c in cnts:# compute the center of the contourM = cv2.moments(c)cX = int(M["m10"] / M["m00"])cY = int(M["m01"] / M["m00"])# draw the contour and center of the shape on the imagecv2.drawContours(image, [c], -1, (0, 255, 0), 2)cv2.circle(image, (cX, cY), 7, (255, 255, 255), -1)cv2.putText(image, "center", (cX - 20, cY - 20),cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2)# show the imagecv2.imshow("Image", image)cv2.waitKey(0)

我们从2-4行开始,先导入必要的包,然后解析命令行参数。 我们在这里只需要一个 --image,这是我们要处理的图像驻留在磁盘上的路径。

然后,我们获取此图像,将其从磁盘加载,然后通过应用灰度转换,使用5 x 5内核进行高斯平滑以及最后进行阈值处理(第14-17行)对其进行预处理。

阈值运算的输出如下所示:

请注意,在应用阈值之后,形状是如何在黑色背景上表示为白色前景。

下一步是使用轮廓检测找到这些白色区域的位置:

在第20行和第21行上调用cv2.findContours会返回与图像上每个白色斑点相对应的轮廓(即轮廓)集。 然后,根据我们使用的是OpenCV 2.4、3还是4,第22行获取适当的元组值。

在第25行上,我们开始循环遍历各个轮廓,然后在第27行上计算轮廓区域的图像矩。

在计算机视觉和图像处理中,图像矩通常用于表征图像中对象的形状。 这些力矩捕获了形状的基本统计特性,包括对象的面积,质心(即,对象的中心(x,y)坐标),方向以及其他所需的特性。

在这里,我们只对轮廓的中心感兴趣,该轮廓是在第28和29行上计算的。

第32-34行处理:

  • 通过调用cv2.drawContours绘制围绕当前形状的轮廓轮廓。
  • 在形状的坐标(cX,cY)的中心放置一个白色圆圈。
  • 将文字中心写在白色圆圈附近。

2. 查找图像中的形状

我们的目标:检测图像中的黑色形状。

使用cv2.inRange函数实际上很容易检测到这些黑色形状:

# import the necessary packages
import numpy as np
import argparse
import imutils
import cv2# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", help = "path to the image file")
args = vars(ap.parse_args())# load the image
image = cv2.imread(args["image"])# find all the 'black' shapes in the image
lower = np.array([0, 0, 0])
upper = np.array([15, 15, 15])
shapeMask = cv2.inRange(image, lower, upper)# find the contours in the mask
cnts = cv2.findContours(shapeMask.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
print("I found {} black shapes".format(len(cnts)))
cv2.imshow("Mask", shapeMask)# loop over the contours
for c in cnts:# draw the contour and show itcv2.drawContours(image, [c], -1, (0, 255, 0), 2)cv2.imshow("Image", image)cv2.waitKey(0)

在第16和17行上,我们在BGR颜色空间中定义了上下边界点。 请记住,OpenCV以BGR顺序而不是RGB顺序存储图像。

我们的下边界由纯黑色组成,分别为蓝色,绿色和红色通道中的每个指定零。

我们的上限由一个非常深的灰色阴影组成,这次为每个通道指定15。

然后,我们在第18行的上下限范围内找到所有像素。

我们的shapeMask现在看起来像这样:

如您所见,原始图像中的所有黑色形状现在在黑色背景上均为白色。

下一步是检测shapeMask中的轮廓。 这也很简单:

我们在第21和22行调用cv2.findContours,指示它找到形状的所有外部轮廓(即边界)。

由于各种版本的OpenCV处理轮廓的方式不同,我们在第23行分析了轮廓。

从那里,我们将找到的轮廓数量打印到控制台。

然后,我们开始在第28行上循环遍历各个轮廓,并在第30行上将形状的轮廓绘制到原始图像上。

3. 查找轮廓中的极点

我将演示如何沿轮廓找到最北,南,东和西(x,y)坐标,就像本博文顶部的图像一样。

尽管这项技能本身并不是天生就有用的,但通常被用作更高级的计算机视觉应用程序的预处理步骤。 手势识别就是一个很好的例子。

我们的目标是计算图像中手部轮廓的极限点。

# import the necessary packages
import imutils
import cv2# load the image, convert it to grayscale, and blur it slightly
image = cv2.imread("hand_01.png")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (5, 5), 0)# threshold the image, then perform a series of erosions +
# dilations to remove any small regions of noise
thresh = cv2.threshold(gray, 45, 255, cv2.THRESH_BINARY)[1]
thresh = cv2.erode(thresh, None, iterations=2)
thresh = cv2.dilate(thresh, None, iterations=2)# find contours in thresholded image, then grab the largest
# one
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
c = max(cnts, key=cv2.contourArea)# determine the most extreme points along the contour
extLeft = tuple(c[c[:, :, 0].argmin()][0])
extRight = tuple(c[c[:, :, 0].argmax()][0])
extTop = tuple(c[c[:, :, 1].argmin()][0])
extBot = tuple(c[c[:, :, 1].argmax()][0])# draw the outline of the object, then draw each of the
# extreme points, where the left-most is red, right-most
# is green, top-most is blue, and bottom-most is teal
cv2.drawContours(image, [c], -1, (0, 255, 255), 2)
cv2.circle(image, extLeft, 8, (0, 0, 255), -1)
cv2.circle(image, extRight, 8, (0, 255, 0), -1)
cv2.circle(image, extTop, 8, (255, 0, 0), -1)
cv2.circle(image, extBot, 8, (255, 255, 0), -1)
# show the output image
cv2.imshow("Image", image)
cv2.waitKey(0)

第2行和第3行导入我们所需的包。 然后,我们从磁盘加载示例图像,将其转换为灰度,然后稍微高斯模糊。

第12行执行阈值处理,使我们能够将手部区域与其余图像分开。 阈值化后,我们的二进制图像如下所示:

为了检测手的轮廓,我们调用cv2.findContours,然后对轮廓进行排序以找到最大的轮廓,我们假定是手本身(第18-21行)。

在我们沿着轮廓找到极限点之前,重要的是要了解轮廓只是(x,y)坐标的NumPy数组。 因此,我们可以利用NumPy函数来帮助我们找到极限坐标。

例如,第24行通过调用x值上的argmin()并获取与x值关联的整个(x,y)坐标来找到整个轮廓数组c中最小的x坐标(即“西”值)。 argmin()返回的索引。

同样,第25行使用argmax()函数在轮廓数组中找到最大的x坐标(即“东”值)。

第26和27行仅对y坐标执行相同的操作,分别为我们提供“北”和“南”坐标。

现在我们有了极端的北,南,东和西坐标,我们可以在图像上绘制它们

4 轮廓排序

  • 根据轮廓的大小/区域对轮廓进行排序,并按照模板按照其他任意标准对轮廓进行排序。
  • 仅使用一个功能就可以从左到右,从右到左,从上到下以及从下到上对轮廓区域进行排序。
# import the necessary packages
import numpy as np
import argparse
import imutils
import cv2def sort_contours(cnts, method="left-to-right"):# initialize the reverse flag and sort indexreverse = Falsei = 0# handle if we need to sort in reverseif method == "right-to-left" or method == "bottom-to-top":reverse = True# handle if we are sorting against the y-coordinate rather than# the x-coordinate of the bounding boxif method == "top-to-bottom" or method == "bottom-to-top":i = 1# construct the list of bounding boxes and sort them from top to# bottomboundingBoxes = [cv2.boundingRect(c) for c in cnts](cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes),key=lambda b:b[1][i], reverse=reverse))# return the list of sorted contours and bounding boxesreturn (cnts, boundingBoxes)def draw_contour(image, c, i):# compute the center of the contour area and draw a circle# representing the centerM = cv2.moments(c)cX = int(M["m10"] / M["m00"])cY = int(M["m01"] / M["m00"])# draw the countour number on the imagecv2.putText(image, "#{}".format(i + 1), (cX - 20, cY), cv2.FONT_HERSHEY_SIMPLEX,1.0, (255, 255, 255), 2)# return the image with the contour number drawn on itreturn image# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True, help="Path to the input image")
ap.add_argument("-m", "--method", required=True, help="Sorting method")
args = vars(ap.parse_args())# load the image and initialize the accumulated edge image
image = cv2.imread(args["image"])
accumEdged = np.zeros(image.shape[:2], dtype="uint8")# loop over the blue, green, and red channels, respectively
for chan in cv2.split(image):# blur the channel, extract edges from it, and accumulate the set# of edges for the imagechan = cv2.medianBlur(chan, 11)edged = cv2.Canny(chan, 50, 200)accumEdged = cv2.bitwise_or(accumEdged, edged)# show the accumulated edge map
cv2.imshow("Edge Map", accumEdged)# find contours in the accumulated image, keeping only the largest
# ones
cnts = cv2.findContours(accumEdged.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)[:5]
orig = image.copy()# loop over the (unsorted) contours and draw them
for (i, c) in enumerate(cnts):orig = draw_contour(orig, c, i)# show the original, unsorted contour image
cv2.imshow("Unsorted", orig)# sort the contours according to the provided method
(cnts, boundingBoxes) = sort_contours(cnts, method=args["method"])# loop over the (now sorted) contours and draw them
for (i, c) in enumerate(cnts):draw_contour(image, c, i)# show the output image
cv2.imshow("Sorted", image)
cv2.waitKey(0)

我们将从导入必要的程序包开始:NumPy用于数值处理,argparse用于解析命令行参数,cv2用于我们的OpenCV绑定。

让我们暂时跳过这些步骤,然后立即跳入定义我们的sort_contours函数,该函数使我们能够对轮廓进行排序,而不必先解析参数,加载图像并执行其他常规过程,而不必从头开始。

实际的sort_contours函数在第7行中定义,并带有两个参数。第一个是cnts,我们要排序的轮廓列表,第二个是sorting方法,它指示我们要对轮廓进行排序的方向(即,从左到右,从上到下等)。

从那里,我们将在第9行和第10行上初始化两个重要的变量。这些变量仅表示排序顺序(升序或降序)以及我们将用于执行排序的边界框的索引(稍后会详细介绍)。我们将初始化这些变量,使其以升序排列,并沿着轮廓的边界框的x轴位置排列。

如果是从右到左或从下到上排序,则需要根据图像中轮廓的位置以降序排序(第13和14行)。

同样,在第18行和第19行,我们检查是从上到下还是从下到上进行排序。如果是这种情况,那么我们需要根据y轴值而不是x轴进行排序(因为我们现在是垂直而非水平排序)。

轮廓的实际排序发生在第23-25行。

我们首先计算每个轮廓的边界框,它只是边界框的起始(x,y)坐标,然后是宽度和高度(因此称为“边界框”)。 (第23行)

boundingBoxes使我们能够对实际的轮廓进行排序,我们使用一些Python魔术在第24行和第25行上对两个列表进行了排序。使用此代码,我们可以根据我们提供的标准对轮廓和边界框进行排序。

最后,我们将边界框和轮廓的(现在已排序)列表返回到第28行的调用函数。

在此过程中,让我们继续定义另一个帮助器函数draw_contour。

此函数仅在第33-35行上计算所提供轮廓c的中心(x,y)坐标,然后使用该中心坐标在第38和39行上绘制轮廓ID i。

最后,传入的图像返回到第42行的调用函数。

同样,这只是一个辅助功能,我们将利用它在实际图像上绘制轮廓ID号,以便可视化工作结果。

现在已经完成了辅助功能,让我们将驱动程序代码放置在适当的位置以拍摄实际图像,检测轮廓并对其进行排序。

第45-48行不是很有趣-它们只是解析我们的命令行参数,--image是我们的图像在磁盘上的驻留路径,而--method是我们想要的方向的文本表示。 整理轮廓。

从那里,我们将图像从第51行的磁盘上加载下来,并在第52行的边缘图上分配内存。

构造实际的边缘贴图发生在第55-60行,我们在图像的每个蓝色,绿色和红色通道(第55行)上循环,对每个通道略微模糊以消除高频噪声(第58行),执行边缘检测, (第59行),并在第60行上更新累积的边缘贴图。

我们在第63行显示累积的边缘图,如下所示:

如您所见,我们已经检测到图像中乐高积木的实际边缘轮廓。

现在,让我们看看是否可以

(1)找到这些乐高积木的轮廓,

(2)然后对它们进行排序。

很显然,这里的第一步是在67-69行的累积边缘地图图像中找到实际轮廓。我们正在寻找乐高积木的外部轮廓,该轮廓仅与它们的轮廓相对应。

基于这些轮廓,我们现在将结合使用Python排序函数和cv2.contourArea方法根据它们的大小对它们进行排序-这使我们能够根据轮廓的面积(即大小)从最大到最大对它们进行排序。最小(第70行)。

我们采用这些排序的轮廓(就大小而言,而不是位置),在74行上对其进行循环,并使用draw_contour辅助函数在76行上绘制各个轮廓。

该图像然后显示在第78行的屏幕上。

但是,您会注意到,我们的轮廓仅根据其大小进行了排序-并未关注其在图像中的实际位置。

我们在第81行上解决了这个问题,我们在其中调用了自定义sort_contours函数。此方法接受我们的轮廓列表以及排序方向方法(通过命令行参数提供),并对它们进行排序,分别返回已排序的边界框和轮廓的元组。

最后,我们采用这些已排序的轮廓,在其上循环,绘制每个轮廓,最后将输出图像显示在屏幕上(第84-89行)。

python open-cv 基础知识总结(三)相关推荐

  1. Python入门之基础知识(三)

    文章目录 前言 一.序列是什么? 二.列表的概念 三.列表的创建 1.基本语法[]创建 2.list()创建 3.range()创建 4.推导式创建 四.列表元素的增加或删除 1.通过Append() ...

  2. CV:传统视觉知识—机器视觉系统的基础知识(机器视觉三要素+典型的工业机器视觉系统五大组件)

    CV:传统视觉知识-机器视觉系统的基础知识(机器视觉三要素+典型的工业机器视觉系统五大组件) 目录 机器视觉三要素 1.what-测量.判断 2.why-灵活性.自动化

  3. Python复习系列:Python基础知识(三)

    Python基础知识(三) Python基础知识(三) (一)循环结构和选择结构 1. 条件表达式 2. 选择结构 2.1 单分支选择结构 2.2 双分支选择结构 2.3 多分支选择结构 2.4 选择 ...

  4. Python培训入门基础知识学什么?

    Python培训基础知识主要是针对一些零基础的同学安排的,虽说Python是相对比较简单的一门编程语言,但是没有基础的同学还是要进行系统的学习,那么Python培训入门基础知识学什么呢?来看看下面小编 ...

  5. 学python需要什么基础知识-没学过Python先要学习哪些基础知识?

    零基础学Python应该学习哪些入门知识 关于零基础怎么样能快速学好Python的问题,百度提问和解答的都很多,你可以百度下看看.我觉得从个人自学的角度出发,应从以下几个方面来理解: 1 为什么选择学 ...

  6. python基础知识资料-学习Python列表的基础知识汇总

    千里之行,始于足下.要练成一双洞悉一切的眼睛,还是得先把基本功扎扎实实地学好.今天,本喵带大家仔细温习一下Python的列表.温故而知新,不亦说乎. 当然,温习的同时也要发散思考,因为有些看似无关紧要 ...

  7. python二级公共基础知识

    python二级公共基础知识 一.算法和数据结构 算法及其基本特征: 算法是对解题方法的准确而完整的描述. 算法的四个基本特征:可行性,确定性,有穷性,拥有足够的情报.  算法的复杂度: 算法的时间复 ...

  8. 初识 Python 必看基础知识~ 熬夜爆肝

    本文主要梳理一些 Python 入门的基础知识,分享给每一位走在IT路上的侠客~ 全文知识梳理来源于<Python编程 从入门到实践(第2版)> 声明:未打广告,豆瓣评分9.3,刷博客时见 ...

  9. Python复习笔记——基础知识

    Python复习笔记-基础知识 文章目录 Python复习笔记-基础知识 Python变量 基于值的内存管理方式 赋值语句的执行过程 Python定义变量名的规范 运算符和表达式 加+ 乘* 除/ % ...

  10. 零基础可以学python吗-学Python需要什么基础知识?零基础可以学Python吗?

    学Python需要什么基础知识?一般来说,想要学Python最好具备一定的计算机专业知识,尤其是数学和英语不错的话,对学Python也有一定的帮助.但是零基础的学习者就不能学Python了吗?当然不是 ...

最新文章

  1. jupyter python版本_Ubuntu Desktop 16.04 LTS 下成功配置Jupyter的两个python内核版本(2.7x,3.5x)...
  2. max7219驱动共阳点阵
  3. js获取被点击的元素以及子元素
  4. 计算机无法用telnet,为何我的电脑cmd没法使用telnet命令?
  5. MySQL不使用逗号_Mysql 不能使用逗号的情况
  6. linux系统下top命令的详细用法、参数详解、以及模式配置
  7. 在JUnit中处理异常的3种方法。 选择哪一个?
  8. 通过 .NET Framework 中的 XPath 和 XSLT API 方便地操作 XML 数据
  9. python程序设计搜题软件下载_智慧职教云课堂APPPython程序设计答案搜题公众号
  10. 无迹卡尔曼滤波(UKF)详解
  11. 如何快速辨识四位数字贴片电阻阻值
  12. Android图片选择器PhotoPicker
  13. Linux命令分隔符
  14. ggplot绘制小提琴图
  15. 千万不要死于无知——心理状态
  16. STM32实现LED流水灯
  17. 迷你计算机主板,打造最强MINI主机 五款高规ITX主板推荐
  18. 设备厂商Plc远程上下载程序远程调试运维
  19. avi怎么转换成视频mp4
  20. 反恐24小时[第1季]——我打赌这是我第一次写观后感

热门文章

  1. 计算机找不到 bitlocker,win10系统bitlocker找不到tpm的解决方法
  2. 【计算机】ELF文件和BIN文件
  3. 第4章 空间数据转换算法
  4. HotSpot 类加载
  5. Android软键盘输入详解
  6. 免费在线进行图片压缩
  7. php爬虫爬取百度的内容,爬虫(一)抓取百度页面的内容
  8. Python之多进程与多线程
  9. 名编辑电子杂志大师教程 | 添加广告插件
  10. uniapp 微信小程序留言板+动态显示新增留言