grabcut.py 6.29 KB
Newer Older
1 2 3 4 5 6 7
#!/usr/bin/env python
'''
===============================================================================
Interactive Image Segmentation using GrabCut algorithm.

This sample shows interactive image segmentation using grabcut algorithm.

8
USAGE:
9 10
    python grabcut.py <filename>

11
README FIRST:
12
    Two windows will show up, one for input and one for output.
13 14

    At first, in input window, draw a rectangle around the object using
15
mouse right button. Then press 'n' to segment the object (once or a few times)
16
For any finer touch-ups, you can press any of the keys below and draw lines on
17 18 19 20 21 22 23 24 25 26 27 28 29
the areas you want. Then again press 'n' for updating the output.

Key '0' - To select areas of sure background
Key '1' - To select areas of sure foreground
Key '2' - To select areas of probable background
Key '3' - To select areas of probable foreground

Key 'n' - To update the segmentation
Key 'r' - To reset the setup
Key 's' - To save the results
===============================================================================
'''

30 31 32
# Python 2/3 compatibility
from __future__ import print_function

33
import numpy as np
34
import cv2 as cv
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
import sys

BLUE = [255,0,0]        # rectangle color
RED = [0,0,255]         # PR BG
GREEN = [0,255,0]       # PR FG
BLACK = [0,0,0]         # sure BG
WHITE = [255,255,255]   # sure FG

DRAW_BG = {'color' : BLACK, 'val' : 0}
DRAW_FG = {'color' : WHITE, 'val' : 1}
DRAW_PR_FG = {'color' : GREEN, 'val' : 3}
DRAW_PR_BG = {'color' : RED, 'val' : 2}

# setting up flags
rect = (0,0,1,1)
drawing = False         # flag for drawing curves
rectangle = False       # flag for drawing rect
rect_over = False       # flag to check if rect drawn
rect_or_mask = 100      # flag for selecting rect or mask mode
value = DRAW_FG         # drawing initialized to FG
thickness = 3           # brush thickness

def onmouse(event,x,y,flags,param):
    global img,img2,drawing,value,mask,rectangle,rect,rect_or_mask,ix,iy,rect_over
59

60
    # Draw Rectangle
61
    if event == cv.EVENT_RBUTTONDOWN:
62 63 64
        rectangle = True
        ix,iy = x,y

65
    elif event == cv.EVENT_MOUSEMOVE:
66 67
        if rectangle == True:
            img = img2.copy()
68
            cv.rectangle(img,(ix,iy),(x,y),BLUE,2)
69
            rect = (min(ix,x),min(iy,y),abs(ix-x),abs(iy-y))
70 71
            rect_or_mask = 0

72
    elif event == cv.EVENT_RBUTTONUP:
73 74
        rectangle = False
        rect_over = True
75
        cv.rectangle(img,(ix,iy),(x,y),BLUE,2)
76
        rect = (min(ix,x),min(iy,y),abs(ix-x),abs(iy-y))
77
        rect_or_mask = 0
78
        print(" Now press the key 'n' a few times until no further change \n")
79

80
    # draw touchup curves
81

82
    if event == cv.EVENT_LBUTTONDOWN:
83
        if rect_over == False:
84
            print("first draw rectangle \n")
85 86
        else:
            drawing = True
87 88
            cv.circle(img,(x,y),thickness,value['color'],-1)
            cv.circle(mask,(x,y),thickness,value['val'],-1)
89

90
    elif event == cv.EVENT_MOUSEMOVE:
91
        if drawing == True:
92 93
            cv.circle(img,(x,y),thickness,value['color'],-1)
            cv.circle(mask,(x,y),thickness,value['val'],-1)
94

95
    elif event == cv.EVENT_LBUTTONUP:
96 97
        if drawing == True:
            drawing = False
98 99
            cv.circle(img,(x,y),thickness,value['color'],-1)
            cv.circle(mask,(x,y),thickness,value['val'],-1)
100

101 102 103
if __name__ == '__main__':

    # print documentation
104
    print(__doc__)
105 106 107 108 109

    # Loading images
    if len(sys.argv) == 2:
        filename = sys.argv[1] # for drawing purposes
    else:
110 111
        print("No input image given, so loading default image, ../data/lena.jpg \n")
        print("Correct Usage: python grabcut.py <filename> \n")
112 113
        filename = '../data/lena.jpg'

114
    img = cv.imread(filename)
115 116 117 118 119
    img2 = img.copy()                               # a copy of original image
    mask = np.zeros(img.shape[:2],dtype = np.uint8) # mask initialized to PR_BG
    output = np.zeros(img.shape,np.uint8)           # output image to be shown

    # input and output windows
120 121 122 123
    cv.namedWindow('output')
    cv.namedWindow('input')
    cv.setMouseCallback('input',onmouse)
    cv.moveWindow('input',img.shape[1]+10,90)
124

125 126
    print(" Instructions: \n")
    print(" Draw a rectangle around the object using right mouse button \n")
127 128 129

    while(1):

130 131 132
        cv.imshow('output',output)
        cv.imshow('input',img)
        k = cv.waitKey(1)
133 134 135 136 137

        # key bindings
        if k == 27:         # esc to exit
            break
        elif k == ord('0'): # BG drawing
138
            print(" mark background regions with left mouse button \n")
139 140
            value = DRAW_BG
        elif k == ord('1'): # FG drawing
141
            print(" mark foreground regions with left mouse button \n")
142 143 144 145 146 147 148 149
            value = DRAW_FG
        elif k == ord('2'): # PR_BG drawing
            value = DRAW_PR_BG
        elif k == ord('3'): # PR_FG drawing
            value = DRAW_PR_FG
        elif k == ord('s'): # save image
            bar = np.zeros((img.shape[0],5,3),np.uint8)
            res = np.hstack((img2,bar,img,bar,output))
150
            cv.imwrite('grabcut_output.png',res)
151
            print(" Result saved as image \n")
152
        elif k == ord('r'): # reset everything
153
            print("resetting \n")
154 155 156 157 158 159 160 161 162 163
            rect = (0,0,1,1)
            drawing = False
            rectangle = False
            rect_or_mask = 100
            rect_over = False
            value = DRAW_FG
            img = img2.copy()
            mask = np.zeros(img.shape[:2],dtype = np.uint8) # mask initialized to PR_BG
            output = np.zeros(img.shape,np.uint8)           # output image to be shown
        elif k == ord('n'): # segment the image
164 165
            print(""" For finer touchups, mark foreground and background after pressing keys 0-3
            and again press 'n' \n""")
166 167 168
            if (rect_or_mask == 0):         # grabcut with rect
                bgdmodel = np.zeros((1,65),np.float64)
                fgdmodel = np.zeros((1,65),np.float64)
169
                cv.grabCut(img2,mask,rect,bgdmodel,fgdmodel,1,cv.GC_INIT_WITH_RECT)
170 171 172 173
                rect_or_mask = 1
            elif rect_or_mask == 1:         # grabcut with mask
                bgdmodel = np.zeros((1,65),np.float64)
                fgdmodel = np.zeros((1,65),np.float64)
174
                cv.grabCut(img2,mask,rect,bgdmodel,fgdmodel,1,cv.GC_INIT_WITH_MASK)
175 176

        mask2 = np.where((mask==1) + (mask==3),255,0).astype('uint8')
177
        output = cv.bitwise_and(img2,img2,mask=mask2)
178

179
    cv.destroyAllWindows()