Python实现Canny及Hough算法代码实例解析


Posted in Python onAugust 06, 2020

任务说明:编写一个钱币定位系统,其不仅能够检测出输入图像中各个钱币的边缘,同时,还能给出各个钱币的圆心坐标与半径。

效果

Python实现Canny及Hough算法代码实例解析

代码实现

Canny边缘检测:

# Author: Ji Qiu (BUPT)
# filename: my_canny.py

import cv2
import numpy as np


class Canny:

  def __init__(self, Guassian_kernal_size, img, HT_high_threshold, HT_low_threshold):
    '''
    :param Guassian_kernal_size: 高斯滤波器尺寸
    :param img: 输入的图片,在算法过程中改变
    :param HT_high_threshold: 滞后阈值法中的高阈值
    :param HT_low_threshold: 滞后阈值法中的低阈值
    '''
    self.Guassian_kernal_size = Guassian_kernal_size
    self.img = img
    self.y, self.x = img.shape[0:2]
    self.angle = np.zeros([self.y, self.x])
    self.img_origin = None
    self.x_kernal = np.array([[-1, 1]])
    self.y_kernal = np.array([[-1], [1]])
    self.HT_high_threshold = HT_high_threshold
    self.HT_low_threshold = HT_low_threshold

  def Get_gradient_img(self):
    '''
    计算梯度图和梯度方向矩阵。
    :return: 生成的梯度图
    '''
    print ('Get_gradient_img')
    
    new_img_x = np.zeros([self.y, self.x], dtype=np.float)
    new_img_y = np.zeros([self.y, self.x], dtype=np.float)
    for i in range(0, self.x):
      for j in range(0, self.y):
        if j == 0:
          new_img_y[j][i] = 1
        else:
          new_img_y[j][i] = np.sum(np.array([[self.img[j - 1][i]], [self.img[j][i]]]) * self.y_kernal)
        if i == 0:
          new_img_x[j][i] = 1
        else:
          new_img_x[j][i] = np.sum(np.array([self.img[j][i - 1], self.img[j][i]]) * self.x_kernal)

    gradient_img, self.angle = cv2.cartToPolar(new_img_x, new_img_y)#返回幅值和相位
    self.angle = np.tan(self.angle)
    self.img = gradient_img.astype(np.uint8)
    return self.img

  def Non_maximum_suppression (self):
    '''
    对生成的梯度图进行非极大化抑制,将tan值的大小与正负结合,确定离散中梯度的方向。
    :return: 生成的非极大化抑制结果图
    '''
    print ('Non_maximum_suppression')
    
    result = np.zeros([self.y, self.x])
    for i in range(1, self.y - 1):
      for j in range(1, self.x - 1):
        if abs(self.img[i][j]) <= 4:
          result[i][j] = 0
          continue
        elif abs(self.angle[i][j]) > 1:
          gradient2 = self.img[i - 1][j]
          gradient4 = self.img[i + 1][j]
          # g1 g2
          #  C
          #  g4 g3
          if self.angle[i][j] > 0:
            gradient1 = self.img[i - 1][j - 1]
            gradient3 = self.img[i + 1][j + 1]
          #  g2 g1
          #  C
          # g3 g4
          else:
            gradient1 = self.img[i - 1][j + 1]
            gradient3 = self.img[i + 1][j - 1]
        else:
          gradient2 = self.img[i][j - 1]
          gradient4 = self.img[i][j + 1]
          # g1
          # g2 C g4
          #   g3
          if self.angle[i][j] > 0:
            gradient1 = self.img[i - 1][j - 1]
            gradient3 = self.img[i + 1][j + 1]
          #   g3
          # g2 C g4
          # g1
          else:
            gradient3 = self.img[i - 1][j + 1]
            gradient1 = self.img[i + 1][j - 1]

        temp1 = abs(self.angle[i][j]) * gradient1 + (1 - abs(self.angle[i][j])) * gradient2
        temp2 = abs(self.angle[i][j]) * gradient3 + (1 - abs(self.angle[i][j])) * gradient4
        if self.img[i][j] >= temp1 and self.img[i][j] >= temp2:
          result[i][j] = self.img[i][j]
        else:
          result[i][j] = 0
    self.img = result
    return self.img

  def Hysteresis_thresholding(self):
    '''
    对生成的非极大化抑制结果图进行滞后阈值法,用强边延伸弱边,这里的延伸方向为梯度的垂直方向,
    将比低阈值大比高阈值小的点置为高阈值大小,方向在离散点上的确定与非极大化抑制相似。
    :return: 滞后阈值法结果图
    '''
    print ('Hysteresis_thresholding')
    
    for i in range(1, self.y - 1):
      for j in range(1, self.x - 1):
        if self.img[i][j] >= self.HT_high_threshold:
          if abs(self.angle[i][j]) < 1:
            if self.img_origin[i - 1][j] > self.HT_low_threshold:
              self.img[i - 1][j] = self.HT_high_threshold
            if self.img_origin[i + 1][j] > self.HT_low_threshold:
              self.img[i + 1][j] = self.HT_high_threshold
            # g1 g2
            #  C
            #  g4 g3
            if self.angle[i][j] < 0:
              if self.img_origin[i - 1][j - 1] > self.HT_low_threshold:
                self.img[i - 1][j - 1] = self.HT_high_threshold
              if self.img_origin[i + 1][j + 1] > self.HT_low_threshold:
                self.img[i + 1][j + 1] = self.HT_high_threshold
            #  g2 g1
            #  C
            # g3 g4
            else:
              if self.img_origin[i - 1][j + 1] > self.HT_low_threshold:
                self.img[i - 1][j + 1] = self.HT_high_threshold
              if self.img_origin[i + 1][j - 1] > self.HT_low_threshold:
                self.img[i + 1][j - 1] = self.HT_high_threshold
          else:
            if self.img_origin[i][j - 1] > self.HT_low_threshold:
              self.img[i][j - 1] = self.HT_high_threshold
            if self.img_origin[i][j + 1] > self.HT_low_threshold:
              self.img[i][j + 1] = self.HT_high_threshold
            # g1
            # g2 C g4
            #   g3
            if self.angle[i][j] < 0:
              if self.img_origin[i - 1][j - 1] > self.HT_low_threshold:
                self.img[i - 1][j - 1] = self.HT_high_threshold
              if self.img_origin[i + 1][j + 1] > self.HT_low_threshold:
                self.img[i + 1][j + 1] = self.HT_high_threshold
            #   g3
            # g2 C g4
            # g1
            else:
              if self.img_origin[i - 1][j + 1] > self.HT_low_threshold:
                self.img[i + 1][j - 1] = self.HT_high_threshold
              if self.img_origin[i + 1][j - 1] > self.HT_low_threshold:
                self.img[i + 1][j - 1] = self.HT_high_threshold
    return self.img

  def canny_algorithm(self):
    '''
    按照顺序和步骤调用以上所有成员函数。
    :return: Canny 算法的结果
    '''
    self.img = cv2.GaussianBlur(self.img, (self.Guassian_kernal_size, self.Guassian_kernal_size), 0)
    self.Get_gradient_img()
    self.img_origin = self.img.copy()
    self.Non_maximum_suppression()
    self.Hysteresis_thresholding()
    return self.img

