1.基于OpenCV的形状检测Python版本

目录结构

1.1.定义我们的形状检测器类ShapeDetector

开始定义我们的 ShapeDetector 类。我们将跳过这里的 init 构造函数,因为不需要初始化任何东西。

# 导入必要的包
import cv2


class ShapeDetector:
    def __init__(self):
        pass

    def detect(self, c):
        # 初始化形状名称并近似轮廓
        shape = "unidentified"
        peri = cv2.arcLength(c, True)
        approx = cv2.approxPolyDP(c, 0.04 * peri, True)

我们的检测方法,它只需要一个参数 c,即我们试图识别的形状的轮廓。为了进行形状检测,我们将使用轮廓逼近。

顾名思义,轮廓近似是一种算法,用于减少曲线中点的数量,并减少点集——因此称为近似。

轮廓近似是基于曲线可以由一系列短线段近似的假设。这导致生成的近似曲线由原始曲线定义的点的子集组成。

轮廓近似实际上已经在 OpenCV 中通过 cv2.approxPolyDP 方法实现。

为了进行轮廓逼近,我们首先计算轮廓的周长,然后构建实际的轮廓逼近。 cv2.approxPolyDP 的第二个参数的常用值通常在原始轮廓周长的 1%-5% 范围内。

给定我们的近似轮廓,我们可以继续执行形状检测:

        # 如果形状是一个三角形,它将有3个顶点
        if len(approx) == 3:
            shape = "triangle"
        # 如果形状有4个顶点,它要么是正方形,要么是矩形
        elif len(approx) == 4:
            # 计算轮廓的包围框,并使用包围框计算高宽比
            (x, y, w, h) = cv2.boundingRect(approx)
            ar = w / float(h)
            # 正方形的长宽比大约等于1,否则,形状就是矩形
            shape = "square" if ar >= 0.95 and ar <= 1.05 else "rectangle"
        # 如果形状是一个五边形,它将有5个顶点
        elif len(approx) == 5:
            shape = "pentagon"
        # 否则,我们假设形状是一个圆
        else:
            shape = "circle"
        # 返回形状的名称
        return shape

重要的是要了解轮廓由顶点列表组成。我们可以检查此列表中的数目以确定对象的形状。例如,如果近似轮廓有三个顶点

那么它一定是一个三角形。如果一条轮廓有四个顶点,那么它一定是正方形或矩形。为了确定这一点,我们计算形状的长宽比

也就是轮廓边界框的宽度除以高度。如果长宽比是~1.0,那么我们正在检查一个正方形(因为所有的边都有大约相等的长度)。否则,形状就是矩形。如果一条等高线有五个顶点,我们可以将其标记为五边形。否则,我们可以假设我们正在检查的形状是一个圆。

最后,将标识好的形状返回给调用方法。

我们已经定义了一个utils模块。在这个模块中,我们有shapedetector .py,它将存储ShapeDetector类的实现。

最后,我们有detect_shapes.py脚本,我们将使用它从磁盘加载图像,分析它的形状,然后通过ShapeDetector类执行形状检测和识别。

1.2.基于OpenCV的形状检测器

现在我们的 ShapeDetector 类已经定义好了,让我们创建 detect_shapes.py 脚本:

# 导入必要的库
from utils.shapedetector import ShapeDetector
import argparse
import imutils
import cv2

# 构造参数解析并解析参数
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", default="inpaint.jpg", help="path to the input image")
args = vars(ap.parse_args())

首先导入我们已经实现的ShapeDetector类,然后解析参数,下一步,我们开始预处理我们的图像

