【python OpenCV3.3 图像处理教程】边缘保留滤波EFP、直方图均衡化、反向投影、轮廓发现、

【python OpenCV3.3 图像处理教程】边缘保留滤波EFP、直方图均衡化、反向投影、轮廓发现、,第1张

1. 边缘保留滤波EFP
  • 高斯双边滤波:cv.bilateralFilter
  • 均值迁移滤波:cv.pyrMeanShiftFiltering

来自这篇博客的定义:

高斯模糊: 基于权重,权重只考虑像素空间的分布,中间的权重大,边缘的权重小。没有考虑像素值之间的差异问题,没有考虑边缘。
边缘保留滤波: 像素之间的差异很大,说明是显著特征,如果直接平滑(滤波),显著特征会消失。像素之间差异大的地方通常是边缘,所以边缘保留滤波处理后的图片,在平滑(滤波)的情况下,依旧能够保留图像的边缘。

边缘保留滤波EFP:其实就是磨皮效果!!!保留边缘,像素差异小的地方进行模糊处理

import cv2 as cv
import numpy as np

def bi_demo(image):
    dst=cv.bilateralFilter(image,0,100,15)  #磨皮 高斯双边滤波
    cv.imshow('bi_demo',dst)
    
def shift_demo(image):  #磨皮
    dst=cv.pyrMeanShiftFiltering(image,0,100,100)  #均值迁移,类似油画
    cv.imshow('shift_demo',dst)

src=cv.imread('C:\Users\22852\Desktop\opencv\data\girl.jpg')
# cv.namedWindow("input image",cv.WINDOW_AUTOSIZE)
cv.imshow("input image:",src)
bi_demo(src)
shift_demo(src)

cv.waitKey(0)
cv.destroyAllWindows()

2.直方图均衡化、反向投影 2.1 直方图
  1. 直方图的 x 轴是灰度值( 0 到 255), y 轴是图片中具有同一个灰度值的点的数目
  2. 通过直方图可以对图像的对比度,亮度,灰度分布进行了解


对应直方图如下:

通过直方图可以看出图片整体过亮,对比度大,有四个波峰。
代码:

def plot_demo(image):
    plt.hist(image.ravel(),256,[0,256])
    plt.show()

图像对应三个通道的直方图:

代码:

def image_hist(image):
    color=('blue','green','red')
    for i ,color in enumerate(color):
        hist=cv.calcHist([image],[i],None,[256],[0,256])
        plt.plot(hist,color)
        plt.xlim([0,256])
    plt.show()
2.2 直方图均衡化
  1. 先转化为灰度图:cv.cvtColor
  2. 再对灰度图进行直方图均衡化:cv.equalizeHist

代码:

def equalHist_demo(image):#直方图均衡化
    gray=cv.cvtColor(image,cv.COLOR_BGR2GRAY)
    dst=cv.equalizeHist(gray)
    cv.imshow('equalHist_demo',dst)

2.3 局部自适应直方图均衡化

参考

equalizeHist这种全局的均衡化也会存在一些问题,由于整体亮度的提升,也会使得局部图像的细节变得模糊,因为我们需要进行分块的局部均衡化 *** 作

def claHe_demo(image):#局部自适应直方图均衡化
    gray=cv.cvtColor(image,cv.COLOR_BGR2GRAY)
    clache=cv.createCLAHE(clipLimit=3.0,tileGridSize=(8,8))
    dst=clache.apply(gray)
    cv.imshow('clahe_demo',dst)

左图为局部自适应直方图均衡化,右图为直方图均衡化:

2.4 直方图的相似性

cv.compareHist:

  • cv.HISTCMP_BHATTACHARYYA:巴氏距离
  • cv.HISTCMP_CORREL:相关性
  • cv.HISTCMP_CHISQR:卡方
  • cv.COMP_INTERSECT :相交系数

