Advertisement

无人驾驶汽车的计算机视觉技术

阅读量:

作者:禅与计算机程序设计艺术

1.简介

1969年,英国物理学家康奈尔·艾萨克·爱默生最先提出"机器人作为宇宙中理性的一种补偿"这一重要观点直至如今无人驾驶(self-driving car)已融入自然生态体系并广泛应用于多个关键领域无人驾驶汽车的出现对机器学习图像处理等相关科技的发展起到了显著促进作用这些技术不仅有助于实现自动驾驶功能还能支撑相关技术体系的完善然而由于缺乏统一的技术标准和规范机制目前行业内技术交流仍然较为有限导致各方在技术研发方向上存在诸多分歧本文将从理论层面探讨无人驾驶汽车的计算机视觉技术

2.计算机视觉技术的基本概念及术语说明

在讲解无人驾驶汽车的计算机视觉技术前,应先认识一些基本概念与术语。

2.1 计算机视觉的定义及特点

计算机视觉(Computer Vision, CV)主要涉及让机器具备视觉感知功能的分支领域。一般来说,在这一领域内研究如何使机器能够识别和理解各种视觉信息,并进而实现智能行为的应用,例如目标跟踪、图像识别以及结构化输出等技术。

2.1.1 计算机视觉的定义

从工程学角度来看

主要涉及图像处理模式识别机器学习计算视觉环境感知等多个子领域

2.1.2 计算机视觉的特点

计算机视觉具有以下几个主要特征:

1

2

2.2 图像表示、像素值、颜色空间、直方图等基本概念

  1. 图像表示:图像由像素构成,在每个像素中都有相应的灰度值或RGB值。图像的表现形式多种多样,在最常用的两种表现形式为灰度图像和RGB图像。其中灰度图像是仅由单个灰度值定义的图像类型,而RGB图像是通过红、绿、蓝三个通道赋予每个像素色彩属性。
  2. 像素值:在数字图像中,每个像素的数值代表该位置点的亮度或色彩属性。这些数值通常采用整数表示方法,在0到255之间取整。
  3. 颜色空间:颜色信息的描述方式有很多种,在应用最广泛的有两种表现形式——RGB色彩空间与HSV色彩空间。前者基于三原色理论构建颜色体系,后者则通过两个坐标轴来定义颜色特性。不同色彩空间之间存在转换关系,在实际应用中可以选择合适的模型进行转换运算。
  4. 直方图:直方图是用于展示数字图像统计特征的一种图形工具。它由一系列垂直条形构成,在横坐标轴上标注的是可能的像素数值范围,在纵坐标轴上则是对应数值出现的频率分布情况。通过不同颜色区分各区域分布特征可以使图表更加直观易懂,并且能够有效反映图片的整体明暗、对比度及色调分布情况等关键参数。

3.核心算法原理和具体操作步骤以及数学公式讲解

本节将深入分析自动驾驶汽车中计算机视觉技术的关键算法及其核心原理,并详细描述其具体的实现流程。

边缘检测:其主要目标在于识别图像中的关键边缘信息,并以此为基础实现物体定位与识别过程。常用的技术手段包括Canny算子、Harris角点探测法以及Hofmann角点探测法等方法。
具体的Canny算子作为一种基于边缘检测的图像分割技术,在1986年由John Canny及其合作伙伴Andrew P. Witkin和Andrew Shepherd等人提出。该算法通过高斯滤波器对图像进行平滑处理,并结合梯度算子提取边缘特征。随后通过分析图像像素强度的变化情况来实现轮廓检测与区域划分。其主要运算流程如下所述:

  1. 使用高斯滤波进行模糊处理;
  2. 梯度算子求图像的梯度;
  3. 将梯度值映射到 0~1 之间;
  4. 根据梯度值确定是否是边缘;
  5. 对噪声和其他干扰进行抑制。
    1.2 Harris 角点检测法:Harris 角点检测法是一种基于图像梯度的方法,由 Marcus-Kanade 提出。该算法通过求图像的梯度幅值和角度进行筛选,检测图像中的显著角点。
    1.3 霍夫曼角点检测法:霍夫曼角点检测法是一种基于曲线积分的方法,由 R. Hough 于 1972 年提出。该算法通过扫描图像中的所有直线,判断哪些直线能够与点对应,从而找到图像上的角点。
    1.4 检测图像的边缘
    可以通过将不同的边缘检测算法组合起来,来检测到图像的边缘。如在 Canny 算子的基础上,结合 Harris 角点检测和霍夫曼角点检测,就可以获得更好的边缘检测效果。

