计算机视觉(四)

旧城等待, 2022-06-02 00:58 389阅读 0赞

Grabcut

Grabcut算法详解

http://blog.csdn.net/zouxy09/article/details/8534954

原理:
首先用矩形将要选择的前景区域选定,其中前景区域应该完全包含在矩形框当中。然后算法进行迭代式分割,知道达到效果最佳。但是有时分割结果不好,例如前景当成背景,背景当成前景。测试需要用户修改。用户只需要在非前景区域用鼠标划一下即可。

  1. 首先,输入矩形框,矩形框外部区域都是背景。内部一定包含前景。电脑对输入图像进行初始化,标记前景和背景的像素。使用高斯混合模型(GMM)对前景和背景建模。根据输入,GMM会学习并创建新的像素分布。对未知的像素(前景或背景不确定),根据他们与已知的分类像素关系进行分类。(类似聚类操作)这样会根据像素的分布创建一幅图,图中节点是像素。除了像素点是节点以外,还有Source\_nodeSink\_node两个节点。所有的前景图像斗鱼Source\_node相连。背景与Sink\_node相连。像素是否连接到Source\_node/end\_node依赖于权值,这个权值由像素属于同一类,也就是前景或者背景的概率来决定。如果像素的颜色有很大区别,那么他们之间的权重就很小。使用mincut算法对图像进行分割。它会根据最小代价方程对图像分成source\_nodesink\_node。代价方程是指裁剪所有边上权重的和。裁剪完成后,所有连接到source\_node的判定为前景,sink\_node上的为背景。继续此过程,直到分类收敛。
  2. def grabCut(img, mask, rect, bgdModel, fgdModel, iterCount, mode=None): # real signature unknown; restored from __doc__ """ grabCut(img, mask, rect, bgdModel, fgdModel, iterCount[, mode]) -> mask, bgdModel, fgdModel """ pass

