2016-06-03 6 views
2

Ich möchte eine binäre Bildmaske erstellen, die nur Einsen und Nullen in Python enthält. Die Region of Interest (weiß) ist nicht rechteckig, definiert durch 4 Eckpunkte und sieht beispielsweise wie folgt aus: enter image description hereWas ist der effizienteste Weg, um eine nicht-rechteckige ROI eines Bildes in OpenCV auszuwählen?

In meinem Ansatz berechne ich zunächst die Liniengleichung der oberen und unteren ROI-Grenze und dann I Überprüfen Sie für jedes Maskenelement, ob es kleiner oder größer als die Boarder ist. Der Code funktioniert, aber viel zu langsam. Eine 2000 x 1000-Maske benötigt bis zu 4 Sekunden für die Verarbeitung meiner Maschine.

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() 

Was ist eine effizientere Möglichkeit, eine Maske wie diese zu erstellen?

Gibt es ähnliche Lösungen für nicht rechteckige Formen, die von numpy, OpenCV oder einer ähnlichen Bibliothek bereitgestellt werden?

+0

http://codereview.stackexchange.com/ – almanegra

+0

werfen Sie einen Blick auf [Extreme Points] (http://docs.opencv.org/3.1.0/d1/d32/tutorial_py_contour_properties.html#gsc.tab=0) – sturkmen

+0

Siehe meine Antwort unter http://stackoverflow.com/questions/12638790/drawing-rectangle-inside-a-2d-numpy-array für ein Beispiel zum Zeichnen eines gefüllten Polygons mit Pillow. –

Antwort

2

Zeichnen Sie die Maske mit 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) 

Diese ~ 1ms nehmen sollte.

+0

Prächtig. OpenCV scheint die Matrix umgekehrt zu indexieren. Wenn Sie Ihre ROI-Koordinaten austauschen, um das von mir gepostete Bild zu reproduzieren, akzeptiere ich Ihre Antwort. –

+0

Ich habe die Antwort aktualisiert, um den Unterschied zwischen der OpenCV-Indexierung (x, y) und der numpy-Indexierung (Zeilenhaupt) zu verdeutlichen. Die Kommentare in Ihren Snippets geben an, dass ROI als Array von (x, y) bereitgestellt wird. Die Art und Weise, wie Sie mask [x, y] indexieren, ist nicht mit der Indexierung von Zeilen mit numpy konsistent. – szym

+0

Wenn das roi konvex ist, sollten Sie [cv2.fillConvexPoly] (https://docs.opencv.org/2.4/modules/core/doc/drawing_functions.html#fillconvexpoly) für eine bessere Leistung verwenden. – Masterfool

Verwandte Themen