OpenCV之角点检测和边缘检测的方法总结

OpenCV之角点检测和边缘检测的方法总结

OpenCV之角点检测和边缘检测的方法总结

一. 膨胀和腐蚀的粗略理解

因为膨胀和腐蚀都属于形态学滤波范畴,所以必须先有一个结构体元素。结构体元素就是滤波器矩阵,其有多种类型,包括x形、矩形、十字交叉形、菱形等。其中cv2有默认getStructingElement()方法获取矩形和十字交叉形的结构体元素,当然也可以通过numpy库中的numpy.array()自定义,下面通过一个代码例子列举:

A. cv2内部方法默认分别获取 矩形滤波器,十字交叉形滤波器:

其中 第一个参数是类型第二个参数是内核大小ksize,即滤波器大小,最好为奇数(3,5,7)

kernel_rect=cv2.getStructuringElement( cv2.MORPH_RECT , (5,5) ),

kernel_cross=cv2.getStructuringElement(cv2.MORPH_CROSS,(5,5))

B. numpy.array()自定义

x形滤波器结构体元素

kernel_x=np.array([[1,0,0,0,1],[0,1,0,1,0],[0,0,1,0,0],[0,1,0,1,0],[1,0,0,0,1]],dtype=np.uint8)

菱形滤波器结构体元素

kernel_diamond = np.array([[0,0,1,0,0],[0,1,1,1,0],[1,1,1,1,1],[0,1,1,1,0],[0,0,1,0,0]],dtype=np.uint8)

在获取完结构体元素后,就进行膨胀或者腐蚀操作,所谓 膨胀就是把上面获得的结构体元素与原图像的灰度图逐个遍历, 获取该区域内的最大值。所以膨胀过后的效果图是, 原本图中的亮的区域更多,暗的区域变少,有利于背景的提取。如果连续多次膨胀,最终会得到原图大小的全为255像素的全白图片。而 腐蚀就是膨胀的非操作, 获取的是区域内的最小值 ,原本图中的暗的区域更多,亮的区域变少,有利于前景的提取。如果连续多次膨胀,最终会得到原图大小的全为0像素的黑色图片,下面利用一张二值图来演示一下:

原图:

OpenCV之角点检测和边缘检测的方法总结

膨胀后:

OpenCV之角点检测和边缘检测的方法总结

连续膨胀后:

OpenCV之角点检测和边缘检测的方法总结

腐蚀:

OpenCV之角点检测和边缘检测的方法总结

连续腐蚀:

OpenCV之角点检测和边缘检测的方法总结

把腐蚀和膨胀这个功能用函数封装起来:

注释:way变量表示结构体类型,为了把获取结构体元素两种方法结合起来, 设置了flag变量,1表示用CV2默认的获取结构体元素的方法(分别可以获取矩形、交叉形),0表示自定义内核类型及大小

def dilate(image,way,flag):
    #获取结构体元素 1.直接获取getStructurinElement
    if(flag):
        kernel=cv2.getStructuringElement(way,(5,5))
        #膨胀
        result=cv2.dilate(image,kernel)
    #膨胀
    else:
        result=cv2.dilate(image,way)
    return result
def erode(image,way,flag):
    if(flag):
        kernel=cv2.getStructuringElement(way,(5,5))
        #腐蚀
        result=cv2.erode(image,kernel)
    #腐蚀
    else:
        result=cv2.erode(image,way)
    return result

src=cv2.imread('building.jpg')
src=cv2.cvtColor(src,cv2.COLOR_BGR2GRAY)
#自定义形态学滤波器的核大小 利用np.array
#x形滤波器结构体元素
kernel_x=np.array([[1,0,0,0,1],[0,1,0,1,0],[0,0,1,0,0],[0,1,0,1,0],[1,0,0,0,1]],dtype=np.uint8)
#菱形滤波器结构体元素
kernel_diamond = np.array([[0,0,1,0,0],[0,1,1,1,0],[1,1,1,1,1],[0,1,1,1,0],[0,0,1,0,0]],dtype=np.uint8)
#十字膨胀后菱形腐蚀
src1=dilate(src,cv2.MORPH_CROSS,1)
src1=erode(src1,kernel_diamond,0)
cv2.imshow('result',src1)
cv2.waitKey(-1)