Hough变换

# Author: Ji Qiu (BUPT)
# filename: my_hough.py


import numpy as np
import math

class Hough_transform:
  def __init__(self, img, angle, step=5, threshold=135):
    '''

    :param img: 输入的图像
    :param angle: 输入的梯度方向矩阵
    :param step: Hough 变换步长大小
    :param threshold: 筛选单元的阈值
    '''
    self.img = img
    self.angle = angle
    self.y, self.x = img.shape[0:2]
    self.radius = math.ceil(math.sqrt(self.y**2 + self.x**2))
    self.step = step
    self.vote_matrix = np.zeros([math.ceil(self.y / self.step), math.ceil(self.x / self.step), math.ceil(self.radius / self.step)])
    self.threshold = threshold
    self.circles = []

  def Hough_transform_algorithm(self):
    '''
    按照 x,y,radius 建立三维空间,根据图片中边上的点沿梯度方向对空间中的所有单
    元进行投票。每个点投出来结果为一折线。
    :return: 投票矩阵
    '''
    print ('Hough_transform_algorithm')
    
    for i in range(1, self.y - 1):
      for j in range(1, self.x - 1):
        if self.img[i][j] > 0:
          y = i
          x = j
          r = 0
          while y < self.y and x < self.x and y >= 0 and x >= 0:
            self.vote_matrix[math.floor(y / self.step)][math.floor(x / self.step)][math.floor(r / self.step)] += 1
            y = y + self.step * self.angle[i][j]
            x = x + self.step
            r = r + math.sqrt((self.step * self.angle[i][j])**2 + self.step**2)
          y = i - self.step * self.angle[i][j]
          x = j - self.step
          r = math.sqrt((self.step * self.angle[i][j])**2 + self.step**2)
          while y < self.y and x < self.x and y >= 0 and x >= 0:
            self.vote_matrix[math.floor(y / self.step)][math.floor(x / self.step)][math.floor(r / self.step)] += 1
            y = y - self.step * self.angle[i][j]
            x = x - self.step
            r = r + math.sqrt((self.step * self.angle[i][j])**2 + self.step**2)

    return self.vote_matrix


  def Select_Circle(self):
    '''
    按照阈值从投票矩阵中筛选出合适的圆,并作极大化抑制,这里的非极大化抑制我采
    用的是邻近点结果取平均值的方法,而非单纯的取极大值。
    :return: None
    '''
    print ('Select_Circle')
    
    houxuanyuan = []
    for i in range(0, math.ceil(self.y / self.step)):
      for j in range(0, math.ceil(self.x / self.step)):
        for r in range(0, math.ceil(self.radius / self.step)):
          if self.vote_matrix[i][j][r] >= self.threshold:
            y = i * self.step + self.step / 2
            x = j * self.step + self.step / 2
            r = r * self.step + self.step / 2
            houxuanyuan.append((math.ceil(x), math.ceil(y), math.ceil(r)))
    if len(houxuanyuan) == 0:
      print("No Circle in this threshold.")
      return
    x, y, r = houxuanyuan[0]
    possible = []
    middle = []
    for circle in houxuanyuan:
      if abs(x - circle[0]) <= 20 and abs(y - circle[1]) <= 20:
        possible.append([circle[0], circle[1], circle[2]])
      else:
        result = np.array(possible).mean(axis=0)
        middle.append((result[0], result[1], result[2]))
        possible.clear()
        x, y, r = circle
        possible.append([x, y, r])
    result = np.array(possible).mean(axis=0)
    middle.append((result[0], result[1], result[2]))

    def takeFirst(elem):
      return elem[0]

    middle.sort(key=takeFirst)
    x, y, r = middle[0]
    possible = []
    for circle in middle:
      if abs(x - circle[0]) <= 20 and abs(y - circle[1]) <= 20:
        possible.append([circle[0], circle[1], circle[2]])
      else:
        result = np.array(possible).mean(axis=0)
        print("Circle core: (%f, %f) Radius: %f" % (result[0], result[1], result[2]))
        self.circles.append((result[0], result[1], result[2]))
        possible.clear()
        x, y, r = circle
        possible.append([x, y, r])
    result = np.array(possible).mean(axis=0)
    print("Circle core: (%f, %f) Radius: %f" % (result[0], result[1], result[2]))
    self.circles.append((result[0], result[1], result[2]))
 

  def Calculate(self):
    '''
    按照算法顺序调用以上成员函数
    :return: 圆形拟合结果图,圆的坐标及半径集合
    '''
    self.Hough_transform_algorithm()
    self.Select_Circle()
    return self.circles

