2017-07-08 72 views
0

我有一些工作代碼,但性能很糟糕,可以做得更好,所以讓我們看看它如何進行優化。Opencv和python - 兩行之間的着色區域

我有一張圖片,上面繪製了兩條半垂直線,並希望遮蔽這兩條線之間的區域。我當前的代碼逐個像素迭代,這在python中很慢。

#Get starting images 
shade_image = np.zeros_like(image) 
line_image = plot_lines(shade_image, left_line, right_line) 
#Choose color 
shade_color = [0, 255, 0] 
#Iterate through and fill blank image 
left_switch = False 
right_switch = False 
for i in range(0, image.shape[0]): 
    left_switch = False 
    right_switch = False 
    for j in range(0, image.shape[1]): 
     if left_switch & right_switch: shade_image[i][j] = shade_color 
     #Find left edge of left line 
     if (not left_switch) & (not right_switch) & np.any(line_image[i][j] != 0): 
      left_switch = True 
     #Find right edge of left line 
     elif left_switch & (not right_switch) & np.all(line_image[i][j] == 0): 
      right_switch = True 
     #Find left edge of left line 
     elif left_switch & right_switch & np.any(line_image[i][j] != 0): 
      break 
     #In case of a single line, no shading 
     elif left_switch & right_switch & (j == (image.shape[1] - 1)): 
      shade_image[i].fill(0) 
#Shade lane area 
output_image = cv2.addWeighted(image, 1.0, shade_image, 1.0, gamma=0.0) 

不漂亮。我想不知怎麼這可以通過使用line_image中的所有nonzeros並創建一個蒙版來完成,但我不知道如何在左右點之間填充。我嘗試使用fillPolygon,但我不知道如何將所有非零值轉換爲頂點。

如果有幫助,陰影也可以包含線條,這不是確切的。


@Alxeander - 非常有幫助!我幾乎在那裏,除了現在有一個問題,因爲邊界框,填充凸線之外,如下所示:enter image description here

或者,我拋棄cv2.convexHull並直接使用連接的點作爲頂點一個多邊形,並得到這個結果:enter image description here

它遵循的曲率,凸或凹,但因爲它的順序點時,它從左到右翻轉。我試過使用np.flips(points2,0)但沒有改變。我會再玩一些,幾乎在那裏。


犯了錯誤與np.flip(points2,0),即工作!:enter image description here

感謝您的幫助!

+0

如何在您的線定義的?你有沒有在圖像邊界線的端點,你有一個公式,你有起點的角度和距離嗎?等等。你可以用'fillPoly'或其他方法來完成這個工作,這些方法不會像這樣循環遍歷每個點,但這取決於你的行是如何定義的。看起來您可能可以使用'line_image'通過查找行顏色來查找第一行和最後一行的行終點,並將其用作「fillPoly」的終點,但如果行先前已定義你可能根本不需要第一個線。 –

+0

線條不會延伸到頂部和底部。這些線實際上是由一個多項式定義的,我使用plot_lines()來繪製它們與matplotlib.pyplot,然後將它們轉換爲一個np.array(BGR) – DrTarr

回答

1

由於您的線條是由多項式定義的,這意味着您可以輕鬆地從它們中獲取點集。您的域值爲x,您的多項式值爲y。如果你把這些變成一個點陣列

points = np.array([[[x1, y1]], ..., [[xn, yn]]]) 

那麼你可以通過這些點到OpenCV的功能cv2.fillPoly()cv2.drawContours()填寫的區域。

請注意,多項式可以輕鬆定義圖像邊界外的直線。爲了繪製輪廓或多邊形,您應該使用閉合的形狀,並且將這些超出的點從您的域中剪切掉會更容易。

這裏有一個完整的例子定義區域基於兩個多項式和填充區域:

import numpy as np 
import cv2 

img = cv2.imread('img1.png') 
h, w = img.shape[:2] 

x = np.arange(w) 
polynomial1 = lambda x: x**2/800 
polynomial2 = lambda x: x+200 
y1 = polynomial1(x) 
y2 = polynomial2(x) 

points1 = np.array([[[xi, yi]] for xi, yi in zip(x, y1) if (0<=xi<w and 0<=yi<h)]).astype(np.int32) 
points2 = np.array([[[xi, yi]] for xi, yi in zip(x, y2) if (0<=xi<w and 0<=yi<h)]).astype(np.int32) 
points2 = np.flipud(points2) 
points = np.concatenate((points1, points2)) 

polynomialgon = img.copy() 
cv2.fillPoly(polynomialgon, [points], color=[255,255,255]) 
cv2.imshow('Polygon defined by two polynomials', polynomialgon) 
cv2.waitKey(0) 

,導致:

Filled polygon defined by two polynomials

注意,flipud是繼續前進的點從線的端點以順時針方式;否則在polynomial1結束時,線路將上升到polynomial2開始的位置,所以我們回溯並越過該區域。只要線的端點順時針或逆時針跟蹤,線的作用並不重要。

0

亞歷山大把我領到了正確的方向,我不得不調整它處理的凸條:

import numpy as np 
import cv2 

img = cv2.imread('img1.png') 
h, w = img.shape[:2] 

x = np.arange(w) 
polynomial1 = lambda x: x**2/800 
polynomial2 = lambda x: x+200 
y1 = polynomial1(x) 
y2 = polynomial2(x) 

points1 = np.array([[[xi, yi]] for xi, yi in zip(x, y1) if (0<=xi<w and 0<=yi<h)]).astype(np.int32) 
points2 = np.array([[[xi, yi]] for xi, yi in zip(x, y2) if (0<=xi<w and 0<=yi<h)]).astype(np.int32) 
points = np.concatenate(points1, np.flip(points2, 0)) 

polynomialgon = img.copy() 
cv2.fillPoly(polynomialgon, [points], color=[255,255,255]) 
cv2.imshow('Polygon defined by two polynomials', polynomialgon) 
cv2.waitKey(0) 
+0

是的,我想我腦海中的東西與您使用的不同。確實去除船體將允許凸起的形狀。無論如何,我按照這個建議編輯了我的答案。如果這是您尋找的答案,您能否將我的回答標記爲已接受的答案?謝謝! –