二. 膨胀和腐蚀的变换,查找角点并绘制

总体思路,十字膨胀结果后菱形腐蚀得出结果src1,同时在原图上进行x形膨胀结果后进行矩形腐蚀得出结果src2。两者的差值就是所求的角点。

Why? 粗略理解:十字膨胀角点只是在水平和竖直方向上扩展,但边没变,菱形腐蚀后,角点在135度或者45度角上的角点都有收缩,但是边没变。x形膨胀,角点和边都在像x形方向扩展,到矩形腐蚀是各个方向都有收缩,所以这之后的结果是角点还原,边腐蚀的更厉害。两者相减的差值,就是角点。(因为边腐蚀的厉害,相减后,就相当于膨胀了一点点,使得最终边也没有变)

把用形态学查找角点并且绘制找好的角点这个功能用函数封装起来(代码实现):

注释: step1.实现膨胀和腐蚀的函数上面已定义

step2.decrse()是返回两者的差值,即找到的是角点的结果变量result,但有时候找到的角点并不是所有都符合预期,所以需要认为的进行阈值化,通过切片的方式,把result中大于35的像素值全部赋值给255,小于等于35全部赋值为0。

step3.在原图上绘制已经找到的角点,用cv2.cirle()画园,可以设定那些显示,本文设置在找到的result中大于120的像素点才会被显示出来, 特别地,画园时的(x,y)要反过来,result中的坐标存储为(i,j),但画园时要变为(j,i)

至于开运算和闭运算会在下面讲解,不要急

 def decrse(src1,src2):
    return src1.astype(np.int32)-src2.astype(np.int32)
def Print_corr(src,diff):
    kernel=np.ones((5,5),dtype=np.uint8)
    src=cv2.morphologyEx(src,cv2.MORPH_CLOSE,kernel)#闭运算,先膨胀后腐蚀,填补膨胀后的比较暗的部分
                                                    #最终使图像中暗色部分区域更加暗,并且该区域比较平滑
    cv2.imshow('CLOSE',src)
    cv2.waitKey(100)
    for i in range(diff.shape[0]):
        for j in range(diff.shape[1]):
            if diff[i,j]>100:
                img=cv2.circle(src,(j,i),5,255)
    return img
#十字膨胀后菱形腐蚀
src1=dilate(src,cv2.MORPH_CROSS,1)
src1=erode(src1,kernel_diamond,0)
#x形膨胀后矩形腐蚀
src2=dilate(img_ori,kernel_x,0)
src2=erode(src2,cv2.MORPH_RECT,1)
result=decrse(src1,src2)
result[result>=35]=255
result[result<35]=0 result_draw="Print_corr(src,result)" cv2.imwrite('dilate_erode.jpg',result_draw) src="result_draw" cv2.imshow('result',src) cv2.waitkey(-1)< code></35]=0>

效果图如下:

OpenCV之角点检测和边缘检测的方法总结

三、开运算、闭运算、顶帽、底帽

3.1 开运算

开运算就是先腐蚀后膨胀,先腐蚀后得到的效果是原图中本来比较黑的部分就会凸显出更暗,但暗的部分也会有不怎么暗的部分(相对于来讲),然后再膨胀,对于这个并不怎么黑的部分来讲,其膨胀就会显得不那么夸张,并且其扩展的周围图像都是比较平滑的,可以很好的去噪声。可以先感受一下效果:

OpenCV之角点检测和边缘检测的方法总结

注释:左边是原图的灰度图,右边是开运算过后的结果,就拿围栏来说,本来就黑,腐蚀过后更黑了,然后图中的红色圈不怎么黑,甚至偏白,但在膨胀时并没有变形的很厉害,反而这部分区域还更加平滑,所以从侧面说明,开运算有良好的去噪效果。

3.2 闭运算

