【笔记】OpenCV3 图像分割-用grabCut做前景检测

grabCut算法的大致思路,摘抄。。。。


  1. 在图片中定义(一个或者多个)包含物体的矩形。
  2. 矩形外的区域被自动认为是背景。
  3. 对于用户定义的矩形区域,可用背景中的数据来区分它里面的前景和背景区域。
  4. 用高斯混合模型(GMM)来对背景和前景建模,并将未定义的像素标记为可能的前景或者背景。
  5. 图像中的每一个像素都被看做通过虚拟边与周围像素相连接,而每条边都有一个属于前景或者背景的概率,这是基于它与周边像素颜色上的相似性。
  6. 每一个像素(即算法中的节点)会与一个前景或背景节点连接。
  7. 在节点完成连接后(可能与背景或前景连接),若节点之间的边属于不同终端(即一个节点属于前景,另一个节点属于背景),则会切断他们之间的边,这就能将图像各部分分割出来
def grabCut(img, mask, rect, bgdModel, fgdModel, iterCount, mode=None)

输入参数:

img: 输入图像

mask: 掩码图像,用来确定哪些区域是背景、前景,哪些可能是前景/背景

0 GC_BGD    定义了明显的背景像素。     
1 GC_FGD    定义了一个明显的前景(对象)像素。 
2 GC_PR_BGD 定义了可能的背景像素。
3 GC_PR_FGD 定义了可能的前景像素。

rect: mode为rect模式时有效 包含前景的矩形(x,y,w,h),以外的部分为背景

bgdModel、fgdModel:背景、前景数组,算法用

itterCount: 算法迭代的次数

mode: cv2.GC_INIT_WITH_RECT,cv2.GC_INIT_WITH_MASK两种模式

 

测试下试试,在代码中加入了鼠标事件,来获取在图形绘制的rect,用来给算法限定前景的范围

  1. 鼠标按下时,设置绘制边框模式setrect_flag为True,且记录下点击的点
  2. 鼠标左键按下,并拖动时,记录鼠标点坐标,用于在移动时绘制矩形框
  3. 鼠标左键松开时,记录下坐标点,完成矩形框绘制
file_name = 'img/renma.jpg'
setrect_flag = False
has_rect = False
set_rect = [1,1,1,1]
cut_flag = False

def onMouse(event,x,y,flags, param):
    global setrect_flag,has_rect,set_rect,cut_flag
    if event == cv2.EVENT_LBUTTONDOWN:
        print("left mouse click...")
        setrect_flag = True
        has_rect = False
        set_rect[0] = x
        set_rect[1] = y
        set_rect[2] = x
        set_rect[3] = y
    if event ==  cv2.EVENT_MOUSEMOVE and flags == cv2.EVENT_FLAG_LBUTTON:
        if setrect_flag:
            set_rect[2] = x
            set_rect[3] = y
    elif event == cv2.EVENT_LBUTTONUP:
        print("left mouse up...")
        if setrect_flag:
            setrect_flag = False
            has_rect = True
            cut_flag = True
            set_rect[2] = x
            set_rect[3] = y
        print(x,y)
    elif event == cv2.EVENT_RBUTTONDOWN:
        print("right mouse down...")
        has_rect = False
        setrect_flag = False

 

  1. 在main处绘制出原图,并记录
  2. 循环判断,当为绘制矩形框模式时,绘制出矩形框
  3. cut_flag 用来判断是否已经完成剪切,如果已完成,就不用处理,不然会一直处理。。。
  4. 在里面判断鼠标按下与松开的位置,来确定最终的前景确认框的rect ,左上角坐标,及宽高
if __name__ == "__main__":

    cv2.namedWindow('pic', cv2.WINDOW_AUTOSIZE)
    cv2.setMouseCallback('pic', onMouse)

    img = cv2.imread(file_name, cv2.IMREAD_COLOR)
    imgold = img.copy()
    cv2.imshow('pic', img)

    while True:
        # 画区域中
        if setrect_flag:
            img = imgold.copy()
            cv2.rectangle(img,(set_rect[0],set_rect[1]),(set_rect[2],set_rect[3]),(255,0,0),1)
            cv2.imshow('pic',img)
        else:
            if cut_flag:
                if has_rect and (set_rect[0] - set_rect[2]) != 0 and (set_rect[1] - set_rect[3]) != 0:
                    # 默认往右下拖动
                    rect = [set_rect[0],set_rect[1],abs(set_rect[2]-set_rect[0]),abs(set_rect[3]-set_rect[1])]
                    if set_rect[2] < set_rect[0] and set_rect[3] < set_rect[1]:#往左上拖动
                        rect[0] = set_rect[2]
                        rect[1] = set_rect[3]
                    elif set_rect[2] < set_rect[0] and set_rect[3] > set_rect[1]:#往左下拖动
                        rect[0] = set_rect[2]
                        rect[1] = set_rect[1]
                    elif set_rect[2] > set_rect[0] and set_rect[3] < set_rect[1]:#往右上拖动
                        rect[0] = set_rect[0]
                        rect[1] = set_rect[3]
                    img = imgold.copy()
                    st = time.time()
                    print('begin cut pic...')
                    cuppic(img,rect)
                    print("cut over , it takes {:.3f}".format(time.time()-st))
                    cut_flag = False
                else:
                    cv2.imshow('pic', imgold)

        pressKey = cv2.waitKey(20)
        if cv2.getWindowProperty('pic', cv2.WND_PROP_AUTOSIZE) < 1:
            break
        if pressKey == 27:  # ESC
            print('退出。。。。。')
            break

    cv2.destroyAllWindows()

 

