zoukankan      html  css  js  c++  java
  • opencv3计算机视觉+Python(四)

    使用分水岭和GrabCut算法进行物体分割

    用GrabCut算法进行图像分割

    在OpenCV中,实现了grabcut分割算法,该算法可以方便的分割出前景图像,操作简单,而且分割的效果很好。算法的原理参见papaer:“GrabCut” — Interactive Foreground Extraction using Iterated Graph Cuts

    比如下面的一副图,我们只要选定一个四边形框,把框中的图像作为grabcut的一个输入参数,表示该框中的像素可能属于前景,但框外的部分一定属于背景。

    GrabCut算法实现步骤为:

    1.在图片中定义含有(一个或多个)物体的矩形

    2.矩形外的区域被自动认为是背景

    3.对于用户定义的矩形区域,可用背景中的数据来区别它里面的前景和背景区域

    4.用高斯混合模型(GMM)来对背景和前景建模,并将未定义的像素标记为可能的前景或背景。

    5.图像中的每一个像素都被看作通过虚拟边与周围像素相连接,而每条边都有一个属于前景或背景的概率,这基于它与周围像素颜色上的相似性。

    6.每一个像素(即算法中的节点)会与一个前景或背景节点连接

    7.在节点完成连接后(可能与背景或前景连接),若节点之间的边属于不同终端(即一个节点属于前景,另一个节点属于背景),则会切断它们之间的边(这就是算法名中的切割部分),这就能将图像各部分分割出来。

    import numpy as np
    import cv2
    from matplotlib import pyplot as plt
    
    img=cv2.imread('1.jpg')
    mask=np.zeros(img.shape[:2],np.uint8)#创建一个掩模
    

    #创建以0填充的前景和背景模型
    bgdModel=np.zeros((1,65),np.float64)
    fgdModel=np.zeros((1,65),np.float64)
    
    rect=(100,160,400,670)#创建矩形
    cv2.grabCut(img,mask,rect,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_RECT)#使用了指定的空模型和掩模来运行GrabCut,并且实际上是用一个矩形来初始化这个操作
    #做完这些后,我们的掩模已经变成包含0~3之间的值。值为0和2的将转为0,值为1,3的将转为1.然后保存在mask2中。这样就可以用mask2过滤出所有的0值像素(理论上会完整保留所有前景像素)
    mask2=np.where((mask==0)|(mask==2),0,1).astype('uint8')
    img=img*mask2[:,:,np.newaxis]
    
    plt.subplot(121),plt.imshow(img)
    plt.title("grabcut"),plt.xticks([]),plt.yticks([])
    plt.subplot(122),plt.imshow(cv2.cvtColor(cv2.imread("1.jpg"),cv2.COLOR_BGR2RGB))
    plt.title("original"),plt.xticks([]),plt.yticks([])
    plt.show()


    使用分水岭算法进行图像分割

    把图像中的低密度的区域(变化很少)想象成山谷,图像中高密度的区域(变化很多)想象成山峰。开始向山谷中注入水直到不同的山谷中的水开始汇聚。为了阻止不同山谷的水汇聚,可以设置一些栅栏,最后得到的栅栏就是图像分割。

    import numpy as np
    import cv2
    from matplotlib import pyplot as plt
    img=cv2.imread("1.jpg")
    gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#颜色转为灰度
    ret,thresh=cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)#可为图像设一个阈值
    kernel=np.ones((3,3),np.uint8)
    opening=cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel,iterations=2)#去除噪声
    sure_bg=cv2.dilate(opening,kernel,iterations=3)
    
    dist_transform=cv2.distanceTransform(opening,cv2.DIST_L2,5)#可以通过distanceTransform来获取确定的前景区域。也就是说,这是图像中最可能是前景的区域,越是远离背景区域的边界点越可能属于前景,这里用了阈值来决定那些区域是前景
    ret,sure_fg=cv2.threshold(dist_transform,0.7*dist_transform.max(),255,0)
    #这个阶段之后,所得到的前景和背景中有重合的部分该怎么办?首先需要确定这些区域,这可从sure_bg与sure_fg的集合相减得到
    sure_fg=np.uint8(sure_fg)
    unknown=cv2.subtract(sure_bg,sure_fg)
    #现在有了这些区域,就可以设定栅栏来阻止水汇聚,这是通过connectedComponents函数完成。
    ret,markers=cv2.connectedComponents(sure_fg)
    
    markers=markers+1
    markers[unknown==255]=0
    #把栅栏绘制成红色
    markers=cv2.watershed(img,markers)
    img[markers==-1]=[255,0,0]
    plt.imshow(img)
    plt.show()
  • 相关阅读:
    函数
    A × B problem
    求n的阶乘
    自己构建一个vector函数
    int与string的互相转化
    列一列(斐波那契数列)
    找一找
    c++大数计算模板
    JSON--js中 json字符串转对象、对象转字符串
    JSON
  • 原文地址:https://www.cnblogs.com/yifdu25/p/8445471.html
Copyright © 2011-2022 走看看