闭运算就是先膨胀后腐蚀,先膨胀后得到的效果是原图中本来比较亮的部分就会凸显出更亮,但亮的部分也会有不怎么亮的部分(相对于来讲),然后再腐蚀,对于这个并不怎么亮的部分来讲,其腐蚀就会收缩这部分,填补这部分比较亮的细缝,使得前景更好的提取。(类似于美图秀秀的P图遮豆,人像就是前景。

记住闭运算类似于祛痘,填补空洞,最后实现就要腐蚀。就不会记混开闭运算谁先腐蚀谁先膨胀,之后又如何判断是开还是闭运算。

效果图如下:

OpenCV之角点检测和边缘检测的方法总结

注释:左边是原图的灰度图,右边是闭运算过后的结果,就拿图中圆圈1来说,本来就白,膨胀过后更白了,然后图中的红色圈2不怎么白,甚至偏黑,但在腐蚀时并没有收缩的很厉害,反而这部分区域被填补,所以从侧面说明,闭运算有良好的填补细小缝隙效果。

3.3 顶帽,底帽

顶帽=原图-开运算,简单来说就是提取比原图中更亮的区域。

底帽=原图-闭运算,简单来说就是提取比原图中更暗的区域。

代码实现:1.获取结构体元素

2.直接调用cv2的tophat,blackhat

import cv2
import numpy as np
kernel=np.ones((3,3),dtype=np.uint8)
img=cv2.imread('building.jpg')
img=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
black_hat=cv2.morphologyEx(img,cv2.MORPH_BLACKHAT,kernel)
top_hat=cv2.morphologyEx(img,cv2.MORPH_TOPHAT,kernel)
cv2.imshow('black_hat',black_hat)
cv2.imshow('top_hat',top_hat)
key=cv2.waitKey()
cv2.destroyAllWindows()

效果图如下:

OpenCV之角点检测和边缘检测的方法总结

OpenCV之角点检测和边缘检测的方法总结

四、Harris检测并绘制角点

4.1 原理

一个固定窗口在图像上进行任意方向上滑动,滑动前compare滑动后,窗口中灰度值变化,变化大的,则该窗口存在角点

4.2 代码实现

step1.获取结构体元素

step2.调用cornerHarris()方法探测角点

step3. 探测角点归一化 cv2.normalize(相当于阈值化结果)

step4.在原图中绘制角点(画圆)

def harris_checkPoint(image):
    #image=cv2.cvtColor(image,cv2.COLOR_GRAY2BGR)
    blocksize=2
    apertureSize=3
    k=0.04
    kernel=np.ones((5,5),dtype=np.uint8)
    image=cv2.morphologyEx(src,cv2.MORPH_OPEN,kernel)#&#x5F00;&#x8FD0;&#x7B97; &#x5148;&#x8150;&#x8680;&#x540E;&#x81A8;&#x80C0;&#xFF0C;&#x53BB;&#x9664;&#x566A;&#x58F0;
                                                    #&#x6548;&#x679C;&#x56FE;&#x662F;&#x80CC;&#x666F;&#x56FE;&#x7684;&#x90E8;&#x5206;&#x533A;&#x57DF;&#x66F4;&#x4EAE;&#xFF0C;&#x5E76;&#x4E14;&#x8BE5;&#x533A;&#x57DF;&#x6BD4;&#x8F83;&#x5E73;&#x6ED1;
    cv2.imshow('OPEN',image)
    cv2.waitKey(100)
    #gray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
    dst=cv2.cornerHarris(image,blocksize,apertureSize,k)
    dst_norm=np.empty(dst.shape,dtype=np.float32)
    #&#x7ED3;&#x679C;&#x5F52;&#x4E00;&#x5316;
    cv2.normalize(dst,dst_norm,alpha=0,beta=255,norm_type=cv2.NORM_MINMAX)
    #&#x7ED8;&#x5236;&#x7ED3;&#x679C;
    for i in range(dst_norm.shape[0]):
        for j in range(dst_norm.shape[1]):
            if int(dst_norm[i,j])>120:
                cv2.circle(image,(j,i),2,(255,255,255),2)
    return image

效果如图:

OpenCV之角点检测和边缘检测的方法总结

今天先到这里了,本次内容有点多,主要是理解腐蚀和膨胀的应用。如果不想理解概念,可直接跳过本章进入下一章,下一章内容会直接附上完整代码,方便运行看结果。关于今天的总结和边缘检测,也请关注我的下一章内容。码字不易,请多多一键三连666,哈哈哈哈!!!

Original: https://blog.csdn.net/m0_57724611/article/details/121439783
Author: Never Leung
Title: OpenCV之角点检测和边缘检测的方法总结

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/762083/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球