调用分隔算法

  1. 用图像等大的数据初始化掩码
  2. 创建以0填充的前景和背景模型, 输入必须是单通道的浮点型图像, 1行, 13x5 = 65的列 即(1,65)
  3. 自定义区域
  4. 分割
  5. 将0,2合并为0, 1,3合并为1
  6. 与图像合并,取出前景
def cuppic(img, rect):
    print("set rect to ",rect)
    mask = np.zeros(img.shape[:2], np.uint8)
    bgdModel = np.zeros((1,65), np.float64)
    fgdModel = np.zeros((1,65), np.float64)

    bgrect = tuple(rect)
    cv2.grabCut(img, mask, bgrect, bgdModel, fgdModel, 16, cv2.GC_INIT_WITH_RECT)

    mask2 = np.where((mask == 2)|(mask==0),0,1).astype('uint8')
    imgnew = img*mask2[:,:,np.newaxis]
    cv2.imshow('new',imgnew)

效果

 

 

 

已标记关键词 清除标记
相关推荐
在网上找到了一个用Kmeans算法对图片前景与背景的分割的例子,很适合现在的学习,可一直有一个错误不会修改,跪求大神了。 ``` ```# -*- coding: utf-8 -*- import cv2 import numpy as np import math def panelAbstract(srcImage): # read pic shape imgHeight,imgWidth = srcImage.shape[:2] imgHeight = int(imgHeight);imgWidth = int(imgWidth) # 均值聚类提取前景:二维转一维 imgVec = np.float32(srcImage.reshape((-1,3))) criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER,10,1.0) flags = cv2.KMEANS_RANDOM_CENTERS label,clusCenter = cv2.kmeans(imgVec,2,None,criteria,10,flags) clusCenter = np.uint8(clusCenter) clusResult = clusCenter[label.flatten()] imgres = clusResult.reshape((srcImage.shape)) imgres = cv2.cvtColor(imgres,cv2.COLOR_BGR2GRAY) bwThresh = int((np.max(imgres)+np.min(imgres))/2) _,thresh = cv2.threshold(imgres,bwThresh,255,cv2.THRESH_BINARY_INV) threshRotate = cv2.merge([thresh,thresh,thresh]) # 确定前景外接矩形 #find contours contours = cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) minvalx = np.max([imgHeight,imgWidth]);maxvalx = 0 minvaly = np.max([imgHeight,imgWidth]);maxvaly = 0 maxconArea = 0;maxAreaPos = -1 for i in range(len(contours)): if maxconArea < cv2.contourArea(contours[i]): maxconArea = cv2.contourArea(contours[i]) maxAreaPos = i objCont = contours[maxAreaPos] # 旋转校正前景 rect = cv2.minAreaRect(objCont) for j in range(len(objCont)): minvaly = np.min([minvaly,objCont[j][0][0]]) maxvaly = np.max([maxvaly,objCont[j][0][0]]) minvalx = np.min([minvalx,objCont[j][0][1]]) maxvalx = np.max([maxvalx,objCont[j][0][1]]) if rect[2] <=-45: rotAgl = 90 +rect[2] else: rotAgl = rect[2] if rotAgl == 0: panelImg = srcImage[minvalx:maxvalx,minvaly:maxvaly,:] else: rotCtr = rect[0] rotCtr = (int(rotCtr[0]),int(rotCtr[1])) rotMdl = cv2.getRotationMatrix2D(rotCtr,rotAgl,1) imgHeight,imgWidth = srcImage.shape[:2] #图像的旋转 dstHeight = math.sqrt(imgWidth *imgWidth + imgHeight*imgHeight) dstRotimg = cv2.warpAffine(threshRotate,rotMdl,(int(dstHeight),int(dstHeight))) dstImage = cv2.warpAffine(srcImage,rotMdl,(int(dstHeight),int(dstHeight))) dstRotimg = cv2.cvtColor(dstRotimg,cv2.COLOR_BGR2GRAY) _,dstRotBW = cv2.threshold(dstRotimg,127,255,0) contours = cv2.findContours(dstRotBW,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) maxcntArea = 0;maxAreaPos = -1 for i in range(len(contours)): if maxcntArea < cv2.contourArea(contours[i]): maxcntArea = cv2.contourArea(contours[i]) maxAreaPos = i x,y,w,h = cv2.boundingRect(contours[maxAreaPos]) #提取前景:panel panelImg = dstImage[int(y):int(y+h),int(x):int(x+w),:] return panelImg if __name__=="__main__": srcImage = cv2.imread(&#39;11.jpg&#39;) a=panelAbstract(srcImage) cv2.imshow(&#39;figa&#39;,a) cv2.waitKey(0) cv2.destroyAllWindows() 这是原地址https://blog.csdn.net/Dawn__Z/article/details/82115160 报错如下(知道错是什么意思就是不会改):Traceback (most recent call last): File "D:\Workspaces\MyEclipse 2015\pythonTest\src\cc.py", line 70, in a=panelAbstract(srcImage) File "D:\Workspaces\MyEclipse 2015\pythonTest\src\cc.py", line 7, in panelAbstract imgHeight,imgWidth = srcImage.shape[:2] AttributeError: &#39;NoneType&#39; object has no attribute &#39;shape&#39;
©️2020 CSDN 皮肤主题: 点我我会动 设计师:白松林 返回首页