相关系数:值越大,相关度越高[0~1]
卡方系数:值越小,相关度越高[0~]
相交系数: 值越大,相关度越高[0~9.455319]
巴氏距离:值越小,相关度越高[0~1]

def create_rgb_hist(image):
    h,w,c = image.shape
    rgbHist=np.zeros([16*16*16,1],np.float32)
    bsize=256/16
    for row in range(h):
        for col in range(w):
            b=image[row,col,0]
            g=image[row,col,1]
            r=image[row,col,2]
            index=int(b/bsize+16+16+g/bsize+16+r/bsize)
            rgbHist[index,0]=rgbHist[index,0]+1
        return rgbHist

def hist_compare(image1,image2):  #比较
    hist1=create_rgb_hist(image1)
    hist2=create_rgb_hist(image2)
    match1=cv.compareHist(hist1,hist2,cv.HISTCMP_BHATTACHARYYA)
    match2=cv.compareHist(hist1,hist2,cv.HISTCMP_CORREL)
    match3 = cv.compareHist(hist1, hist2, cv.HISTCMP_CHISQR)
    print("巴氏距离: %s,相关性: %s,卡方: %s"%(match1,match2,match3))

巴氏距离: 0.9134011518713788,相关性: 0.06669171290986387,卡方: 468.4549783549784

以上为自己写的直方图,也可以直接用API计算的直方图进行比较和计算
2.5 直方图反向投影

实际上是原图像的256个灰度值(0~255)划分为对应几个区间,反向投影矩阵中某点的值就是它对应的原图像中的点所在区间的灰度直方图值。
所以,一个区间点越多,在反向投影矩阵中就越亮。
如果两幅图的反向投影矩阵相似或相同,那么我们就可以判定这两幅图这个特征是相同的。
参考

输入图片1:

输出:


代码:

def hist2d_demo(image):
    hsv=cv.cvtColor(image,cv.COLOR_BGR2HSV)
    hist=cv.calcHist([hsv],[0,1],None,[180,256],[0,180,0,256])
    cv.imshow("hist2d",hist)
    plt.imshow(hist,interpolation='nearest')
    plt.title('2D Histogram')
    plt.show()

cv.calcBackProject:

反向投影可以用来做图像分割, 或者在图像中找寻我们感兴趣的部分。 它会输出与输入图像(待搜索)同样大小的图像,
其中的每一个像素值代表了输入图像上对应点属于目标对象的概率。
输出图像中像素值越高(越白)的点就越可能代表我们要搜索的目标(在输入图像所在的位置)。 直方图投影经常与camshift 算法等一起使用。
步骤:

  1. 为一张包含我们要查找目标的图像创建直方图, 我们要查找的对象要尽量占满这张图像。 最好使用颜色直方图,因为一个物体的颜色要比它的灰度能更好的被用来进行图像分割与对象识别。
  2. 再把这个颜色直方图投影到输入图像中寻找我们的目标, 也就是找到输入图像中的每一个像素点的像素值在直方图中对应的概率,这样我们就得到一个概率图像。
  3. 设置适当的阈值对概率图像进行二值化
    参考


代码:

def back_project_demo(sample,target):
    roi_hsv = cv.cvtColor(sample, cv.COLOR_BGR2HSV)
    target_hsv = cv.cvtColor(target, cv.COLOR_BGR2HSV)

    roiHist = cv.calcHist([roi_hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])

    # 归一化: 原始图像,结果图像,映射到结果图像中的最小值,最大值,归一化类型
    # cv.NORM_MINMAX对数组的所有值进行转化,使它们线性映射到最小值和最大值之间
    # 归一化后的图像便于显示, 归一化后到0~255之间
    cv.normalize(roiHist, roiHist, 0, 255, cv.NORM_MINMAX)
    # images, channels, hist, ranges, scale,
    dst = cv.calcBackProject([target_hsv], [0, 1], roiHist, [0, 180, 0, 256], 1)
    cv.imshow("backProjectionDemo", dst)
