專案:停車場車位識別
GITHUB地址
GITHUB
解決程序如下
形態學操作
對原始影像預處理操作,然后第一步給某一幀影像套上mask遮罩,原始影像和遮罩如下圖所示:


然后對圖片二值化等基本操作,得到的結果進行禮帽操作(TOPHAT),目的是去除干擾的白色車輛,效果如下圖所示:

垂直直線檢測
對影像進行霍夫變換,選擇較大的閾值,將影像中的垂直直線檢測出來,并使用abs(y2 - y1) >= 20 and abs(x2 - x1) <= 10的方法進行粗略的結果篩選,具體代碼如下:
lines = cv2.HoughLinesP(img, rho = 1, theta=np.pi, threshold=5, minLineLength=100, maxLineGap=40)
img1 = np.zeros(org.shape, np.uint8)
cleaned = []
for line in lines:
for x1, y1, x2, y2 in line:
if abs(y2 - y1) >= 20 and abs(x2 - x1) <= 10:
cleaned.append((x1, y1, x2, y2))
cv2.line(img1, (x1, y1), (x2, y2), [255, 255, 255], 2)
img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
imshow(img1)
處理結果如下:

之后對影像進行閉運算 + 開運算,去除未填補滿的小洞以及毛刺部分,然后使用Canny邊緣檢測,檢測出影像中的輪廓部分,處理結果如下:

之后對邊界進行輪廓檢測,并找到外接矩形,然后即可獲得每一大列(總共10列)的中心位置
水平直線檢測
依然使用霍夫變換進行水平直線檢測,此時選擇較小的閾值,具體的代碼如下:
lines = cv2.HoughLinesP(img, rho = 0.1, theta=np.pi/10, threshold=18, minLineLength=10, maxLineGap=7)
show = org.copy()
cleaned = []
for line in lines:
for x1, y1, x2, y2 in line:
if abs(x1 - x2) > 25 and abs(y1 - y2) < 10:
cleaned.append((x1, y1, x2, y2))
show = cv2.line(show, (x1, y1), (x2, y2), [0, 255, 0], 1)
for (x, y, h) in center_line:
(x1, y1, x2, y2) = (x, y - h/2, x, y + h/2)
x1 = int(x1)
y1 = int(y1)
x2 = int(x2)
y2 = int(y2)
show = cv2.line(show, (x1, y1), (x2, y2), (0, 0, 255), 1)
imshow(show)
處理結果如下:

之后進行排序和聚類,使得其順序為從上到下,并且分為十大簇,每一簇代表一大列
記憶化搜索擇優
觀察上一步得到的結果,容易看出綠色的線有重合,而且非常的雜亂還有空缺,此時需要使用記憶化搜索進行擇優,具體的代碼比較復雜,如下:
#用于儲存最終結果
ans = [[] for i in range(len(break_dot) - 1)]
#動態規劃陣列
dp = []
#快取變數
buf = []
#用于計算路徑path的變數
father = {}
path = []
#尋找近鄰函式
err = 2.5
def findnei(idx, y, multi):
y1_upper = y + 15.5*multi + err
y1_lower = y + 15.5*multi - err
y2_upper = y - 15.5*multi + err
y2_lower = y - 15.5*multi - err
upper = []
lower = []
for i in range(len(buf)):
y = buf[i][1]
if y > y1_lower and y < y1_upper:
upper.append(i)
elif y > y2_lower and y < y2_upper:
lower.append(i)
return (upper, lower)
#深度優先搜索
def dfs(idx, i):
#查表
if dp[i] >= 0:
return dp[i]
#取出臨近點
y1 = buf[i][1]
for j in range(5):
nei = findnei(idx, y1, j+1)[1]
if len(nei) != 0:
break
#如果沒有臨近點
if len(nei) == 0:
dp[i] = 1
father[i] = None
return dp[i]
#找到最優臨近點的編號和DP值
MAX = -1e6
MAX_IDX = -1
#狀態轉移
for j in range(len(nei)):
if dfs(idx, nei[j]) > MAX:
MAX = dfs(idx, nei[j]) + 1
MAX_IDX = nei[j]
#記錄father
dp[i] = MAX
father[i] = MAX_IDX
return dp[i]
# memdfs
for i in range(10):
buf = cleaned[break_dot[i]:break_dot[i+1]]
#初始化
dp = [-1 for i in range(len(buf))]
#記憶化搜索
MAX = -1e6
for j in range(len(buf)-1, -1, -1):
if dfs(i, j) > MAX:
MAX = dfs(i, j)
#計算path路徑
x = father[j]
path = []
path.append(j)
while x != None:
path.append(x)
x = father[x]
#計算ans
path = sorted(path)
for j in path:
ans[i].append(buf[j])
#搜索結果可視化
clr = [(255, 0, 0), (0, 255, 0), (0, 0, 255)]
show = np.copy(org)
for i in range(len(break_dot) - 1):
for (x1, y1, x2, y2) in ans[i]:
show = cv2.line(show, (x1, y1), (x2, y2), clr[i % 3], 2)
imshow(show)
處理的結果如下:

插值和對齊
記憶化搜索出來的結果沒有重疊的部分,而且都是匹配比較優良的組合,但是其沒有左右對齊,比較雜亂,而且中間有空隙,
需要使用插值演算法填補其中的空隙,使用對齊演算法將每一簇的橫線對齊
具體的代碼如下:
#對齊
ex = 30
for i in range(len(ans)):
(x0, y0, _) = center_line[i]
for j in range(len(ans[i])):
(x1, y1, x2, y2) = ans[i][j]
x1 = x0 - ex
x2 = x0 + ex
ans[i][j] = (x1, y1, x2, y2)
#對齊結果顯示
show = np.copy(org)
for i in range(len(break_dot) - 1):
for (x1, y1, x2, y2) in ans[i]:
show = cv2.line(show, (x1, y1), (x2, y2), (0, 0, 255), 2)
imshow(show)
#插值
err = 2.5
def gap(y1, y2):
delta = abs(y1 - y2)
mul = (delta + err) / 15.5
return int(mul)
for i in range(len(ans)):
buf = []
for j in range(len(ans[i]) - 1):
(x1, y1, x2, y2) = ans[i][j]
(_, y, _, _) = ans[i][j+1]
cnt = gap(y, y1)
for k in range(cnt):
newy = int(y1 + 15.5 * k)
buf.append((x1, newy, x2, newy))
buf.append(ans[i][len(ans[i]) - 1])
ans[i] = buf
#繪制
show = np.copy(org)
for i in range(len(break_dot) - 1):
for (x1, y1, x2, y2) in ans[i]:
show = cv2.line(show, (x1, y1), (x2, y2), (0, 0, 255), 2)
imshow(show)
處理結果如下:

最后進行影像的切分,切分結果如下:

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/4725.html
標籤:python
下一篇:計算機網路習題
