边缘/轮廓检测

边缘/轮廓检测

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)来过滤,效果会更好
在这里插入图片描述

发布了138 篇原创文章 · 获赞 68 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_40626497/article/details/105219498