3.轮廓发现 3.1 方法1
  1. 高斯模糊,去噪
  2. 转化为灰度图
  3. 转化为二值化图
  4. findContours:
    1. cv.RETR_LIST发现所有形状
    2. cv.RETR_EXTERNAL只发现边缘
  5. cv.drawContours

代码

def countours_demo(image):
    dst=cv.GaussianBlur(image,(3,3),0)#高斯滤波
    # img=cv.cvtColor(image,cv.COLOR_BGR2GRAY)
    img=cv.cvtColor(dst,cv.COLOR_BGR2GRAY)
    ret,binary=cv.threshold(img,0,255,cv.THRESH_BINARY|cv.THRESH_OTSU)
    cv.imshow("binary:",binary)
    # binary=edge_demo(binary)
    img, contours, hierarchy=cv.findContours(binary,cv.RETR_LIST,cv.CHAIN_APPROX_SIMPLE)#cv.RETR_LIST发现所有形状
    # contours, hierarchy=cv.findContours(binary,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE)#cv.RETR_EXTERNAL只发现边缘
    for i,contour in enumerate(contours):
        # cv.drawContours(image,contours,i,[0,0,255])
        # cv.drawContours(image,contours,i,[0,0,255],-1)#填充
        cv.drawContours(image,contours,i,[0,0,255],2)#填充
        print(i)
    cv.imshow("circles:",image)

cv.RETR_LIST发现所有形状,线宽2

cv.RETR_EXTERNAL只发现边缘,线宽2


cv.RETR_LIST发现所有形状,线宽2,cv.drawContours:-1填充

3.2 方法2
  1. 去噪
  2. 进行candy边缘提取
    下图分别是对灰度图、原图、梯度图进行的Canny边缘提取,对灰度图和梯度图进行边缘提取效果由于原图。
def edge_demo(image):
    blurred=cv.GaussianBlur(image,(3,3),0)#高斯滤波
    #sigmaX Gaussian kernel standard deviation in X direction.
    gray=cv.cvtColor(blurred,cv.COLOR_BGR2GRAY)
    xgrad=cv.Sobel(gray,cv.CV_16SC1,1,0)
    ygrad=cv.Sobel(gray,cv.CV_16SC1,0,1)
    dst1=cv.Canny(xgrad,ygrad,50,150)
    dst2=cv.Canny(image,50,150)
    dst3=cv.Canny(gray,50,150)
    cv.imshow("Candy Edge_xygrad:",dst1)
    cv.imshow("Candy Edge_image:",dst2)
    cv.imshow("Candy Edge_gray:",dst3)
    return dst1


def countours_demo(image):
    dst=cv.GaussianBlur(image,(3,3),0)#高斯滤波
    # # img=cv.cvtColor(image,cv.COLOR_BGR2GRAY)
    # img=cv.cvtColor(dst,cv.COLOR_BGR2GRAY)
    # ret,binary=cv.threshold(img,0,255,cv.THRESH_BINARY|cv.THRESH_OTSU)
    # cv.imshow("binary:",binary)
    binary=edge_demo(dst)
    img, contours, hierarchy=cv.findContours(binary,cv.RETR_LIST,cv.CHAIN_APPROX_SIMPLE)#cv.RETR_LIST发现所有形状
    # img,contours, hierarchy=cv.findContours(binary,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE)#cv.RETR_EXTERNAL只发现边缘
    for i,contour in enumerate(contours):
        # cv.drawContours(image,contours,i,[0,0,255])
        # cv.drawContours(image,contours,i,[0,0,255],2)#2为线的宽度
        cv.drawContours(image,contours,i,[0,0,255],-1)#填充

        print(i)
    cv.imshow("circles:",image)

只发现边缘

发现所有形状

填充


效果自己多去试试就知道啦!不懂点进API里面有解释,不需要多说什么
最后,泫雅太美丽了

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/717034.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-25
下一篇 2022-04-25

发表评论

登录后才能评论

评论列表(0条)

保存