-
CSE4152-4주차 Lane Detection7학기/고급소프트웨어실습 2022. 10. 29. 21:05
base code는 작성되어 있고, 우리는 핵심 로직 부분만 구현을 진행하면 된다.
Lane Detection을 진행 할 화면은 다음과 같다.
1. Image crop and Gray scaling
edge 추출을 위해서 RGB이미지를 Gray이미지로 변환한다. 그리고, 자동차의 전방 부분만 인식하기 위해 화면의 아랫부분을 자른다.
참고로 현재 이미지의 좌표계는 왼쪽 위가 (0,0) 이고, 각 픽셀의 인덱스는 [Height, Width, RGB]로 표현된다.
따라서, 자동차의 전방부분을 인식하기 위해서는 Height부분을 쪼개야하고, 이후에 계산의 편의를 위하여 Height부분을 뒤집는다.
2. Get Gradient
edge를 찾기 위해 gradient를 구해준다. 이 때, gradient를 구하는 방향은 row방향이어야 한다.
그리고, 부정확한 gradient를 제거하기 위해서 threshold를 해준다. 이 때, gradient를 구하는 방향에 따라서 길 양쪽의 gradient값이 다를 것이다. 변위가 서로 다르기 때문이다. 그러니 gradient에 절대값을 씌워서 이 값을 가지고 threshold를 진행해주어야 한다.
다행이 numpy에 gradient 함수가 존재한다. 이 함수는 파라미터가 2차원이면 row방향, col방향 총 2개의 gradient를 return해준다. 그런데 gray_image는 인덱스가 [Height][Width]로 되어있다. 따라서 Width의 gradient를 구해야 하므로, 두번째로 return되는 gradient array를 이용한다.
threshold를 적용하기 위해 numpy의 where함수를 이용하면 쉽게 구현 할 수 있다.
3. Find maxima of each row
이제, 각 row에 대한 gradient를 구했으므로 maxima를 구해 줄 차례이다.
scipy.sinal.find_peak 함수를 이용하면 파라미터로 넣은 array에 대해서 peak좌표를 구해 줄 수 있다.
그러면 해당 row에 대한 차선 두 개의 좌표는 (peak, row)가 된다.
def find_maxima_gradient_rowwise(self, gradient_sum): ''' ##### TODO ##### This function should output arguments of local maxima for each row of the gradient image. You can use scipy.signal.find_peaks to detect maxima. Hint: Use distance argument for a better robustness. input: gradient_sum 65x96x1 output: maxima (np.array) shape : (Number_maxima, 2) ''' temp = np.empty((0, 2)) for row in range(self.cut_size): # Find peaks with min distance of at least 3 pixel argmaxima = find_peaks(gradient_sum[row],distance=3)[0] # if one lane_boundary is found if argmaxima.shape[0] == 1: temp = np.append(temp, np.array([[argmaxima[0], row]]), axis=0) # lanes_found = True # if 2 lane_boundaries are found elif argmaxima.shape[0] == 2: temp = np.append(temp, np.array([[argmaxima[0], row]]), axis=0) temp = np.append(temp, np.array([[argmaxima[1], row]]), axis=0) # lanes_found = True return temp
나의 경우 한 row에서 peak가 2개 이하인 경우에만 추가해줬다. 이 경우엔 유턴이 나올 경우 peak가 3개 이상이므로 제대로 탐지되지 않는다. 잘 개선을 하는것도 좋을것이다.
4. Lane detection
이제 제일 중요한 lane detection이다. 우리는 3. 에서 각 peak점들을 수집했다. 이 peak들을 두개의 직선으로 분류해서 그려주면 된다!
def lane_detection(self, state_image_full): ''' ##### TODO ##### This function should perform the road detection args: state_image_full [96, 96, 3] out: lane_boundary1 spline lane_boundary2 spline ''' # to gray gray_state = self.cut_gray(state_image_full) # edge detection via gradient sum and thresholding gradient_sum = self.edge_detection(gray_state) maxima = self.find_maxima_gradient_rowwise(gradient_sum) ind = np.lexsort((maxima[:,0],maxima[:,1])) maxima = maxima[ind] # first lane_boundary points lane_boundary1_points, lane_boundary2_points, lane_found = self.find_first_lane_point(gradient_sum) # if no lane was found,use lane_boundaries of the preceding step if lane_found: ##### TODO ##### # in every iteration: # 1- find maximum/edge with the lowest distance to the last lane boundary point # 2- append maximum to lane_boundary1_points or lane_boundary2_points # 3- delete maximum from maxima # 4- stop loop if there is no maximum left # or if the distance to the next one is too big (>=100) for i in maxima: len_1, len_2 = np.linalg.norm(i-lane_boundary1_points[-1]), np.linalg.norm(i-lane_boundary2_points[-1]) if len_1 < len_2: lane_boundary1_points = np.append(lane_boundary1_points, [i], axis=0) else: lane_boundary2_points = np.append(lane_boundary2_points, [i], axis=0) # lane_boundary 1 # lane_boundary 2 ################ ##### TODO ##### # spline fitting using scipy.interpolate.splprep # and the arguments self.spline_smoothness # # if there are more lane_boundary points points than spline parameters # else use perceding spline lane_boundary1_points = np.unique(lane_boundary1_points, axis=0) lane_boundary2_points = np.unique(lane_boundary2_points, axis=0) if lane_boundary1_points.shape[0] > 4 and lane_boundary2_points.shape[0] > 4: lane_boundary1, u = splprep(lane_boundary1_points.T, s=0) lane_boundary2, u = splprep(lane_boundary2_points.T, s=0) # Pay attention: the first lane_boundary point might occur twice # lane_boundary 1 # lane_boundary 2 else: lane_boundary1 = self.lane_boundary1_old lane_boundary2 = self.lane_boundary2_old ################ else: lane_boundary1 = self.lane_boundary1_old lane_boundary2 = self.lane_boundary2_old self.lane_boundary1_old = lane_boundary1 self.lane_boundary2_old = lane_boundary2 # output the spline return lane_boundary1, lane_boundary2
단순히 maxima의 점을 하나씩 보면서 두 개의 직선 중 더 가까운곳에 매핑을 해주면 된다.
splprep로 스무스하게 그려주면 완료!
5. 결과