欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

边缘/轮廓检测

程序员文章站 2022-07-14 09:47:07
...

边缘/轮廓检测

Canny边缘检测

Canny边缘检测原理

Canny边缘检测的一般步骤

  • step1:去噪
    • 边缘检测容易受到噪声的影响。因此,在进行边缘检测前,通常需要先进行去噪
    • 通常采用高斯滤波器去除噪声
  • step2:梯度
    • 对平滑后的图像采用sobel算子计算梯度和方向
    • 梯度的方向一般总是与边界垂直
    • 梯度方向被归为四类:垂直、水平、两个对角线
  • step3:非极大值抑制
    • 在获得了梯度和方向后,遍历图像,去除所有不是边界的点
    • 实现方法:逐个遍历像素点,判断当前像素点是否是周围像素点中具有相同方向梯度的最大值;若是,保留该点;否则,抑制(归零)
    • 例子:下图黄色背景的值被保留,其余点被抑制(处理为0)
      边缘/轮廓检测
  • step4:滞后阈值
    • 两个值:minVal:滞后阈值1;maxVal:滞后阈值2
    • 阈值越大,信息越少
    • 例子:
      边缘/轮廓检测
Canny函数及使用

edges = cv2.Canny(image, threshold1, threshold2)

  • edges:边界图像
  • image:原始图像
  • threshold1:阈值1(minVal
  • threshold2:阈值2(maxVal

操作小记

import cv2

o = cv2.imread("lena.jpg", cv2.IMREAD_GRAYSCALE)
r = cv2.Canny(o, 100, 200)
cv2.imshow("ori", o)
cv2.imshow("res", r)
cv2.waitKey()
cv2.destroyAllWindows()

效果
边缘/轮廓检测

轮廓查找和绘制

图像轮廓

轮廓定义

  • 边缘检测能够测出边缘,但是边缘是不连续的
  • 将边缘连接为一个整体,构成轮廓

注意问题

  • 对象是二值图像。所以需要预先进行阈值分割或者边缘检测处理
  • 查找轮廓需要更改原始图像。因此,通常使用原始图像的一份拷贝操作
  • 在OpenCV中,是从黑色背景中查找白色对象。因此,对象必须是白色的,背景必须是黑色的

使用函数

  • cv2.findContours():查找图像轮廓的函数
    • contours, hierarchy = cv2.findContours(image, mode, method)
      • contours:轮廓
      • hierarchy:图像的拓扑信息(轮廓层次)
      • image:原始图像
      • mode:轮廓检索模式
        • cv2.RETR_EXTERNAL:表示只检测外轮廓
        • cv2.RETR_LIST:检测的轮廓不建立等级关系
        • cv2.RETR_CCOMP:建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层
        • cv2.RETR_TREE:建立一个等级树结构的轮廓
      • method:轮廓的近似方法
        • cv2.CHAIN_APPROX_NONE:存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2), abs(y2-y1)) == 1
        • cv2.CHAIN_APPROX_SIMPLE:压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息
        • cv2.CHAIN_APPROX_TC89_L1:使用teh-Chinl chain 近似算法
        • cv2.CHAIN_APPROX_TC89_KCOS:使用teh-Chinl chain 近似算法
  • cv2.drawContours():将查找的轮廓绘制到图像上
    • r = cv2.drawContours(o, contours, contourldx, color[, thickness])
      • r:目标图像,直接修改目标的像素点,实现绘制
      • o:原始图像
      • contours:需要绘制的边缘数组
      • contourldx:需要绘制的边缘索引,如果全部绘制则为 -1
      • color:绘制的颜色,为BGR格式的Scalar
      • thickness:可选,绘制的密度,即描述轮廓时所用的画笔粗细

注意:若是采用这个格式img, contours, hierarchy = cv2.findContours(image, mode, method)会报下面错误,原因是opencv的方法改掉了,findCountours方法被修改为只返回coutours和hierarchy

