def __init__(self, city): self.path = os.path.dirname(__file__) self.path_xml = os.path.join(self.path, "data", city + ".xml") self.tree = element_tree.parse(self.path_xml) self.root = self.tree.getroot() self.table = Table() for ss in self.root: id = ss.attrib["id"] l = Line(id) for stop in ss: l.add(stop.text) self.table.add(l)
class PreProcess(object): def __init__(self, image_thresh, minv, fun_name_list): """ PreProcess line, find the lines and draw picture """ self.image_thresh = image_thresh self.Minv = minv self.l_line = Line() self.r_line = Line() self.i = 0 self.fun_names = fun_name_list self.ym_per_pix = 30 / 720 # meters per pixel in y dimension self.xm_per_pix = 3.7 / 700 # meters per pixel in x dimension @staticmethod def find_base(binary_image): # Take a histogram of the bottom half of the image histogram = np.sum(binary_image[binary_image.shape[0] // 2:, :], axis=0) # Find the peak of the left and right halves of the histogram # These will be the starting point for the left and right lines midpoint = np.int(histogram.shape[0] // 2) leftx_base = np.argmax(histogram[:midpoint]) rightx_base = np.argmax(histogram[midpoint:]) + midpoint return leftx_base, rightx_base def get_binary_image(self, warped_img, fun_name): """ type is the image_thresh function's name """ return getattr(self.image_thresh, fun_name)(warped_img) def sliding_windows(self, binary_image, nwindows=9, margin=100, minpix=50): """ Fit a second order polynomial to each """ # Set height of windows window_height = np.int(binary_image.shape[0] / nwindows) # Identify the x and y positions of all nonzero pixels in the image nonzero = binary_image.nonzero() nonzeroy = np.array(nonzero[0]) nonzerox = np.array(nonzero[1]) # Current positions to be update for each window leftx_current, rightx_current = self.find_base(binary_image) # Create empty lists to receive left and right lane pixel indices left_lane_inds = [] right_lane_inds = [] # Step through the windows one by one for window in range(nwindows): # Identify window boundaries in x and y (and right and left) win_y_low = binary_image.shape[0] - (window + 1) * window_height win_y_high = binary_image.shape[0] - window * window_height win_xleft_low = leftx_current - margin win_xleft_high = leftx_current + margin win_xright_low = rightx_current - margin win_xright_high = rightx_current + margin # Identify the nonzero pixels in x and y within the window good_left_inds = ((nonzeroy >= win_y_low) & (nonzeroy < win_y_high) & (nonzerox >= win_xleft_low) & (nonzerox < win_xleft_high)).nonzero()[0] good_right_inds = ((nonzeroy >= win_y_low) & (nonzeroy < win_y_high) & (nonzerox >= win_xright_low) & (nonzerox < win_xright_high)).nonzero()[0] # Append these indices to the lists left_lane_inds.append(good_left_inds) right_lane_inds.append(good_right_inds) # If you found > minpix pixels, recenter next window on their mean position if len(good_left_inds) > minpix: leftx_current = np.int(np.mean(nonzerox[good_left_inds])) if len(good_right_inds) > minpix: rightx_current = np.int(np.mean(nonzerox[good_right_inds])) left_lane_inds = np.concatenate(left_lane_inds) right_lane_inds = np.concatenate(right_lane_inds) # Extract left and right line pixel positions leftx = nonzerox[left_lane_inds] lefty = nonzeroy[left_lane_inds] rightx = nonzerox[right_lane_inds] righty = nonzeroy[right_lane_inds] # Fit a second order polynomial to each left_fit = np.polyfit(lefty, leftx, 2) right_fit = np.polyfit(righty, rightx, 2) # Fit new polynomials to x,y in world space left_fit_cr = np.polyfit(lefty * self.ym_per_pix, leftx * self.xm_per_pix, 2) right_fit_cr = np.polyfit(righty * self.ym_per_pix, rightx * self.xm_per_pix, 2) return locals() def skip_sliding_windows(self, binary_image, margin=100): """ Skip the sliding windows step once you know where the lines are """ nonzero = binary_image.nonzero() nonzeroy = np.array(nonzero[0]) nonzerox = np.array(nonzero[1]) left_fit_x = self.l_line.best_fit[0] * (nonzeroy ** 2) + self.l_line.best_fit[1] * nonzeroy + \ self.l_line.best_fit[2] right_fit_x = self.r_line.best_fit[0] * (nonzeroy ** 2) + self.r_line.best_fit[1] * nonzeroy + \ self.r_line.best_fit[2] left_lane_inds = ((nonzerox > left_fit_x - margin) & (nonzerox < left_fit_x + margin)) right_lane_inds = ((nonzerox > right_fit_x - margin) & (nonzerox < right_fit_x + margin)) leftx = nonzerox[left_lane_inds] lefty = nonzeroy[left_lane_inds] rightx = nonzerox[right_lane_inds] righty = nonzeroy[right_lane_inds] # Fit a second order polynomial to each Again left_fit = np.polyfit(lefty, leftx, 2) right_fit = np.polyfit(righty, rightx, 2) left_fit_cr = np.polyfit(lefty * self.ym_per_pix, leftx * self.xm_per_pix, 2) right_fit_cr = np.polyfit(righty * self.ym_per_pix, rightx * self.xm_per_pix, 2) return locals() def add_to_line(self, warped_img, fun_name, margin=100): try: self.binary_image = self.get_binary_image(warped_img, fun_name) if not self.l_line.detected or not self.r_line.detected: line_info = self.sliding_windows(self.binary_image, margin=margin) else: line_info = self.skip_sliding_windows(self.binary_image, margin=margin) left_fit = line_info.get('left_fit') right_fit = line_info.get('right_fit') left_lane_inds = line_info.get('left_lane_inds') right_lane_inds = line_info.get('right_lane_inds') left_fit_cr = line_info.get('left_fit_cr') right_fit_cr = line_info.get('right_fit_cr') if left_fit is None or right_fit is None: return False, ValueError('not found fit ...') self.l_line.add(left_fit, left_lane_inds) self.r_line.add(right_fit, right_lane_inds) self.l_line.fit_cr = left_fit_cr self.r_line.fit_cr = right_fit_cr return True, None except Exception as ex: # print(ex.args) return False, ex def calc_curv_rad_and_center_dist(self, warped_img, margin=100): """ Method to determine radius of curvature and distance from lane center """ # Todo: 可以在这里添加一个过滤,如果没有找到合适的路线,那就在已经找到中使用最合适的,或是使用上一下图像的 for fun_name in self.fun_names: result, ex = self.add_to_line(warped_img, fun_name, margin=margin) if result: break else: print('notfound fun is: ', ex.args) # cv2.imwrite('output_images/test_{}.jpg'.format(self.i), warped_img) self.i += 1 self.l_line.current_fit = [] self.r_line.current_fit = [] # raise ex l_best_fit = self.l_line.best_fit r_best_fit = self.r_line.best_fit left_fit_cr = self.l_line.fit_cr right_fit_cr = self.r_line.fit_cr ploty = np.linspace(0, self.binary_image.shape[0] - 1, self.binary_image.shape[0]) left_fitx = l_best_fit[0] * ploty**2 + l_best_fit[ 1] * ploty + l_best_fit[2] right_fitx = r_best_fit[0] * ploty**2 + r_best_fit[ 1] * ploty + r_best_fit[2] # Calculate the new radii of curvature y_eval = np.max(ploty) left_curverad = ( (1 + (2 * left_fit_cr[0] * y_eval * self.ym_per_pix + left_fit_cr[1])**2)**1.5) / np.absolute(2 * left_fit_cr[0]) right_curverad = ( (1 + (2 * right_fit_cr[0] * y_eval * self.ym_per_pix + right_fit_cr[1])**2)**1.5) / np.absolute(2 * right_fit_cr[0]) # Now our radius of curvature is in meters self.l_line.radius_of_curvature = (left_curverad + right_curverad) / 2 self.r_line.radius_of_curvature = (left_curverad + right_curverad) / 2 # Calculating the distance between the vehicle distance and the center of the road, > 0 is right else left pix_center = self.binary_image.shape[1] / 2 - (left_fitx[-1] + right_fitx[-1]) / 2 m_center = pix_center * self.xm_per_pix self.l_line.line_base_pos = m_center self.r_line.line_base_pos = m_center def draw_lane(self, src_image): new_img = np.copy(src_image) l_fit = self.l_line.best_fit r_fit = self.r_line.best_fit if l_fit is None or r_fit is None: return src_image h, w = src_image.shape[0], src_image.shape[1] # Create an image to draw the lines on warp_zero = np.zeros((h, w), dtype=np.uint8) color_warp = np.dstack((warp_zero, warp_zero, warp_zero)) ploty = np.linspace(0, h - 1, num=h) # to cover same y-range as image left_fitx = l_fit[0] * ploty**2 + l_fit[1] * ploty + l_fit[2] right_fitx = r_fit[0] * ploty**2 + r_fit[1] * ploty + r_fit[2] # Recast the x and y points into usable format for cv2.fillPoly() pts_left = np.array([np.transpose(np.vstack([left_fitx, ploty]))]) pts_right = np.array( [np.flipud(np.transpose(np.vstack([right_fitx, ploty])))]) pts = np.hstack((pts_left, pts_right)) # Draw the lane onto the warped blank image cv2.fillPoly(color_warp, np.int_([pts]), (0, 180, 0)) cv2.polylines(color_warp, np.int32([pts_left]), isClosed=False, color=(255, 0, 0), thickness=15) cv2.polylines(color_warp, np.int32([pts_right]), isClosed=False, color=(0, 0, 255), thickness=15) # Warp the blank back to original image space using inverse perspective matrix (Minv) newwarp = cv2.warpPerspective(color_warp, self.Minv, (w, h)) # Combine the result with the original image result = cv2.addWeighted(new_img, 1, newwarp, 1, 0) return result def draw_small(self, src_image, warped_img): small_shape = (640, 300) small_binary = cv2.resize(self.binary_image, small_shape) small_binary_image = np.dstack( (small_binary, small_binary, small_binary)) * 255 small_warp_image = cv2.resize(warped_img, small_shape) hmerge = np.hstack((small_warp_image, small_binary_image)) background = self.draw_lane(src_image) background[:300, :, :] = hmerge * 0.8 return background def draw_data(self, src_image, warped_img): self.calc_curv_rad_and_center_dist(warped_img) new_img = np.copy(self.draw_small(src_image, warped_img)) font = cv2.FONT_HERSHEY_DUPLEX text = 'Curve radius: ' + '{:04.2f}.'.format( self.l_line.radius_of_curvature) + 'm' cv2.putText(new_img, text, (40, 350), font, 1.5, (255, 255, 255), 2, cv2.LINE_AA) if self.l_line.line_base_pos > 0: direction = 'right' else: direction = 'left' abs_center_dist = abs(self.l_line.line_base_pos) text = direction + ' of center ' + '{:04.3f}'.format( abs_center_dist) + 'm' cv2.putText(new_img, text, (40, 400), font, 1.5, (255, 255, 255), 2, cv2.LINE_AA) return new_img
class Simulator: def __init__(self, server_use, rounds, round_number, epsilon, window, seed=None): self.epsilon = epsilon self.window = window self.running = False self.server_use = server_use self.server = Server() # Servidor self.measures = {} self.flags = { # Dicionário usado para comunicação entre threads "stop": False, "services_num": 0, "served": 0, "round": round_number } self.f_line = Line(self.flags) # Fila 1 self.s_line = Line(self.flags, last_line=True) # Fila 2 self.rounds = rounds self.seed = seed self.iter = 0 self.finished_by_key = False # Inicializando clientes de LOG LOGGER2.info("## Initializing arrivals ##") LOGGER3.info("## Initializing lines ##") LOGGER4.info("## Initializing services ##") LOGGER5.info("## Initializing server ##") LOGGER1.info( "## Initializing simulator <> Server user: {} <> Seed: {} <> Rounds: {} ##" .format(self.server_use, self.seed, self.rounds)) self.initial_time = None # Método gerador de fregueses (roda em thread separada) def arrivals(self, rate): if self.seed: LOGGER2.info("Semente: {}".format(self.seed)) random.seed(self.seed) arrivals_sample = [] chron = Chronometer("Arrivals") while not self.flags["stop"]: # Enquanto o simulador não parar chron.start() # Inicia o temporizador next_sample = random.expovariate( rate ) # Gera um número com distribuição exponencial e taxa dada LOGGER2.info("Waiting: {}".format(next_sample)) arrivals_sample.append(next_sample) while not chron.spent( ) / 1000000 > next_sample: # Enquanto o temporizador for menor que o número pass # Continua em loop chron.stop(final=True) # Ao terminar, reseta o temporizador, chron.take_note("Service {} goes to line 1".format(self.iter), "arrivals".format(self.iter)) service = Service(self.iter) # Cria um serviço self.f_line.add(service) # e o adiciona na fila 1 service.t_line1.start() self.iter += 1 self.flags["services_num"] += 1 @property def rate(self): # Taxa = uso do servidor/2 return self.server_use / 2 # Inicia o simulador def start(self): self.running = True # Gera as threads de servidor e de chegadas de fregueses LOGGER1.info("Initializing server") t_server = Thread(target=self.server.start, args=(self.flags, self.f_line, self.s_line), name="server") LOGGER1.info("Initializing arrivals") t_arrivals = Thread(target=self.arrivals, args=(self.rate, ), name="arrivals") self.initial_time = datetime.now() t_server.start() t_arrivals.start() LOGGER1.info("Server and arrivals threads initialized") while self.flags[ "served"] < self.rounds: # Enquanto o número de fregueses servidos for menor # que o número de rodadas definido if msvcrt.kbhit() and ord( msvcrt.getch()) == 27: # A menos que se pressione ESC LOGGER1.info("Finished by ESC Key press") print("Terminando o simulador...") self.finished_by_key = True break # Continua em loop self.flags[ "stop"] = True # Ao terminar, manda um sinal para todas as threads finalizarem # print("Aguarde a finalização do simulador...") t_server.join() t_arrivals.join() LOGGER1.info("Finished simulator") # É hora de calcular: E[W], E[T], E[Nq], E[N], V[W] (PARA FILAS 1 E 2) self.take_off_transient() self.calculate_measures() if self.finished_by_key: return False return True def calculate_measures(self): self.measures["E[W1]"] = np.mean(self.measures["W1"]) self.measures["E[T1]"] = np.mean(self.measures["T1"]) self.measures["E[N1]"] = np.mean(self.measures["N1"]) self.measures["E[Nq1]"] = np.mean(self.measures["Nq1"]) self.measures["V[W1]"] = np.var(self.measures["W1"]) self.measures["E[W2]"] = np.mean(self.measures["W2"]) self.measures["E[T2]"] = np.mean(self.measures["T2"]) self.measures["E[N2]"] = np.mean(self.measures["N2"]) self.measures["E[Nq2]"] = np.mean(self.measures["Nq2"]) self.measures["V[W2]"] = np.var(self.measures["W2"]) print( "Simulador {}:\n" "- Fila 1:\n >> E[W] = {}\n >> E[T] = {}\n >> E[N] = {}\n" " >> E[Nq] = {}\n >> Var[W] = {}\n\n" "- Fila 2:\n >> E[W] = {}\n >> E[T] = {}\n >> E[N] = {}\n" " >> E[Nq] = {}\n >> Var[W] = {}\n\n".format( self.flags["round"], self.measures["E[W1]"], self.measures["E[T1]"], self.measures["E[N1]"], self.measures["E[Nq1]"], self.measures["V[W1]"], self.measures["E[W2]"], self.measures["E[T2]"], self.measures["E[N2]"], self.measures["E[Nq2]"], self.measures["V[W2]"])) def take_off_transient(self): measures = { "W1": [], "W2": [], "T1": [], "T2": [], "Nq1": [], "Nq2": [], "N1": [], "N2": [] } line_timestamps = [] service_timestamps = [] with open("line_measures_{}.csv".format(self.flags["round"]), "r") as f: lines = f.readlines() for line in lines[1:]: splitted = line.split(",") line_timestamps.append(splitted[0]) measures["N1"].append(int(splitted[1])) measures["Nq1"].append(int(splitted[2])) measures["N2"].append(int(splitted[3])) measures["Nq2"].append(int(splitted[4])) with open("service_measures_{}.csv".format(self.flags["round"]), "r") as f: lines = f.readlines() for line in lines[1:]: splitted = line.split(",") service_timestamps.append(splitted[0]) measures["T1"].append(int(splitted[1]) / 1000000) measures["W1"].append(int(splitted[2]) / 1000000) measures["T2"].append(int(splitted[3]) / 1000000) measures["W2"].append(int(splitted[4]) / 1000000) finishes = self.get_time_transient_finishes(line_timestamps, measures) for i in range(len(service_timestamps)): if service_timestamps[i] > finishes: self.measures["W1"] = measures["W1"][i:] self.measures["W2"] = measures["W2"][i:] self.measures["T1"] = measures["T1"][i:] self.measures["T2"] = measures["T2"][i:] break for i in range(len(line_timestamps)): if line_timestamps[i] > finishes: self.measures["N1"] = measures["N1"][i:] self.measures["N2"] = measures["N2"][i:] self.measures["Nq1"] = measures["Nq1"][i:] self.measures["Nq2"] = measures["Nq2"][i:] break def get_time_transient_finishes(self, line_t, measures): sum = 0 initial_t = line_t[0] acc_values = [] timestamps = [] for i in range(1, len(measures["N1"])): services_on_system = measures["N1"][i] + measures["N2"][i] passed_time = self.time_passed(line_t[i - 1], line_t[i]) sum += services_on_system * passed_time acc_values.append(sum) timestamps.append(self.time_passed(initial_t, line_t[i])) acc = [x / y for x, y in zip(acc_values, timestamps)] for i in range(self.window, len(acc)): var = np.var(np.array(acc[i - self.window:i])) if var < self.epsilon: transient_found = i - self.window break plt.plot(timestamps, acc, 'b-') plt.axvline(x=timestamps[transient_found]) plt.savefig("transient_{}.png".format(self.flags["round"])) """ t_axis = np.array([self.time_passed( self.initial_time, datetime.strptime(time, "%Y-%m-%d %H:%M:%S.%f") ) for time in service_t]) m_axis = np.array([x+y for x, y in zip(measures["T1"], measures["T2"])]) constants, matrix = opt.curve_fit( self.transient_function, t_axis, m_axis, bounds=([0.0, 1.0], [100000.0, 100000.]) ) plt.plot(t_axis, m_axis, 'b-', label='data') plt.plot( m_axis, self.transient_function(m_axis, *constants), 'r-', label='fit: a=%5.3f, b=%5.3f' % tuple(constants) ) plt.legend() plt.show() for i in range(1, len(service_t)): if m_axis[i] - m_axis[i-1] < self.epsilon: return service_t[i] for i in range(len(measures["T1"])): variances.append( np.var([x+y for x, y in zip(measures["T1"][i:], measures["T2"][i:])]) ) variances = variances[0:-1] print("Variâncias de cálculo do período transiente: {}".format(variances)) for i in range(len(variances)-3): if variances[i+1] - variances[i] < self.epsilon: if variances[i+2] - variances[i+1] < self.epsilon: if variances[i+3] - variances[i+2] < self.epsilon: return service_t[i] """ return line_t[transient_found + 1] def time_passed(self, initial, final): delta = datetime.strptime(final, "%Y-%m-%d %H:%M:%S.%f") - \ datetime.strptime(initial, "%Y-%m-%d %H:%M:%S.%f") return delta.seconds + delta.microseconds / 1000000
class ImageProcessor(): """ Implements the computer vision algorithms for detecting lanes in an image. """ def __init__(self, frameDimensions, frameRate): # Define camera dimensions. self.frameDimensions = frameDimensions self.frameRate = frameRate self.w = self.frameDimensions[0] self.h = self.frameDimensions[1] # ROI dimensions in percentage. self.roiY = (0.57, 0.71) self.roiX = (0.67, 0.95) # Initialize the left and right lane classes. self.left = Line(self.frameDimensions, (0, 0, 255)) self.right = Line(self.frameDimensions, (255, 0, 0)) # Camera calibration # Scale the calibration matrix to the desired frame dimensions. self.calibrationResolution = ( 1280, 720) # Resolution at which the camera matrix is provided. kx = self.w / self.calibrationResolution[ 0] # Calculate the change in the -x axis. ky = self.h / self.calibrationResolution[ 1] # Calculate the change in the -y axis. cameraMatrix = np.array([ # Raw camera calibration matrix. [1.00612323e+03, 0.00000000e+00, 6.31540281e+02], [0.00000000e+00, 1.00551440e+03, 3.48207362e+02], [0.00000000e+00, 0.00000000e+00, 1.00000000e+00] ]) self.cameraMatrix = np.multiply( cameraMatrix, [ # Adjust the camera calibration matrix. [kx, 1, kx], [1, ky, ky], [1, 1, 1] ]) self.distortionCoefficients = np.array( [[0.18541226, -0.32660915, 0.00088513, -0.00038131, -0.02052374]]) self.newCameraMatrix, self.roi = cv2.getOptimalNewCameraMatrix( self.cameraMatrix, self.distortionCoefficients, self.frameDimensions, 1, self.frameDimensions) self.rectifyMapX, self.rectifyMapY = cv2.initUndistortRectifyMap( self.cameraMatrix, self.distortionCoefficients, None, self.newCameraMatrix, self.frameDimensions, 5) def doBlur(self, frame, iterations, kernelSize): """ Performs a gaussian blur with the set number of iterations. """ blured = frame.copy() while iterations > 0: blured = cv2.GaussianBlur(blured, (kernelSize, kernelSize), sigmaX=0, sigmaY=0) iterations -= 1 return blured def doRegionOfInterest(self, frame): """ Obtains the region of interest from a frame. The dimensions of the ROI are set by the class properties roiX and roiY. """ y0Px = self.h * self.roiY[0] y1Px = self.h * self.roiY[1] x0Px = (1 - self.roiX[0]) * self.w / 2 x1Px = (1 - self.roiX[1]) * self.w / 2 vertices = np.array([[(x0Px, y0Px), (x1Px, y1Px), (self.w - x1Px, y1Px), (self.w - x0Px, y0Px)]], dtype=np.int32) mask = np.zeros_like(frame) cv2.fillPoly(mask, vertices, 255) return cv2.bitwise_and(frame, mask) def findLanes(self, frame, lines, minAngle=10, drawAll=False): """ Iterates through the results from the Hough Transform and filters the detected lines into those who belong to the left and right lane. Finally fits the data to a 1st order polynomial. """ self.left.clear() self.right.clear() if type(lines) == type(np.array([])): for line in lines: for x1, y1, x2, y2 in line: angle = np.degrees(np.arctan2(y2 - y1, x2 - x1)) if np.abs(angle) > minAngle: if angle > 0: self.right.add(x1, y1, x2, y2) if drawAll: cv2.line(frame, (x1, y1), (x2, y2), self.right.color) else: self.left.add(x1, y1, x2, y2) if drawAll: cv2.line(frame, (x1, y1), (x2, y2), self.left.color) self.left.fit() self.right.fit() return frame def drawPoly(self, frame, poly, color, width=3): """ Draws a 1-D polynomial into the frame. Uses the roiY for the -y coordinates. """ y0 = self.h * self.roiY[0] y1 = self.h * self.roiY[1] y0Px = int(y0) y1Px = int(y1) if poly: x0Px = int(poly(y0)) x1Px = int(poly(y1)) cv2.line(frame, (x0Px, y0Px), (x1Px, y1Px), color, width) else: cv2.line(frame, (0, y0Px), (0, y1Px), color, width) def process(self, frame): """ Main pipeline for detecting lanes on a frame. """ undistort = cv2.remap(frame, self.rectifyMapX, self.rectifyMapY, cv2.INTER_LINEAR) gray = cv2.cvtColor(undistort, cv2.COLOR_BGR2GRAY) grayColor = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR) blured = self.doBlur(gray, iterations=3, kernelSize=7) canny = cv2.Canny(blured, threshold1=20, threshold2=40) roi = self.doRegionOfInterest(canny) houghLines = cv2.HoughLinesP(roi, rho=1, theta=np.pi / 180, threshold=20, lines=np.array([]), minLineLength=5, maxLineGap=60) lanes = self.findLanes(grayColor, houghLines, minAngle=10, drawAll=True) # self.drawPoly(lanes, self.left.poly, self.left.color, width=3) # self.drawPoly(lanes, self.right.poly, self.right.color, width=3) return grayColor