Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the most efficient way to select a non-rectangular ROI of an Image in OpenCV?

I want to create a binary image mask, containing only ones and zeros in python. The Region of Interest(white) is non-rectangular, defined by 4 corner points and looks for example as follows: enter image description here

In my approach, I first calculate the line equation of the upper and lower ROI border and then I check for each mask element, if it's smaller or bigger than the boarders. The code is working, but far to slow. A 2000x1000 mask takes up to 4s of processing my machine.

from matplotlib import pyplot as plt 
import cv2
import numpy as np
import time

def line_eq(line):
    """input:
            2 points of a line
       returns: 
            slope and intersection of the line
    """
    (x1, y1), (x2, y2) = line
    slope = (y2 - y1) / float((x2 - x1))
    intersect = int(slope * (-x1) + y1)

    return slope,intersect

def maskByROI(mask,ROI):
    """
        input: 
            ROI: with 4 corner points e.g. ((x0,y0),(x1,y1),(x2,y2),(x3,y3))
            mask: 
        output: 
            mask with roi set to 1, rest to 0

    """


    line1 = line_eq((ROI[0],ROI[1]))
    line2 = line_eq((ROI[2],ROI[3]))

    slope1 = line1[0] 
    intersect1 = line1[1]

    #upper line
    if slope1>0:
        for (x,y), value in np.ndenumerate(mask):
                if y > slope1*x +intersect1:
                    mask[x,y] = 0
    else:   
        for (x,y), value in np.ndenumerate(mask):
                if y < slope1*x +intersect1:
                    mask[x,y] = 0
    #lower line
    slope2 = line2[0]
    intersect2 = line2[1]
    if slope2<0:
        for (x,y), value in np.ndenumerate(mask):
                if y > slope2*x +intersect2:
                    mask[x,y] = 0
    else:   
        for (x,y), value in np.ndenumerate(mask):
                if y < slope2*x +intersect2:
                    mask[x,y] = 0

    return mask



mask = np.ones((2000,1000))

myROI = ((750,0),(900,1000),(1000,1000),(1500,0))

t1 = time.time()
mask = maskByROI(mask,myROI)
t2 = time.time()

print "execution time: ", t2-t1


plt.imshow(mask,cmap='Greys_r')
plt.show()

What is a more efficient way to create a mask like this?

Are there any similar solutions for non-rectangular shapes provided by numpy, OpenCV or a similar Library?

like image 952
Mr Vinagi Avatar asked Jun 03 '16 22:06

Mr Vinagi


People also ask

How do I find my ROI on OpenCV?

Python OpenCV – selectroi() Function With this method, we can select a range of interest in an image manually by selecting the area on the image. Parameter: window_name: name of the window where selection process will be shown. source image: image to select a ROI.

Which CV method is used to display an image?

cv2. imshow() method is used to display an image in a window.


1 Answers

Draw the mask with fillPoly:

mask = np.ones((1000, 2000))                              # (height, width)
myROI = [(750, 0), (900, 1000), (1000, 1000), (1500, 0)]  # (x, y)
cv2.fillPoly(mask, [np.array(myROI)], 0)

This should take ~1ms.

like image 194
szym Avatar answered Oct 03 '22 22:10

szym