# 加载图像并将其调整图像大小,以便更好地近似形状
image = cv2.imread(args["image"])
resized = imutils.resize(image, width=300)
ratio = image.shape[0] / float(resized.shape[0])
# 将调整后的图像转换为灰度,稍微模糊它,并阈值化
gray = cv2.cvtColor(resized, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
thresh = cv2.threshold(blurred, 60, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
# 在阈值化图像中找到轮廓并初始化形状检测器
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
                        cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
sd = ShapeDetector()

首先,我们从磁盘加载图像,并调整其大小。然后,我们跟踪旧高度与调整后的新高度的比率——我们将在本教程的后面部分找到这样做的确切原因。

将调整大小后的图像转换为灰度,平滑它以减少高频噪声,最后阈值化它以显示图像中的形状。

阈值之后,我们的图像应该是这样的:

请注意我们的图像是如何被二值化的——形状显示为黑色背景下的白色前景。

最后,在二值图像中找到轮廓,基于OpenCV版本的cv2.findContours获取正确的元组值,并最终初始化我们的ShapeDetector。

最后一步是识别每个轮廓:

# 遍历所有轮廓
for c in cnts:
    # 计算轮廓的中心,然后仅使用轮廓检测形状的名称
    M = cv2.moments(c)
    cX = int((M["m10"] / M["m00"]) * ratio)
    cY = int((M["m01"] / M["m00"]) * ratio)
    shape = sd.detect(c)
    # 将轮廓(x, y)坐标乘以调整比例,然后在图像上绘制轮廓和形状的名称
    c = c.astype("float")
    c *= ratio
    c = c.astype("int")
    cv2.drawContours(image, [c], -1, (0, 255, 0), 2)
    cv2.putText(image, shape, (cX, cY), cv2.FONT_HERSHEY_SIMPLEX,
                0.5, (255, 255, 255), 2)
    # 显示输出图像
    cv2.imshow("Image", image)
    cv2.waitKey(0)

我们开始在每个单独的轮廓上循环。对于每一个,我们计算轮廓的中心,然后执行形状检测和识别。

由于我们正在处理从调整大小后的图像中提取的轮廓(而不是原始图像),我们需要将轮廓和中心(x, y)坐标乘以调整比率。

这将为我们提供原始图像的轮廓和质心的正确(x, y)坐标。

最后,我们在图像上绘制轮廓和识别的形状,然后显示我们的结果。

2.基于OpenCV的形状检测C 版本

在本教程中,让我们看看如何使用 OpenCV 的轮廓来识别对象的形状和位置。

使用OpenCV的轮廓,你可以得到每个白斑的顶点的点序列(白斑被认为是多边形)。例如,对于三角形你会得到3个点(顶点),

对于四边形你会得到4个点。你可以通过多边形的顶点数来识别任何多边形。

你甚至可以通过计算和比较顶点之间的距离来识别多边形的特征,如凸性、凹性、等边等。

我们看看如何使用 OpenCV 来完成。您所需要的只是一个二进制图像,其中您的对象应该是白色的,背景应该是黑色的。

现在我将使用OpenCV C 应用程序来识别上图中的三角形、四边形和七边形。我将沿着每个确定的多边形的周长画一条线,

三角形颜色为蓝色,四边形颜色为绿色,七边形颜色为红色。

2.1代码实现

#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;

int main()
{

    Mat img = imread("FindingContours.png");

    //show the original image
    namedWindow("Raw");
    imshow("Raw", img);

    //converting the original image into grayscale
    Mat imgGrayScale = Mat(img.size(), CV_8UC1);
    cvtColor(img, imgGrayScale, COLOR_BGR2GRAY);

    //thresholding the grayscale image to get better results
    threshold(imgGrayScale, imgGrayScale, 128, 255, THRESH_BINARY);

    //finding all contours in the image
    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;
    findContours(imgGrayScale, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);


    //iterating through each contour
    for (size_t i = 0; i < contours.size(); i  )
    {
        vector<Point> approx;
        //obtain a sequence of points of contour, pointed by the variable 'contour'
        approxPolyDP(contours[i], approx, arcLength(contours[i], true) * 0.02, true);

        //if there are 3  vertices  in the contour(It should be a triangle)
        if (approx.size() == 3)
        {
            //drawing lines around the triangle
            for (int i = 0; i < 3; i  ) {
                line(img, approx[i], approx[(i 1)%3], Scalar(255, 0, 0), 4);
            }
        }
        //if there are 4 vertices in the contour(It should be a quadrilateral)
        else if (approx.size() == 4)
        {
            //drawing lines around the quadrilateral
            for (int i = 0; i < 4; i  ) {
                line(img, approx[i], approx[(i   1) % 4], Scalar(0, 255, 0), 4);
            }
        }

        //if there are 7  vertices  in the contour(It should be a heptagon)
        else if (approx.size() == 7)
        {
            //drawing lines around the heptagon
            for (int i = 0; i < 7; i  ) {
                line(img, approx[i], approx[(i   1) % 7], Scalar(0, 0, 255), 4);
            } 
        }
    }

    //show the image in which identified shapes are marked   
    namedWindow("Tracked");
    imshow("Tracked", img);

    waitKey(0); //wait for a key press

    //cleaning up
    destroyAllWindows();

    return 0;
}

如您所见,三角形用蓝色标记, 四边形用绿色标记,七边形用红色标记。所以,现在很明显,这种方法能够识别形状。 首先将原始图像转换为灰度。

这是因为这种方法只适用于单通道的灰度图像。为了获得更好的结果,我使用“threshold”函数对灰度图像进行阈值处理。

您可以使用自己的方式对图像进行阈值处理。然后我找到阈值图像中的所有轮廓,并识别和跟踪所有三角形、四边形和七边形。

2.2主要函数解析

让我们讨论一下这个应用程序中的OpenCV 函数。

double threshold(InputArray src, OutputArray dst, double thresh, double maxval, int type);

src:源图像(8位单通道)

dst:与src具有相同大小相同类型的目标图像

thresh:阈值

maxval:滿足條件的像素替换为这个值

type:阈值化方法,

THRESH_BINARY

  • dst(x,y)=max, if src(x,y) > ThreshVal
  • dst(x,y)=0, if src(x,y) < ThreshVal

THRESH_BINARY_INV

  • dst(x,y)=0,如果 src(x,y) > ThreshVal
  • dst(x,y)=max,如果 src(x,y) < ThreshVal

THRESH_TOZERO

  • dst(x,y)=src(x,y), 如果 src(x,y) > ThreshVal
  • dst(x,y)=0, 如果 src(x,y) < ThreshVal

THRESH_TOZERO_INV

  • dst(x,y)=0,如果 src(x,y) > ThreshVal
  • dst(x,y)=src(x,y),如果 src(x,y) < ThreshVal

THRESH_TRUNC

  • dst(x,y)=threshVal,如果 src(x,y) > ThreshVal
  • dst(x,y)=src(x,y), if src(x,y) < ThreshVal

在上面的应用程序中,我使用了“ THRESH_BINARY”,因为我想在对象所在的位置分配 255(白色其他是0(黑色)。

findContours( InputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method, Point offset = Point());

image: 8位单通道图像。非零像素被视为1。零像素保持为0,因此图像被视为二值。你可以使用#compare #inRange #threshold,#adaptiveThreshold,

#Canny,以及其他参数来创建灰度或彩色图像的二值图像。

contours: 发现的所有轮廓

hierarchy:轮廓之间的层次结构

int mode - 从图像中检索轮廓的模式,您必须选择以下之一

  • RETR_LIST - 检索所有轮廓并将它们放入列表中
  • RETR_EXTERNAL - 仅检索外轮廓
  • RETR_CCOMP - 检索所有轮廓并将它们组织成两级层次结构:
  • RETR_TREE - 检索所有轮廓并重建嵌套轮廓的完整层次结构

int method - 近似方法,您必须选择以下之一

  • CHAIN_APPROX_NONE - 将链码中的所有点转换为点
  • CHAIN_APPROX_SIMPLE - 压缩水平、垂直和对角线段,只留下它们的端点
  • CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS - 应用 Teh-Chin 链近似算法的一种风格。

Point offset:每个轮廓点应移动的偏移量。当我们在图像中设置 ROI(感兴趣区域)时,这很有用。通常我们将偏移量设置为 ‘Point(0,0)’

void approxPolyDP( InputArray curve, OutputArray approxCurve, double epsilon, bool closed );

  • curve: 存储2D点的std::vector或Mat
  • approxCurve: 多边形近似的结果。类型应该与输入类型相匹配。
  • epsilon: 指定近似精度的参数。这是原始轮廓与其近似值之间的最大距离。
  • closed: 如果为真,逼近曲线是闭合的(它的第一个和最后一个顶点是连接的)。否则不闭合。

2.3结果展示

以上就是OpenCV形状检测的示例详解的详细内容,更多关于OpenCV形状检测的资料请关注Devmax其它相关文章!

OpenCV形状检测的示例详解的更多相关文章

  1. iOS使用openCV检测来自摄像头的矩形

    如果我在处理它之前克隆matimage,通过记录它,它似乎处理图像甚至找到矩形,但矩形不会被绘制到图像输出到imageView.我很确定我错过了一些东西,可能是因为我没有正确传递某个对象,指向对象的指针等等,而我需要修改的对象则没有.无论如何,如果这不是正确的方法,我真的很感谢他们做这样的事情的教程或例子,使用openCV或GPUImage…它不需要尝试使用matimage来设置imageView.image,而只需要将matimage转换为在imageView中实际修改,因为CvVideoCamera已

  2. 使用Xcode为OS X Lion / Mountain Lion编译OpenCV(2.3.1)

    任何人都可以为我提供一些如何使用Xcode在OSXLion上编译OpenCV2.3.1的详细指南吗?我对此感到生气…我得到了源码,使用cmake创建Xcode模板并尝试构建它,但它失败了大约200个错误.提前致谢,大教堂解答我的回答帖子.解决方法详细指南如何使用MacPorts在Xcode4.2.1的OSXLion下启动和运行OpenCV2.3.1编辑08/06/2012:这也适用于OpenCV2.4.1.只需确保您获得最新版本的Xcode并安装“命令行工具”.编辑15/08/2012:使用Mountai

  3. ios – OpenCV构建问题,找不到ext/atomicity.h

    我得到编译器错误抱怨在构建包含OpenCV的项目时.环境是针对iOS的Xcode4.5.它为模拟器编译良好,但在为设备构建时失败.这是错误文本:我正在使用opencv2.framework,使用指令here构建cmake.解决方法默认情况下,XCode4.5使用libc(支持C11的LLVMC标准库)生成要构建的新项目.但OpenCV期望针对GNUlibstd

  4. 从IOS / iPad / iPhone的最大速度

    我使用OpenCVforiOS完成计算密集型应用程序.当然这很慢.但它比我的PC原型慢了200倍.所以我正在优化它.从最初的15秒,我能够获得0.4秒的速度.我想知道我是否找到了所有的东西以及别人想要分享的东西.我做了什么:>将OpenCV中的“double”数据类型替换为“float”.双倍是64位,32位cpu不能轻易处理,所以浮动给了我一些速度.OpenCV经常使用双倍.>为编译器选项添加了

  5. 在Swift iOS中使用OpenCV

    在我的xcode项目中添加OpenCV2框架后,我试图搜索samlpes或教程与swift集成。有什么好的教程同样吗?OpenCV是用C编写的框架。苹果的reference告诉我们YoucannotimportC++codedirectlyintoSwift.Instead,createanObjective-CorCwrapperforC++code.所以你不能在一个swift项目中直接导入和使用OpenCV,但这实际上并不坏,因为你(需要)继续使用框架的C语法,这是在网络上有很多文档。那么你怎么进行呢

  6. 在Android Studio中解决已弃用的NDK警告

    或者除了添加所有已编译的代码并设置我之前提到的标志之外,还有其他方法可以将OpenCV导入Android项目吗?任何有关这方面的帮助将不胜感激.解决方法我建议迁移到使用cmake的本机支持.您可以查看链接,该链接提供了使用cmake通过以下link添加OpenCV的分步教程.您的代码应该保持不变而不做任何更改,只有必要的操作才能弄清楚如何使用CMakeLists.txt将它们包含在构建过程中.

  7. android – opencv管理器包没找到?如何自动安装?

    我正在使用openCV,每当我运行代码时它都会给我包管理器没有安装,那么如何通过我的应用程序安装它.是必须从Play商店下载它还是我们可以在设备中自动安装它.请帮我.提前致谢.解决方法您需要使用静态初始化来包含apk中的所有OpenCV二进制文件.请参阅此文档:ApplicationDevelopmentwithStaticInitialization

  8. 如何从Android相机中找到框架的轮廓并将其转换为box2d实体?

    使用openframeworks,OpenCV和Box2D,我能够以良好的帧速率实现它.使用Android似乎是一项更复杂的任务(部分原因是我是JAVA新手).这就是我的开始:>使用“OpenCV示例–图像处理”并删除除“canny”效果之外的所有内容,这会产生一个漂亮的黑色&白色图像,非常适合找到轮廓.>从“OpenCVSample–color-blob-detection”中我抓住了在Mat中

  9. 在Android上的OpenCV中逐帧处理视频

    如果是的话,你知道任何例子.>编译适用于Android的FFMPEG也是一种选择.但是,我认为自己编写FrameGrabber和FrameRecorder有点过分.我认为除了JavaCV之外,还必须存在一些解决方案.>从API18开始,Android中有MediaCodec和Mediamuxer.也许他们可以帮助我?

  10. 使用opencv进行android角点跟踪

    当我相对于Android相机移动它时,我试图跟踪一张纸的角落的位置(您可以假设纸张将是与背景完全不同的颜色).我想找到android屏幕上每个角落的x,y坐标.我也希望能够改变纸张的角度,因此它不一定会一直呈现出完美的矩形.我正在使用opencv2.4.1forAndroid,但我在包中找不到cvgoodfeaturetotrack或cvfindcornersubpix.现在我正在考虑使用CvCa

随机推荐

  1. 10 个Python中Pip的使用技巧分享

    众所周知,pip 可以安装、更新、卸载 Python 的第三方库,非常方便。本文小编为大家总结了Python中Pip的使用技巧,需要的可以参考一下

  2. python数学建模之三大模型与十大常用算法详情

    这篇文章主要介绍了python数学建模之三大模型与十大常用算法详情,文章围绕主题展开详细的内容介绍,具有一定的参考价值,感想取得小伙伴可以参考一下

  3. Python爬取奶茶店数据分析哪家最好喝以及性价比

    这篇文章主要介绍了用Python告诉你奶茶哪家最好喝性价比最高,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧

  4. 使用pyinstaller打包.exe文件的详细教程

    PyInstaller是一个跨平台的Python应用打包工具,能够把 Python 脚本及其所在的 Python 解释器打包成可执行文件,下面这篇文章主要给大家介绍了关于使用pyinstaller打包.exe文件的相关资料,需要的朋友可以参考下

  5. 基于Python实现射击小游戏的制作

    这篇文章主要介绍了如何利用Python制作一个自己专属的第一人称射击小游戏,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起动手试一试

  6. Python list append方法之给列表追加元素

    这篇文章主要介绍了Python list append方法如何给列表追加元素,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  7. Pytest+Request+Allure+Jenkins实现接口自动化

    这篇文章介绍了Pytest+Request+Allure+Jenkins实现接口自动化的方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  8. 利用python实现简单的情感分析实例教程

    商品评论挖掘、电影推荐、股市预测……情感分析大有用武之地,下面这篇文章主要给大家介绍了关于利用python实现简单的情感分析的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下

  9. 利用Python上传日志并监控告警的方法详解

    这篇文章将详细为大家介绍如何通过阿里云日志服务搭建一套通过Python上传日志、配置日志告警的监控服务,感兴趣的小伙伴可以了解一下

  10. Pycharm中运行程序在Python console中执行,不是直接Run问题

    这篇文章主要介绍了Pycharm中运行程序在Python console中执行,不是直接Run问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

返回
顶部