调用

# Author: Ji Qiu (BUPT)
# filename: main.py

import cv2
import math
from my_hough import Hough_transform
from my_canny import Canny

# np.set_printoptions(threshold=np.inf)
Path = "picture_source/picture.jpg"
Save_Path = "picture_result/"
Reduced_ratio = 2
Guassian_kernal_size = 3
HT_high_threshold = 25
HT_low_threshold = 6
Hough_transform_step = 6
Hough_transform_threshold = 110

if __name__ == '__main__':
  img_gray = cv2.imread(Path, cv2.IMREAD_GRAYSCALE)
  img_RGB = cv2.imread(Path)
  y, x = img_gray.shape[0:2]
  img_gray = cv2.resize(img_gray, (int(x / Reduced_ratio), int(y / Reduced_ratio)))
  img_RGB = cv2.resize(img_RGB, (int(x / Reduced_ratio), int(y / Reduced_ratio)))
  # canny takes about 40 seconds
  print ('Canny ...')
  canny = Canny(Guassian_kernal_size, img_gray, HT_high_threshold, HT_low_threshold)
  canny.canny_algorithm()
  cv2.imwrite(Save_Path + "canny_result.jpg", canny.img)
  
  # hough takes about 30 seconds
  print ('Hough ...')
  Hough = Hough_transform(canny.img, canny.angle, Hough_transform_step, Hough_transform_threshold)
  circles = Hough.Calculate()
  for circle in circles:
    cv2.circle(img_RGB, (math.ceil(circle[0]), math.ceil(circle[1])), math.ceil(circle[2]), (28, 36, 237), 2)
  cv2.imwrite(Save_Path + "hough_result.jpg", img_RGB)
  print ('Finished!')