车牌识别技术:该技术的主要目标是准确识别并定位小型车辆的车牌图像。通常情况下,有效的车牌号码由4至12个字符组成,并且为了提高定位精度和字符辨识度,在实际应用中会将原始图像经过预处理后分割成独立的字符片段,并对每个片段进行详细分析以提高识别精度。

复制代码
    def detect_car_number(img):
     '''
     Detect and locate the number of a car plate image.
     :param img: numpy array, the input image
     :return: list, a list of tuples (x, y, w, h), where x is the left top point's x value,
         y is the left top point's y value, w is width, and h is height, representing the bounding box
         of each character in the detected characters' images.
     '''
     gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)   # convert to grayscale
     ret, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)    # binarize the image using Otsu's method
     contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)    # find all contour points
     
     # find the contour with maximum area that covers most of the image as the main background 
     max_area = -1
     for cnt in contours:
     if len(cnt) > 5:
         area = cv2.contourArea(cnt)
         if area > max_area:
             max_area = area
             bg_mask = np.zeros_like(binary)
             cv2.drawContours(bg_mask, [cnt], -1, 255, -1)
     
     # remove the foreground from the original image
     fg_mask = cv2.bitwise_not(bg_mask)
     roi = cv2.bitwise_and(img, img, mask=fg_mask)
     
     # split the image into individual characters based on their similarity
     chars = []
     kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 2))
     char_imgs = cv2.dilate(roi, kernel, iterations=2)
     bw = cv2.cvtColor(char_imgs, cv2.COLOR_BGR2GRAY)
     _, bw = cv2.threshold(bw, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
     im2, contours, hierarchy = cv2.findContours(bw, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
     for c in sorted(contours, key=cv2.contourArea, reverse=True)[:10]:    # only consider the largest 10 contours
     x,y,w,h = cv2.boundingRect(c)
     
     if abs(w/float(h)-3)>0.1 or h<15:    # exclude very narrow or short characters 
         continue 
     if cv2.contourArea(c)<50:      # exclude very small characters
         continue
         
     roi = bw[y:y+h, x:x+w]
     hsv_roi = cv2.cvtColor(roi, cv2.COLOR_GRAY2BGR)
     color_min = np.array([20, 100, 50])
     color_max = np.array([60, 255, 255])
     mask = cv2.inRange(hsv_roi, color_min, color_max)
     
     # if no pixels are within range, discard this character
     if not cv2.countNonZero(mask)==0:    
         img[y:y+h, x:x+w] = cv2.addWeighted(img[y:y+h, x:x+w], 0, hsv_roi,.7, 0)    # add this character to output image
         
         roi = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)
         resized = cv2.resize(roi,(32,32), interpolation = cv2.INTER_AREA)
         
         chars.append((x,y,w,h))
     
     return chars
    
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读
  1. 对象检测:在无人驾驶汽车领域中,目标检测作为首要环节发挥着重要作用。它不仅是一种常见的技术问题,更是实现自动驾驶系统的基础步骤之一。具体而言,目标检测是指从给定的图像中准确识别物体的具体位置、类别以及尺寸范围,并涵盖行人、车辆等各类实体的识别任务。这一过程主要由两大部分组成:首先是特征提取阶段(特征提取),其次是物体定位与分类阶段(定位与分类)。
    3.1 分类器:在目标识别过程中,分类器的作用是通过建立多类别判别模型来完成对不同对象的识别任务。常见的分类方法包括支持向量机(SVM)、k近邻算法(KNN)、卷积神经网络(CNN)等多类别的判别方法体系。其中SVM是一种基于统计学习理论的二类判别方法;KNN则是一种基于距离度量的非参数判别方法;CNN则是一种基于深度学习框架设计的多层感知机类型的方法体系。
    3.2 检测器:在图像分析系统中,目标检测器的作用是通过建立统一的目标定位与跟踪模型来实现对特定场景下物体的存在状态进行实时感知与判断的过程。目前主流的目标检测算法主要包括区域卷积神经网络(R-CNN)、快速区域卷积神经网络(Fast R-CNN)、超快区域卷积神经网络(Faster R-CNN)等高效精确的目标定位算法体系

4.具体代码实例和解释说明

本节深入介绍无人驾驶系统中计算机视觉技术的具体代码实现,并对其运行逻辑进行详细解析

  1. 边缘检测
复制代码
    import cv2
    import numpy as np
    # Read the test image 
    # Convert the image to gray scale
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # Apply Gaussian blurring
    blur = cv2.GaussianBlur(gray,(3,3),0)
    # Apply Canny edge detection algorithm
    canny = cv2.Canny(blur,100,200)
    # Show the resulting edges
    cv2.imshow("Edges",canny)
    cv2.waitKey()
    
    
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读
  1. 车牌检测
复制代码
    import cv2
    import numpy as np
    def detect_car_number(img):
      '''
      Detect and locate the number of a car plate image.
      :param img: numpy array, the input image
      :return: list, a list of tuples (x, y, w, h), where x is the left top point's x value,
          y is the left top point's y value, w is width, and h is height, representing the bounding box
          of each character in the detected characters' images.
      '''
      
      # Step 1: Preprocessing the image
      gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
      ret, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
      bg_mask = cv2.dilate(binary,np.ones((5,11)),iterations = 2)
      
      # Step 2: Finding the region of interest
      cnts,_ = cv2.findContours(bg_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
      areas = [cv2.contourArea(c) for c in cnts]
      max_index = np.argmax(areas)
      x,y,w,h = cv2.boundingRect(cnts[max_index])
      rect = cv2.minAreaRect(cnts[max_index])
      angle = int(rect[-1])
      img_rotated = ndimage.rotate(img,angle)
      
      rows,cols,chans = img_rotated.shape
      M = cv2.getRotationMatrix2D((cols/2,rows/2),angle,1)
      dst = cv2.warpAffine(img_rotated,M,(cols,rows))
      dst = dst[int(y):int(y+h),int(x):int(x+w)]
      
      # Step 3: Splitting the characters into different regions
      chars = []
      kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 2))
      char_imgs = cv2.dilate(dst, kernel, iterations=2)
      bw = cv2.cvtColor(char_imgs, cv2.COLOR_BGR2GRAY)
      _, bw = cv2.threshold(bw, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
      im2, contours, hierarchy = cv2.findContours(bw, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
      for c in sorted(contours, key=cv2.contourArea, reverse=True)[:10]:
      x,y,w,h = cv2.boundingRect(c)
      
      if abs(w/float(h)-3)>0.1 or h<15: 
          continue 
      if cv2.contourArea(c)<50: 
          continue
          
      roi = bw[y:y+h, x:x+w]
      hsv_roi = cv2.cvtColor(roi, cv2.COLOR_GRAY2BGR)
      color_min = np.array([20, 100, 50])
      color_max = np.array([60, 255, 255])
      mask = cv2.inRange(hsv_roi, color_min, color_max)
      
      # If there is no pixel within range, ignore this character
      if not cv2.countNonZero(mask)==0:
          chars.append((x,y,w,h))
          
      # Step 4: Stitching back the characters together 
      n_chars = len(chars)
      ratio = float(n_chars)/float(img.shape[1])
      w_total = sum([i[2] for i in chars])
      h_max = max([i[3] for i in chars])
      res = np.zeros((h_max*ratio,w_total,3)).astype(np.uint8)
      start_x = 0
      end_x = 0
      for idx,c in enumerate(chars):
      x,y,w,h = c
      roi = dst[y:y+h, x:x+w].copy()
      hsv_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
      color_min = np.array([20, 100, 50])
      color_max = np.array([60, 255, 255])
      mask = cv2.inRange(hsv_roi, color_min, color_max)
      roi[:, :, 2][mask == 0] = 0
       if idx==0:
          res[:,start_x:end_x,:] = cv2.resize(roi,(1,res.shape[1]),interpolation = cv2.INTER_LINEAR)
      elif idx==(len(chars)-1):
          pad = (w_total - (idx*(res.shape[1]/n_chars)))//2
          tmp = cv2.resize(roi,(pad+(res.shape[1]-pad-(idx-1)*(res.shape[1]/n_chars)),1),interpolation = cv2.INTER_LINEAR)
          res[:,end_x:,:] = np.concatenate((tmp,res[:,end_x:,:]))
      else:
          pad = (w_total - ((idx+1)*res.shape[1]/n_chars))/2
          tmp = cv2.resize(roi,(pad+(res.shape[1]-pad-(idx-1)*(res.shape[1]/n_chars)),1),interpolation = cv2.INTER_LINEAR)
          res[:,end_x:(end_x+tmp.shape[1]),:] = tmp.T
          end_x += tmp.shape[1]
              
      return [(int(p[0]*ratio)+x, int(p[1]*ratio)+y, int(p[2]*ratio), int(p[3]*ratio)) for p in chars]
    # Test on an example image
    cars = detect_car_number(img)
    for c in cars:
      cv2.rectangle(img,tuple(c[:2]), tuple(map(lambda x:x+c[2],c[:2])), (0,255,0), 2)
    cv2.imshow("Detected Car Number",img)
    cv2.waitKey()
    
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读
  1. 对象检测
复制代码
    import cv2
    import numpy as np
    # Load the pre-trained model
    net = cv2.dnn.readNetFromDarknet('yolov3.cfg', 'yolov3.weights')
    # Specify target device
    net.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV)
    net.setPreferableTarget(cv2.dnn.DNN_TARGET_CPU)
    def detect_objects(frame):
      '''
      Detect objects in the given frame using YOLOv3 neural network.
      :param frame: numpy array, the input frame
      :return: list, a list of lists [[class index, score, bbox],...], where class index is the integer index
          of the object category, score is the probability of the prediction being correct, and bbox is the
          bounding box coordinates represented by two corner points (x1,y1,x2,y2).
      '''
      blob = cv2.dnn.blobFromImage(frame, 1/255., (416, 416), swapRB=True, crop=False)
      net.setInput(blob)
      layerNames = net.getLayerNames()
      outputLayers = [layerNames[i[0]-1] for i in net.getUnconnectedOutLayers()]
      outputs = net.forward(outputLayers)
      
      classIds = []
      confidences = []
      boxes = []
      conf_threshold = 0.5
      nms_threshold = 0.4
      
      for out in outputs:
      for detection in out:
          scores = detection[5:]
          classId = np.argmax(scores)
          confidence = scores[classId]
          if confidence > conf_threshold:
              center_x = int(detection[0]*frame.shape[1])
              center_y = int(detection[1]*frame.shape[0])
              w = int(detection[2]*frame.shape[1])
              h = int(detection[3]*frame.shape[0])
              x = int(center_x - w/2)
              y = int(center_y - h/2)
              classIds.append(classId)
              confidences.append(float(confidence))
              boxes.append([x, y, w, h])
      indices = cv2.dnn.NMSBoxes(boxes, confidences, conf_threshold, nms_threshold)
      
      result = []
      for i in indices:
      i = i[0]
      box = boxes[i]
      label = str(classes[classIds[i]])
      score = confidences[i]
      xmin, ymin = box[0], box[1]
      xmax, ymax = xmin + box[2], ymin + box[3]
      result.append([[label,score,[xmin,ymin,xmax,ymax]]])
      
      return result
    classes = ["person","bicycle","car","motorbike","aeroplane","bus","train","truck","boat","traffic light","fire hydrant","stop sign"]
    # Test on an example video clip
    cap = cv2.VideoCapture('video.mp4')
    while True:
      ret, frame = cap.read()
      if not ret:
      break
      objects = detect_objects(frame)
      print(objects)
      cv2.imshow("Frame",frame)
      cv2.waitKey(10)
    cap.release()
    cv2.destroyAllWindows()
    
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读

5.未来发展趋势与挑战

该领域的技术发展势头依然强劲,并伴随着越来越多的技术要素逐步融入其中。随着无人驾驶汽车相关技术取得突破性进展,在多个新兴领域中应用该技术将带来新的机遇。目前,在这个研究领域仍处于起步阶段,在全球范围内正掀起一股研究热潮。尽管当前仍处在实验初期阶段,在未来的发展过程中仍有许多探索的空间和发展路径待确定。展望未来,在多个方面上推进该领域的进步将是主要方向:一方面将致力于提高算法精度;另一方面则会减少计算资源的需求;再一方面则会提升处理效率;此外还将寻求降低云端存储的成本;最后则会优化无人机系统的运行效率;同时还需要进一步增强系统的能力包括路径规划、语音交互等。

全部评论 (0)

还没有任何评论哟~