Traceback (most recent call last):
  File "D:/data/Code/PycharmProjects/helloworld/test.py", line 7, in <module>
    img, contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
ValueError: not enough values to unpack (expected 3, got 2)

Process finished with exit code 1

操作小记

import cv2

o = cv2.imread("money.png")
gray = cv2.cvtColor(o, cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
co = o.copy()
r = cv2.drawContours(co, contours, -1, (0, 0, 255), 1)
cv2.imshow("ori", o)
cv2.imshow("res", r)
cv2.waitKey()
cv2.destroyAllWindows()

效果
边缘/轮廓检测

Hough轮廓检测

Hough-直线检测

霍夫直线变换介绍

  • Hough Line Transform用来做直线检测
  • 前提条件:边缘检测已经完成
  • 平面空间到极坐标空间转换
    边缘/轮廓检测
  • 具体
    边缘/轮廓检测

操作小记

import cv2
import numpy as np


def line_detection(img):
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    edges = cv2.Canny(gray, 50, 150, apertureSize=3)
    lines = cv2.HoughLines(edges, 1, np.pi / 180, 200)
    for line in lines:
        rho, theta = line[0]
        a = np.cos(theta)
        b = np.sin(theta)
        x0 = a * rho
        y0 = b * rho
        x1 = int(x0 + 1000 * (-b))
        y1 = int(y0 + 1000 * a)
        x2 = int(x0 - 1000 * (-b))
        y2 = int(y0 - 1000 * a)
        cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 2)
    cv2.imshow("line_detection", img)


def line_detect_possible_demo(img):
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    edges = cv2.Canny(gray, 50, 150, apertureSize=3)
    lines = cv2.HoughLinesP(edges, 1, np.pi / 180, 100, minLineLength=50, maxLineGap=10)
    for line in lines:
        x1, y1, x2, y2 = line[0]
        cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 2)
    cv2.imshow("line_detect_possible_demo", img)


img = cv2.imread("Sudoku.png")
cv2.imshow("ori", img)
line_detection(img)
line_detect_possible_demo(img)
cv2.waitKey()

效果
边缘/轮廓检测

Hough-圆检测

霍夫圆检测原理

  • 从平面坐标到极坐标转换三个参数C(x0, y0, r)其中x0, y0是圆心
  • 假设平面坐标的任意一个圆上的点,转换到极坐标中:C(x0, y0, r) 处有最大值,霍夫变换正是利用这个原理实现圆检测
    边缘/轮廓检测

现实考量

  • 因为霍夫圆检测对噪声比较敏感,所以首先要对图像做中值滤波
  • 基于效率考虑,OpenCV中实现的霍夫变换圆检测是基于图像梯度的实现,分为两步:
    • 检测边缘,发现可能的圆心
    • 基于第一步的基础上从候选圆心开始计算最佳半径大小

操作小记

import cv2
import numpy as np


def detect_circles_demo(img):
    dst = cv2.pyrMeanShiftFiltering(img, 10, 100)
    cimg = cv2.cvtColor(dst, cv2.COLOR_BGR2GRAY)
    circles = cv2.HoughCircles(cimg, cv2.HOUGH_GRADIENT, 1, 20, param1=50, param2=30, minRadius=0, maxRadius=0)
    circles = np.uint16(np.around(circles))
    for i in circles[0, :]:
        cv2.circle(img, (i[0], i[1]), i[2], (0, 0, 255), 2)
        cv2.circle(img, (i[0], i[1]), 2, (255, 0, 0), 2)
    cv2.imshow("circles", img)


img = cv2.imread("money.png")
cv2.imshow("ori", img)
detect_circles_demo(img)
cv2.waitKey(0)
cv2.destroyAllWindows()

效果
边缘/轮廓检测
若采用dst = cv2.GaussianBlur(img, (23, 23), 0, 0)来过滤,效果会更好
边缘/轮廓检测

相关标签: 机器视觉