使用Python中OpenCV和深度学习进行全面嵌套边缘检测

这篇博客将介绍如何使用OpenCV和深度学习应用全面嵌套的边缘检测。并将对图像和视频流应用全面嵌套边缘检测,然后将结果与OpenCV的标准Canny边缘检测器进行比较。

1. 效果图

愤怒的小鸟——原始图 VS Canny边缘检测图 VS HED边缘检测图

花朵——原始图 VS Canny边缘检测图 VS HED边缘检测图

视频效果图GIF 如下

2. 全面嵌套边缘检测与Canny边缘检测

2.1 Hed与Canny边缘检测对比

Holistically-Nested Edge Detection (HED) 全面嵌套边缘检测

Canny Edge Detection Canny边缘检测

OpenCV 利用Canny边缘检测能够找到图像中对象的边界。但是Canny边缘检测器存在一些问题,即:

  • 需要手动验证(将下部和上值设置为滞后阈值,是一种需要实验和视觉验证的手动过程);
  • 不具备通用性(对不同照明条件下捕获的相同图像,适用于一个图像,却不适用于另一个图像);
  • 通常需要许多预处理步骤(即转换为灰度,模糊/平滑等),以获得良好的边缘图。

整体嵌套边缘检测(HED)试图通过端到端深神经网络解决Canny边缘检测器的局限性。

该网络接受RGB图像作为输入,然后将边缘图作为输出产生。而且通过HED产生的边缘图在图像中很好的保留了对象边界。

2.2. 项目结构

2.3 deploy.prototxt, hed_pretrained_bsds.caffemodel下载

执行代码的关键是获取deploy.prototxt, hed_pretrained_bsds.caffemodel
https://github.com/opencv/opencv/blob/master/samples/dnn/edge_detection.py