cv2.grabCut()函数参数

  • img 输入图像,图像的类型必须为:CV_8UC3
  • mask 掩模图像,确定前景区域,背景区域,不确定区域,可以设置为cv2.GC_BGD,cv2.GC_FGD,cv2.GC_PR_BGD,cv2.GC_PR_FGD,也可以输入0,1,2,3它的大小和image一样,但是它的格式为CV_8UC1,只能是单通道的,grabcut算法的结果就保存在该图像中。

    mask图像的值只能为下面下面4个值(PR,probably表示可能的):计算完成后mask里面值为0到3,其中0表示背景,1表示前景,2表示可能是背景,3表示可能是前景 ,代码中将0和2合并为背景 1和3合并为前景

    GC_BGD = 0, //背景

    GC_FGD = 1, //前景
    GC_PR_BGD = 2, //可能背景

    GC_PR_FGD = 3 //可能前景
    代码中将0和2合并为背景 1和3合并为前景

  1. 根据rectangle生成的mask图像规则为:四边形外面的部分一定是背景,所以在mask图中对应的像素值为GC\_BGD,而四边形内部的的值可能为前景,所以对应的像素值为GC\_PR\_FGD
  • rect 前景的矩形,格式为(x,y,w,h),分别为左上角坐标和宽度,高度
  • bdgModel, fgdModel)**临时矩阵变量**,只需要创建两个大小为(1,65)np.float64的数组。 
  • bgdModel(background背景)——背景模型,如果为null,函数内部会自动创建一个bgdModel;bgdModel必须是单通道浮点型(CV_32FC1)图像,且行数只能为1,列数只能为13x5
    fgdModel(foreground前景——前景模型,如果为null,函数内部会自动创建一个fgdModel;fgdModel必须是单通道浮点型(CV_32FC1)图像,且行数只能为1,列数只能为13x5
  • iterCount 迭代次数,迭代越多,效果越好,但划时间也越长。
  • mode cv2.GC_INIT_WITH_RECT 或 cv2.GC_INIT_WITH_MASK,使用矩阵模式还是掩模模式。
  • mode——用于指示grabCut函数进行什么操作,可选的值有:
      GC_INIT_WITH_RECT(=0),用矩形窗初始化GrabCut;
      GC_INIT_WITH_MASK(=1),用掩码图像初始化GrabCut;
      GC_EVAL(=2),执行分割。
  • 参数为GC_INIT_WITH_MASK,这时第三个参数rectangle没有使用,我们必须在调用grabcut函数之前,手工设置mask图像

1、自定义(自设区域选定)

静态图像:

  1. import numpy as np
  2. from cv2 import *
  3. from matplotlib import pyplot as plt
  4. filename="D:/temp/6.jpg"
  5. img=imread(filename)
  6. mask=np.zeros(img.shape[:2],np.uint8)
  7. bgdmodel=np.zeros((1,65),np.float64)
  8. fgdmodel=np.zeros((1,65),np.float64)
  9. #img.shape[0],img.shape[1],表图像的高度和宽度
  10. rect=(2,2,img.shape[0]-1,img.shape[1]-1)
  11. grabCut(img,mask,rect,bgdmodel,fgdmodel,6,GC_INIT_WITH_RECT)
  12. mask2=np.where((mask==2)|(mask==0),0,1).astype('uint8')
  13. img=img*mask2[:,:,np.newaxis]
  14. plt.subplot(121),plt.imshow(img)
  15. plt.title('grabcut'),plt.xticks([]),plt.yticks([])
  16. plt.subplot(122),plt.imshow(cvtColor(imread(filename),COLOR_BGR2RGB))
  17. plt.title('original'),plt.xticks([]),plt.yticks([])
  18. plt.show()

C++代码参考:

http://blog.csdn.net/l1l2l3q1q2q3/article/details/51181975

http://blog.csdn.net/wangyaninglm/article/details/50074613

http://blog.csdn.net/zxc024000/article/details/51243629

http://blog.csdn.net/roslei/article/details/52221975

(Java)http://blog.csdn.net/huohuxingxing1987/article/details/13278375

摄像(动态):

  1. import numpy as np
  2. from cv2 import *
  3. from matplotlib import pyplot as plt
  4. videocapture=VideoCapture(0)
  5. ret,img=videocapture.read()
  6. while ret:
  7. image = img
  8. mask=np.zeros(img.shape[:2],np.uint8)
  9. bgdmodel=np.zeros((1,65),np.float64)
  10. fgdmodel=np.zeros((1,65),np.float64)
  11. rect=(1,1,image.shape[0],image.shape[1])
  12. grabCut(img,mask,rect,bgdmodel,fgdmodel,2,GC_INIT_WITH_RECT)
  13. mask2=np.where((mask==2)|(mask==0),0,1).astype('uint8')
  14. img=img*mask2[:,:,np.newaxis]
  15. imshow('Grabcut',img)
  16. imshow('Image',image)
  17. waitKey(1)
  18. ret, img = videocapture.read()
  19. destroyAllWindows()

运行非常慢。

2、交互模式

参考:http://blog.topspeedsnail.com/archives/2080

http://blog.csdn.net/tengfei461807914/article/details/62438959

鼠标画笔 setMouseCallback():http://blog.csdn.net/qton\_csdn/article/details/70193884

创建一个鼠标回调函数,在指定事件发生时执行。

使用如下代码查看鼠标事件:

  1. import cv2
  2. events=[i for i in dir(cv2)if 'EVENT' in i]
  3. print events

事件:[‘EVENT_FLAG_ALTKEY’, ‘EVENT_FLAG_CTRLKEY’, ‘EVENT_FLAG_LBUTTON’, ‘EVENT_FLAG_MBUTTON’, ‘EVENT_FLAG_RBUTTON’, ‘EVENT_FLAG_SHIFTKEY’, ‘EVENT_LBUTTONDBLCLK’, ‘EVENT_LBUTTONDOWN’, ‘EVENT_LBUTTONUP’, ‘EVENT_MBUTTONDBLCLK’, ‘EVENT_MBUTTONDOWN’, ‘EVENT_MBUTTONUP’, ‘EVENT_MOUSEHWHEEL’, ‘EVENT_MOUSEMOVE’, ‘EVENT_MOUSEWHEEL’, ‘EVENT_RBUTTONDBLCLK’, ‘EVENT_RBUTTONDOWN’, ‘EVENT_RBUTTONUP’]
C++参考:http://blog.csdn.net/my\_lord\_/article/details/53927865

python:待续

发表评论

表情:
评论列表 (有 0 条评论,389人围观)

还没有评论,来说两句吧...

相关阅读

    相关 计算机视觉(三)

    1、滤波器 傅里叶变换主要作用反应图像各区域像素变化的幅度。 滤波器(核)矩阵:一组权重集合(内部所有值加和为0),作用在源图像的一个区域(滑动),并由此生成目标图像的一个

    相关 计算机视觉(二)

    1、捕获摄像头的帧   VideoCapture类可以获得摄像头的帧流。但对摄像头而言,通常不是用视频的文件名来构造VideoCapture类,而是需要传递摄像头的设备索引(