运行效果

Python实现Canny及Hough算法代码实例解析

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
wxpython 学习笔记 第一天
Mar 16 Python
解析Python中的异常处理
Apr 28 Python
Python cookbook(数据结构与算法)筛选及提取序列中元素的方法
Mar 19 Python
Windows上使用Python增加或删除权限的方法
Apr 24 Python
python3爬虫之设计签名小程序
Jun 19 Python
Python实现读取txt文件中的数据并绘制出图形操作示例
Feb 26 Python
浅谈python多进程共享变量Value的使用tips
Jul 16 Python
Windows下python3安装tkinter的问题及解决方法
Jan 06 Python
基于Python获取照片的GPS位置信息
Jan 20 Python
Python 实现日志同时输出到屏幕和文件
Feb 19 Python
Python编程快速上手——疯狂填词程序实现方法分析
Feb 29 Python
Pytorch可视化的几种实现方法
Jun 10 Python
vscode调试django项目的方法
Aug 06 #Python
Python如何使用input函数获取输入
Aug 06 #Python
Python map及filter函数使用方法解析
Aug 06 #Python
python学习笔记之多进程
Aug 06 #Python
Selenium alert 弹窗处理的示例代码
Aug 06 #Python
Python如何进行时间处理
Aug 06 #Python
Python学习笔记之装饰器
Aug 06 #Python
You might like
php文档更新介绍
2011/07/22 PHP
php 生成自动创建文件夹并上传文件的示例代码
2014/03/07 PHP
Linux系统下PHP-FPM的安装和配置教程
2015/08/17 PHP
PHP实现的限制IP投票程序IP来源分析
2016/05/04 PHP
Jquery中显示隐藏的实现代码分析
2011/07/26 Javascript
js+jquery实现图片裁剪功能
2015/01/02 Javascript
高效的jquery数字滚动特效
2015/12/17 Javascript
jQuery给元素添加样式的方法详解
2015/12/30 Javascript
jQuery基础_入门必看知识点
2016/07/04 Javascript
jQuery设置Easyui校验规则(推荐)
2016/11/21 Javascript
jQuery自定义插件详解及实例代码
2016/12/29 Javascript
AngularJS表单基本操作
2017/01/09 Javascript
Bootstrap缩略图的创建方法
2017/03/22 Javascript
javascript内存分配原理实例分析
2017/04/10 Javascript
利用JavaScript如何查询某个值是否数组内
2017/07/30 Javascript
vue vuex vue-rouert后台项目——权限路由(适合初学)
2017/12/29 Javascript
浅谈Vue-cli单文件组件引入less,sass,css样式的不同方法
2018/03/13 Javascript
jQuery each和js forEach用法比较
2019/02/27 jQuery
如何在Vue中抽离接口配置文件
2019/10/31 Javascript
使用纯前端JavaScript实现Excel导入导出方法过程详解
2020/08/07 Javascript
vue 如何从单页应用改造成多页应用
2020/10/23 Javascript
python实现探测socket和web服务示例
2014/03/28 Python
Python 列表list使用介绍
2014/11/30 Python
python解决Fedora解压zip时中文乱码的方法
2016/09/18 Python
目前最全的python的就业方向
2018/06/05 Python
python读取并定位excel数据坐标系详解
2019/06/26 Python
python 将日期戳(五位数时间)转换为标准时间
2019/07/11 Python
用Python+OpenCV对比图像质量的几种方法
2019/07/15 Python
自定义django admin model表单提交的例子
2019/08/23 Python
PyQt5+Pycharm安装和配置图文教程详解
2020/03/24 Python
乐天旅游香港网站:日本饭店预订
2017/11/29 全球购物
欧洲领先的电子和电信零售商和服务提供商:Currys PC World Business
2017/12/05 全球购物
医校毕业生自我鉴定
2014/01/25 职场文书
四风剖析查摆对照检查材料思想汇报
2014/09/24 职场文书
环卫处个人工作总结
2015/03/04 职场文书
结婚典礼致辞
2015/07/28 职场文书