https://github.com/seminar2012/hed

  • This sample shows how to define custom OpenCV deep learning layers in Python.
  • Holistically-Nested Edge Detection (https://arxiv.org/abs/1504.06375) neural network is used as an example model.
  • Find a pre-trained model at https://github.com/s9xie/hed. We provide the pretrained model and training/testing code for the edge detection framework Holistically-Nested Edge Detection (HED).
  • Please see the Arxiv or ICCV paper for technical details. The pretrained model (fusion-output) gives ODS=.790 and OIS=.808 result on BSDS benchmark dataset.
  • Download the pretrained model (56MB) from (http://vcl.ucsd.edu/hed/hed_pretrained_bsds.caffemodel) and place it in examples/hed/ folder.

3. 源码

3.1 对图像进行HED检测

# USAGE
# python detect_edges_image.py --edge-detector hed_model --image images/bird.jpg

# 导入必要的包
import argparse
import cv2
import os
import imutils

# 构建命令行参数及解析
# --edge-detector Holistically-Nested Edge Detection检测器模型路径
# --image 图片路径
ap = argparse.ArgumentParser()
ap.add_argument("-d", "--edge-detector", type=str, required=True,
                help="path to OpenCV's deep learning edge detector")
ap.add_argument("-i", "--image", type=str, required=True,
                help="path to input image")
args = vars(ap.parse_args())

class CropLayer(object):
    def __init__(self, params, blobs):
        # 初始化剪切区域开始和结束点的坐标
        self.xstart = 0
        self.ystart = 0
        self.xend = 0
        self.yend = 0

    # 计算输入图像的体积
    def getMemoryShapes(self, inputs):
        # 剪切类将接收俩个参数
        # 剪切第一个输入blob以匹配第二个blob,保持批次和通道数
        # 输出输入容积的形状及目标形状
        # 提取批量大小及通道数
        # 分别提取目标形状的高和宽
        (inputShape, targetShape) = (inputs[0], inputs[1])
        (batchSize, numChannels) = (inputShape[0], inputShape[1])
        (H, W) = (targetShape[2], targetShape[3])

        # 计算开始和结束剪切坐标的值
        self.xstart = int((inputShape[3] - targetShape[3]) // 2)
        self.ystart = int((inputShape[2] - targetShape[2]) // 2)
        self.xend = self.xstart + W
        self.yend = self.ystart + H

        # 返回体积,接下来进行实际裁剪
        return [[batchSize, numChannels, H, W]]

    def forward(self, inputs):
        return [inputs[0][:, :, self.ystart:self.yend, self.xstart:self.xend]]

# 从磁盘加载序列化的边缘检测器模型
print("[INFO] loading edge detector...")
protoPath = os.path.sep.join([args["edge_detector"],
                              "deploy.prototxt"])
modelPath = os.path.sep.join([args["edge_detector"],
                              "hed_pretrained_bsds.caffemodel"])
net = cv2.dnn.readNetFromCaffe(protoPath, modelPath)

# 绑定剪裁类到模型
cv2.dnn_registerLayer("Crop", CropLayer)

# 加载输入图像,获取其维度
image = cv2.imread(args["image"])
image = imutils.resize(image, width=400)
(H, W) = image.shape[:2]

# 转换图像为灰度图,高斯平滑,执行Canny边缘检测
print("[INFO] performing Canny edge detection...")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
canny = cv2.Canny(blurred, 30, 150)

# 根据输入图像为全面的嵌套边缘检测器(Holistically-Nested Edge Detector)构建一个输出blob
blob = cv2.dnn.blobFromImage(image, scalefactor=1.0, size=(W, H),
                             mean=(104.00698793, 116.66876762, 122.67891434),
                             swapRB=False, crop=False)

# # 设置blob作为网络的输入并执行算法以计算边缘图
print("[INFO] performing holistically-nested edge detection...")
net.setInput(blob)
hed = net.forward()
# 调整输出为原始图像尺寸的大小
hed = cv2.resize(hed[0, 0], (W, H))
# 将图像像素缩回到范围[0,255]并确保类型为“UINT8”
hed = (255 * hed).astype("uint8")

# 展示HED边缘检测的结果及Canny边缘检测的结果
cv2.imshow("Input", image)
cv2.imshow("Canny", canny)
cv2.imshow("HED", hed)
cv2.waitKey(0)

3.2 对视频进行HED检测

# USAGE 默认使用电脑自带的摄像头
# python detect_edges_video.py --edge-detector hed_model
# 使用视频文件流
# python detect_edges_video.py --edge-detector hed_model --input xl.mp4

# 导入必要的包
from imutils.video import VideoStream
import argparse
import imutils
import time  # 此模块允许放置睡眠命令以允许视频流建立和“热身”。
import cv2
import os

# 构建命令行参数及解析
# --edge-detector Holistically-Nested Edge Detection检测器模型路径
# --input 视频源:网络摄像头,视频文件或其他源。
ap = argparse.ArgumentParser()
ap.add_argument("-d", "--edge-detector", type=str, required=True,
                help="path to OpenCV's deep learning edge detector")
ap.add_argument("-i", "--input", type=str,
                help="path to optional input video (webcam will be used otherwise)")
args = vars(ap.parse_args())

class CropLayer(object):
    def __init__(self, params, blobs):
        # 初始化剪切区域开始和结束点的坐标
        self.xstart = 0
        self.ystart = 0
        self.xend = 0
        self.yend = 0

    # 计算输入图像的体积
    def getMemoryShapes(self, inputs):
        # 剪切类将接收俩个参数
        # 剪切第一个输入blob以匹配第二个blob,保持批次和通道数
        # 输出输入容积的形状及目标形状
        # 提取批量大小及通道数
        # 分别提取目标形状的高和宽
        (inputShape, targetShape) = (inputs[0], inputs[1])
        (batchSize, numChannels) = (inputShape[0], inputShape[1])
        (H, W) = (targetShape[2], targetShape[3])

        # 计算开始和结束剪切坐标的值
        self.xstart = int((inputShape[3] - targetShape[3]) // 2)
        self.ystart = int((inputShape[2] - targetShape[2]) // 2)
        self.xend = self.xstart + W
        self.yend = self.ystart + H

        # 返回体积,接下来进行实际裁剪
        return [[batchSize, numChannels, H, W]]

    def forward(self, inputs):
        # 使用派生(x,y)-oordinate来执行裁剪
        return [inputs[0][:, :, self.ystart:self.yend, self.xstart:self.xend]]

# 初始化视频流,脚本将动态选取使用视频文件流还是网络摄像头流
webcam = not args.get("input", False)

# 如果未提供视频文件路径,则使用电脑自带摄像头
if webcam:
    print("[INFO] starting video stream...")
    vs = VideoStream(src=0).start()
    time.sleep(2.0)
# 否则,获取视频文件流指针
else:
    print("[INFO] opening video file...")
    vs = cv2.VideoCapture(args["input"])

# 从磁盘加载序列化的HED检测器模型
print("[INFO] loading edge detector...")
protoPath = os.path.sep.join([args["edge_detector"],
                              "deploy.prototxt"])
modelPath = os.path.sep.join([args["edge_detector"],
                              "hed_pretrained_bsds.caffemodel"])
net = cv2.dnn.readNetFromCaffe(protoPath, modelPath)

# 将剪裁类注册到模型
cv2.dnn_registerLayer("Crop", CropLayer)

# 遍历视频流的帧
while True:
    # 获取每一帧,如果使用网络摄像头,获取下一帧
    frame = vs.read()
    frame = frame if webcam else frame[1]

    # 如果在处理视频文件流,没有获取到帧则代表已经到了文件尾部,则跳出循环
    if not webcam and frame is None:
        break

    # 等比例缩放帧为宽度500,并获取其维度
    frame = imutils.resize(frame, width=300)
    (H, W) = frame.shape[:2]

    # 转换灰度图,高斯模糊并执行Canny边缘检测
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    blurred = cv2.GaussianBlur(gray, (5, 5), 0)
    canny = cv2.Canny(blurred, 30, 150)

    # 为HED边缘检测器构建输入帧的blob,设置blob,并执行检测以计算边缘图
    blob = cv2.dnn.blobFromImage(frame, scalefactor=1.0, size=(W, H),
                                 mean=(104.00698793, 116.66876762, 122.67891434),
                                 swapRB=False, crop=False)
    net.setInput(blob)
    hed = net.forward()
    hed = cv2.resize(hed[0, 0], (W, H))
    hed = (255 * hed).astype("uint8")

    # 展示Canny、HED的检测结果
    cv2.imshow("Frame", frame)
    cv2.imshow("Canny", canny)
    cv2.imshow("HED", hed)
    key = cv2.waitKey(1) & 0xFF
    # 按下‘q'键表示退出循环
    if key == ord("q"):
        break

# 如果在使用网络摄像头流,则终止相机视频流
if webcam:
    vs.stop()
# 否则,释放视频文件流指针
else:
    vs.release()

# 关闭所有打开的window
cv2.destroyAllWindows()

参考

https://www.pyimagesearch.com/2019/03/04/holistically-nested-edge-detection-with-opencv-and-deep-learning/

到此这篇关于使用Python中OpenCV和深度学习进行全面嵌套边缘检测的文章就介绍到这了,更多相关OpenCV和深度学习全面嵌套边缘检测内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Python使用Opencv实现边缘检测以及轮廓检测的实现

    边缘检测 Canny边缘检测器是一种被广泛使用的算法,并被认为是边缘检测最优的算法,该方法使用了比高斯差分算法更复杂的技巧,如多向灰度梯度和滞后阈值化. Canny边缘检测器算法基本步骤: 平滑图像:通过使用合适的模糊半径执行高斯模糊来减少图像内的噪声. 计算图像的梯度:这里计算图像的梯度,并将梯度分类为垂直.水平和斜对角.这一步的输出用于在下一步中计算真正的边缘. 非最大值抑制:利用上一步计算出来的梯度方向,检测某一像素在梯度的正方向和负方向上是否是局部最大值,如果是,则抑制该像素(像素不属于

  • OpenCV 边缘检测

    边缘在人类视觉和计算机视觉中均起着重要的作用. 人类能够仅凭一张背景剪影或一个草图就识别出物体类型和姿态. 其中OpenCV提供了许多边缘检测滤波函数,这些滤波函数都会将非边缘区域转为黑色,将边缘区域转为白色或其他饱和的颜色. 不过这些滤波函数都很容易将噪声错误地识别为边缘,所以需要进行模糊处理. 本次的模糊操作使用高斯模糊(低通滤波器),最常用的模糊滤波器(平滑滤波器)之一,是一个削弱高频信号强度的低通滤波器. 低通滤波器,在像素与周围像素的亮度差值小于一个特定值时,平滑该像素的亮度,主要用于

  • OpenCV实现图像边缘检测

    最近自己在做一个有关图像处理的小项目,涉及到图像的边缘检测.直线检测.轮廓检测以及角点检测等,本文首先介绍图像的边缘检测,使用的是Canny边缘检测算法,具体代码以及检测效果如下: 1.代码部分: // Image_Canny.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <cv.h> #include "highgui.h" using namespace cv; int _tmain(int

  • OpenCV实现灰度、高斯模糊、边缘检测的示例

    一.彩色图像转灰度 Opencv提供了一个方法,可以使彩色图像变为灰度图像. 函数名:cvtColor(src,dest,way); src表示初始的mat对象: dest表示转换后的mat对象: way表示以何种方式转换. 举个例子: int main() { //定义路径 string path = "Resources//test.png"; //Mat:opencv引入的矩阵数据类型,处理所有图像 Mat img = imread(path); //创建一个新的mat对象,用来

  • python opencv实现图像边缘检测

    本文利用python opencv进行图像的边缘检测,一般要经过如下几个步骤: 1.去噪 如cv2.GaussianBlur()等函数: 2.计算图像梯度 图像梯度表达的是各个像素点之间,像素值大小的变化幅度大小,变化较大,则可以认为是出于边缘位置,最多可简化为如下形式: 3.非极大值抑制 在获得梯度的方向和大小之后,应该对整幅图像做一个扫描,去除那些非边界上的点.对每一个像素进行检查,看这个点的梯度是不是周围具有相同梯度方向的点中最大的.如下图所示: 4.滞后阈值 现在要确定那些边界才是真正的

  • 使用OpenCV-python3实现滑动条更新图像的Canny边缘检测功能

    import cv2 from matplotlib import pyplot as plt import numpy as np img= cv2.imread('39.jpg')#加载图片 cv2.namedWindow('Canny edge detect')#设置窗口,cv2.WINDOW_NORMAL表示窗口大小可自动调节 cv2.namedWindow('Original Image',cv2.WINDOW_NORMAL) cv2.namedWindow('Canny edgeIm

  • 使用Python中OpenCV和深度学习进行全面嵌套边缘检测

    这篇博客将介绍如何使用OpenCV和深度学习应用全面嵌套的边缘检测.并将对图像和视频流应用全面嵌套边缘检测,然后将结果与OpenCV的标准Canny边缘检测器进行比较. 1. 效果图 愤怒的小鸟--原始图 VS Canny边缘检测图 VS HED边缘检测图 花朵--原始图 VS Canny边缘检测图 VS HED边缘检测图 视频效果图GIF 如下 2. 全面嵌套边缘检测与Canny边缘检测 2.1 Hed与Canny边缘检测对比 Holistically-Nested Edge Detectio

  • python开启摄像头以及深度学习实现目标检测方法

    最近想做实时目标检测,需要用到python开启摄像头,我手上只有两个uvc免驱的摄像头,性能一般.利用python开启摄像头费了一番功夫,主要原因是我的摄像头都不能用cv2的VideCapture打开,这让我联想到原来opencv也打不开Android手机上的摄像头(后来采用QML的Camera模块实现的).看来opencv对于摄像头的兼容性仍然不是很完善. 我尝了几种办法:v4l2,v4l2_capture以及simpleCV,都打不开.最后采用pygame实现了摄像头的采集功能,这里直接给大

  • python中opencv图像叠加、图像融合、按位操作的具体实现

    目录 1图像叠加 2图像融合 3按位操作 1图像叠加 可以通过OpenCV函数cv.add()或简单地通过numpy操作添加两个图像,res = img1 + img2.两个图像应该具有相同的深度和类型,或者第二个图像可以是标量值. NOTE: OpenCV添加是饱和操作,也就是有上限值,而Numpy添加是模运算. 添加两个图像时, OpenCV功能将提供更好的结果.所以总是更好地坚持OpenCV功能. 代码: import cv2 import numpy as np x = np.uint8

  • python中opencv K均值聚类的实现示例

    目录 K均值聚类 K均值聚类的基本步骤 K均值聚类模块 简单例子 K均值聚类 预测的是一个离散值时,做的工作就是“分类”. 预测的是一个连续值时,做的工作就是“回归”. 机器学习模型还可以将训练集中的数据划分为若干个组,每个组被称为一个“簇(cluster)”.这种学习方式被称为“聚类(clusting)”,它的重要特点是在学习过程中不需要用标签对训练样本进行标注.也就是说,学习过程能够根据现有训练集自动完成分类(聚类). 根据训练数据是否有标签,可以将学习划分为监督学习和无监督学习. K近邻.

  • Python中字典和集合学习小结

    映射类型: 表示一个任意对象的集合,且可以通过另一个几乎是任意键值的集合进行索引 与序列不同,映射是无序的,通过键进行索引 任何不可变对象都可用作字典的键,如字符串.数字.元组等 包含可变对象的列表.字典和元组不能用作键 引用不存在的键会引发KeyError异常 1)字典 dict { } 空字典 { key1:value1,key2:value2,... } 字典在其它编程语言中又称作关联数组或散列表: 通过键实现元素存取:无序集合:可变类型容器,长度可变,异构,嵌套 支持的操作: len(D

  • python中关于数据类型的学习笔记

    数据类型是每种编程语言必备属性,只有给数据赋予明确的数据类型,计算机才能对数据进行处理运算,因此,正确使用数据类型是十分必要的,不同的语言,数据类型类似,但具体表示方法有所不同,以下是Python编程常用的数据类型: 1. 数字类型 Python数字类型主要包括int(整型).long(长整型)和float(浮点型),但是在Python3中就不再有long类型了. int(整型) 在32位机器上,整数的位数是32位,取值范围是-231~231-1,即-2147483648~214748364:在

  • python中asyncio异步编程学习

    1.   想学asyncio,得先了解协程 携程的意义: 计算型的操作,利用协程来回切换执行,没有任何意义,来回切换并保存状态 反倒会降低性能. IO型的操作,利用协程在IO等待时间就去切换执行其他任务,当IO操作结束后再自动回调,那么就会大大节省资源并提供性能,从而实现异步编程(不等待任务结束就可以去执行其他代码 2.协程和多线程之间的共同点和区别: 共同点: 都是并发操作,多线程同一时间点只能有一个线程在执行,协程同一时间点只能有一个任务在执行: 不同点: 多线程,是在I/O阻塞时通过切换线

  • python中opencv实现图片文本倾斜校正

    本项目为python项目需要安装python及python的opencv模块:opencv_python-4.0.1-cp37-cp37m-win32.whl 和 python的矩阵运算模块:numpy. 1.第一步,安装python3.7,具体安装步骤略. 2.第二步,使用pip安装python的矩阵运算模块:numpy. python -m pip install --user numpy scipy matplotlib ipython jupyter pandas sympy nose

  • Python中OpenCV实现简单车牌字符切割

    在Jupyter Notebook上使用Python+opencv实现如下简单车牌字符切割.关于opencv库的安装可以参考:Python下opencv库的安装过程与一些问题汇总. 1.实现代码 import cv2 import numpy as np import matplotlib.pyplot as plt from PIL import Image #读取原图片 image1=cv2.imread("123456.jpg") cv2.imshow("image1&

  • python中opencv实现文字分割的实践

    图片文字分割的时候,常用的方法有两种.一种是投影法,适用于排版工整,字间距行间距比较宽裕的图像:还有一种是用OpenCV的轮廓检测,适用于文字不规则排列的图像. 投影法 对文字图片作横向和纵向投影,即通过统计出每一行像素个数,和每一列像素个数,来分割文字. 分别在水平和垂直方向对预处理(二值化)的图像某一种像素进行统计,对于二值化图像非黑即白,我们通过对其中的白点或者黑点进行统计,根据统计结果就可以判断出每一行的上下边界以及每一列的左右边界,从而实现分割的目的. 算法步骤: 使用水平投影和垂直投

随机推荐