• 免费好用的星瞳AI云服务上线!简单标注,云端训练,支持OpenMV H7和OpenMV H7 Plus。可以替代edge impulse。 https://forum.singtown.com/topic/9519
  • 我们只解决官方正版的OpenMV的问题(STM32),其他的分支有很多兼容问题,我们无法解决。
  • 如果有产品硬件故障问题,比如无法开机,论坛很难解决。可以直接找售后维修
  • 发帖子之前,请确认看过所有的视频教程,https://singtown.com/learn/ 和所有的上手教程http://book.openmv.cc/
  • 每一个新的提问,单独发一个新帖子
  • 帖子需要目的,你要做什么?
  • 如果涉及代码,需要报错提示全部代码文本,请注意不要贴代码图片
  • 必看:玩转星瞳论坛了解一下图片上传,代码格式等问题。
  • 关于OpenMV 与 msp432 串口通信的问题。



    • 我写了一个关于OpenMV寻线的Python程序,想要通过串口把OpenMv获取到的数据(线的类型,坐标)发送给MSP432,再通过串口助手显示MSP432接收到的数据。但是我不知道OpenMV发送的数据的数据类型,导致我不知道如何将MSP432接收到的数据在串口助手显示。
      下面是我OpenMV的程序:
      import sensor, image, time
      import network, usocket, sys
      import sensor, image, time, network, usocket, sys
      import math
      from pyb import UART
      from pyb import LED

      WIFI_ENABLE = False
      FIND_APRITAG_ENABLE = True

      LED灯定义

      red_led = LED(1)
      green_led = LED(2)
      blue_led = LED(3)

      宏定义区

      GRAYSCALE_THRESHOLD = [(0, 90)] # 灰度阈值
      MIN_PIXELS = 100 # 最小像素
      width = 80 # 宽度
      height = 60 # 高度
      RectHeight = 10 # 矩形高度
      MAX_PIXEL = 200 # 最大像素

      直线阈值定义

      Line_Thr = 1000 # 线路宽度
      Line_Theta_margin = 25 # 折线图
      Line_Margin = 25 # 行距
      Line_Min_degree = 0 # 两线最小夹角
      Line_Max_degree = 179 # 两线最大夹角

      感兴趣区域定义

      Roi_Top = (0, 0, width, RectHeight)
      Roi_Botton = (0, height - RectHeight, width, RectHeight)
      Roi_Left = (0, 0, RectHeight, height)
      Roi_Right = (width - RectHeight, 0, RectHeight, height)
      Rois = [Roi_Top,Roi_Botton,Roi_Left,Roi_Right]

      直线阈值定义

      right_angle_threshold = (70, 90) # 直角阈值
      Line_Thr = 2000
      Line_Theta_margin = 25
      Line_Margin = 25
      Line_Min_degree = 0
      Line_Max_degree = 179

      def find_all_Line(img):
      Line_All = img.find_lines(threshold = Line_Thr, theta_margin = Line_Theta_margin, rho_margin = Line_Margin)
      return Line_All

      From:http://makermare.com:60010//example/feature/right-angle-detection.html

      def calculate_angle(line1, line2):
      # 利用四边形的角公式, 计算出直线夹角
      angle = (180 - abs(line1.theta() - line2.theta()))
      if angle > 90:
      angle = 180 - angle
      return angle

      def is_right_angle(line1, line2):
      global right_angle_threshold
      # 判断两个直线之间的夹角是否为直角
      angle = calculate_angle(line1, line2)

      if angle >= right_angle_threshold[0] and angle <=  right_angle_threshold[1]:
          # 判断在阈值范围内
          return True
      return False
      

      def calculate_intersection(line1, line2):
      # 计算两条线的交点
      a1 = line1.y2() - line1.y1()
      b1 = line1.x1() - line1.x2()
      c1 = line1.x2()*line1.y1() - line1.x1()*line1.y2()

      a2 = line2.y2() - line2.y1()
      b2 = line2.x1() - line2.x2()
      c2 = line2.x2() * line2.y1() - line2.x1()*line2.y2()
      
      if (a1 * b2 - a2 * b1) != 0 and (a2 * b1 - a1 * b2) != 0:
          cross_x = int((b1*c2-b2*c1)/(a1*b2-a2*b1))
          cross_y = int((c1*a2-c2*a1)/(a1*b2-a2*b1))
          return (cross_x, cross_y)
      return (-1, -1)
      

      此函数将所看到的线条整理成一个点或直线信息

      def line_info_process(lines):
      Cross_X = -1
      Cross_Y = -1
      line_info_list = [0,0,0,0,0,0,0]
      line_info_list[0] = -1

      # 如果有两条直线,此处不严谨,应该多判定两条直线
      if len(lines) == 2:
          if is_right_angle(lines[0],lines[1]):
              Cross_X , Cross_Y = calculate_intersection(lines[0],lines[1])
              line_info_list[0] = 0
              line_info_list[1] = Cross_X
              line_info_list[2] = Cross_Y
      
      
      # 如果有一条直线
      if len(lines) == 1:
          if (lines[0].x1() == 0 and lines[0].x2() == 79) or (lines[0].x2() == 0 and lines[0].x1() == 79):
              # 横线
              line_info_list[0] = 1
              line_info_list[1] = lines[0].y1()
              line_info_list[2] = lines[0].y2()
              pass
          if (lines[0].y1() == 0 and lines[0].y2() == 59) or (lines[0].y2() == 0 and lines[0].y1() == 59):
              line_info_list[0] = 2
              line_info_list[1] = lines[0].x1()
              line_info_list[2] = lines[0].x2()
              pass
      
      return line_info_list
      

      def ExceptionVar(var):
      data = []
      data.append(0)
      data.append(0)

      if var == -1:
          data[0] = 0
          data[1] = 0
      else:
          data[0] = var & 0xFF
          data[1] = var >> 8
      return data
      

      def ProcessImg(img):
      Blobs = []

      TopBlobs = img.find_blobs(GRAYSCALE_THRESHOLD, roi = Roi_Top[0:4], merge=True)
      BottonBlobs = img.find_blobs(GRAYSCALE_THRESHOLD, roi = Roi_Botton[0:4], merge=True)
      LeftBlobs = img.find_blobs(GRAYSCALE_THRESHOLD, roi = Roi_Left[0:4], merge=True)
      RightBlobs = img.find_blobs(GRAYSCALE_THRESHOLD, roi = Roi_Right[0:4], merge=True)
      
      
      Blobs.append(TopBlobs)
      Blobs.append(BottonBlobs)
      Blobs.append(LeftBlobs)
      Blobs.append(RightBlobs)
      
      return Blobs
      

      def CalcVerticalCross(x0,y0,x1,y1,x2,y2):
      if y1 != y0:
      k1 = (y1 - y0)/(x1-x0)
      k2 = -1/k1
      x = (-k1x0 + y0 +x2k2 - y2)/(k2 - k1)
      y = k1 * x - k1*x0 + y0
      return x,y
      else:
      return x2,y1

      def CalcCross(x0,y0,x1,y1,x2,y2,x3,y3):
      # 计算两条线的交点
      a1 = y1 - y0
      b1 = x0 - x1
      c1 = x1y0 - x0y1

      a2 = y3 - y2
      b2 = x2 - x3
      c2 = x3 * y2 - x2*y3
      
      if (a1 * b2 - a2 * b1) != 0 and (a2 * b1 - a1 * b2) != 0:
          cross_x = int((b1*c2-b2*c1)/(a1*b2-a2*b1))
          cross_y = int((c1*a2-c2*a1)/(a1*b2-a2*b1))
          return (cross_x, cross_y)
      return (-1, -1)
      

      def FindMaxBlobs(BlobList):
      most_pixels = 0
      largest_blob = 0
      if BlobList:
      for i in range(len(BlobList)):
      if BlobList[i].pixels() > most_pixels:
      most_pixels = BlobList[i].pixels()
      largest_blob = i
      return BlobList[largest_blob]
      return None

      def GetRectMoreInfo_V(Rect):
      x0 = Rect.x() + Rect.w()/2
      y0 = Rect.y()
      x1 = Rect.x() + Rect.w()/2
      y1 = Rect.y() + Rect.h()
      return x0,x1,y0,y1
      pass

      def GetRectMoreInfo_H(Rect):
      x0 = Rect.x() + Rect.w()/2
      y0 = Rect.y()
      x1 = Rect.x() + Rect.w()/2
      y1 = Rect.y() + Rect.h()
      return x0,x1,y0,y1
      pass

      def GetLtype(x0):

      pass
      

      BlobLocation = [[0, 0], [0, 0], [0, 0], [0, 0]]
      Blobs = []
      def RecognitionForm(Blobs,img):
      Top = 0
      Botton = 1
      Left = 2
      Right = 3
      cx = 0
      cy = 1
      MAX_WITH = 20
      MIN_WITH = 6
      MIN_HIGH = 6
      MAX_HIGH = 20

      FormType = 0xFF
      Loaction0 = 0
      Location1 = 0
      
      TopValid = False
      BottonValid = False
      LeftValid = False
      RightValid = False
      
      TopBlob = FindMaxBlobs(Blobs[0])
      BottonBlob = FindMaxBlobs(Blobs[1])
      LeftBlob = FindMaxBlobs(Blobs[2])
      RightBlob = FindMaxBlobs(Blobs[3])
      
      if TopBlob:
          if TopBlob.w() < MAX_WITH and TopBlob.h() > MIN_HIGH:
              BlobLocation[Top][cx] = TopBlob.cx()
              BlobLocation[Top][cy] = TopBlob.cy()
              img.draw_rectangle(TopBlob.rect())
              img.draw_cross(BlobLocation[Top][cx],BlobLocation[Top][cy])
          else:
              TopBlob = None
      
      if BottonBlob:
          if BottonBlob.w() < MAX_WITH and BottonBlob.h() > MIN_HIGH:
              BlobLocation[Botton][cx] = BottonBlob.cx()
              BlobLocation[Botton][cy] = BottonBlob.cy()
              img.draw_rectangle(BottonBlob.rect())
              img.draw_cross(BlobLocation[Botton][cx],BlobLocation[Botton][cy])
          else:
              BottonBlob = None
              pass
      
      if LeftBlob:
          if LeftBlob.w() > MIN_WITH and LeftBlob.h() < MAX_HIGH and LeftBlob.h() > MIN_HIGH:
              BlobLocation[Left][cx] = LeftBlob.cx()
              BlobLocation[Left][cy] = LeftBlob.cy()
              img.draw_rectangle(LeftBlob.rect())
              img.draw_cross(BlobLocation[Left][cx],BlobLocation[Left][cy])
          else:
              LeftBlob = None
      
      if RightBlob:
          if RightBlob.w() > MIN_WITH and RightBlob.h() < MAX_HIGH and RightBlob.h() > MIN_HIGH:
      
              BlobLocation[Right][cx] = RightBlob.cx()
              BlobLocation[Right][cy] = RightBlob.cy()
              img.draw_rectangle(RightBlob.rect())
              img.draw_cross(BlobLocation[Right][cx],BlobLocation[Right][cy])
          else:
              RightBlob = None
      
      if TopBlob:
          TopValid = True
      if BottonBlob:
          BottonValid = True
      if LeftBlob:
          LeftValid = True
      if RightBlob:
          RightValid = True
      
      # 竖线
      if TopValid and BottonValid and (not LeftValid) and (not RightValid):
          Loaction0 = (BlobLocation[Top][cx] + BlobLocation[Botton][cx])//2
          Location1 = BlobLocation[Botton][cy]//2
          FormType = 0
      
      # 横线
      if (not TopValid) and (not BottonValid) and LeftValid and RightValid:
          Loaction0 = BlobLocation[Right][cx]//2
          Location1 = (BlobLocation[Left][cy] + BlobLocation[Right][cy])//2
          FormType = 1
      
      # 十字
      if TopValid and BottonValid and LeftValid and RightValid:
          (Loaction0,Location1) = CalcCross(BlobLocation[Left][cx],BlobLocation[Left][cy],
                                            BlobLocation[Right][cx],BlobLocation[Right][cy],
                                            BlobLocation[Top][cx],BlobLocation[Top][cy],
                                            BlobLocation[Botton][cx],BlobLocation[Botton][cy])
      
          FormType = 2
      
      # T字型
      if (not TopValid) and BottonValid and LeftValid and RightValid:
          x,y = CalcVerticalCross(BlobLocation[Left][cx],BlobLocation[Left][cy],
                                  BlobLocation[Right][cx],BlobLocation[Right][cy],
                                  BlobLocation[Botton][cx],BlobLocation[Botton][cy])
          # print(BlobLocation[Left][cx],BlobLocation[Right][cx],BlobLocation[Botton][cx])
          Loaction0 = int(x)
          Location1 = int(y)
          FormType = 3
      
      # 倒T字型
      if (TopValid) and (not BottonValid) and LeftValid and RightValid:
          x,y = CalcVerticalCross(BlobLocation[Left][cx],BlobLocation[Left][cy],
                                  BlobLocation[Right][cx],BlobLocation[Right][cy],
                                  BlobLocation[Top][cx],BlobLocation[Top][cy])
          Loaction0 = int(x)
          Location1 = int(y)
      
          FormType = 4
      
      # 粗略的检测,对YAW值要求严格
      # L字形
      if  TopValid and (not BottonValid) and (not LeftValid) and RightValid:
          FormType = 5
          return FormType,BlobLocation[Top][cx],BlobLocation[Right][cy]
      
      #    |
      #    |
      # ___|  字形
      if TopValid and (not BottonValid) and ( LeftValid) and (not RightValid):
          FormType = 6
          return FormType,BlobLocation[Top][cx],BlobLocation[Left][cy]
          pass
      
      #    ____
      #    |
      #    |  字形
      #    |
      if not TopValid and (BottonValid) and (not LeftValid) and (RightValid):
          FormType = 7
          return FormType,BlobLocation[Botton][cx],BlobLocation[Right][cy]
      
      
      #    ____
      #       |
      #       |  字形
      #       |
      if not TopValid and ( BottonValid) and ( LeftValid) and (not RightValid):
          FormType = 8
          return FormType,BlobLocation[Botton][cx],BlobLocation[Left][cy]
          pass
      
      #       |
      #  _____|
      #       |  字形
      #       |
      if ( TopValid) and ( BottonValid) and ( LeftValid) and (not RightValid):
          FormType = 9
          return FormType,BlobLocation[Top][cx],BlobLocation[Botton][cx],BlobLocation[Right][cy]
      
      #  |
      #  |_____
      #  |       字形
      #  |
      if ( TopValid) and ( BottonValid) and (not LeftValid) and ( RightValid):
          FormType = 10
          return FormType,BlobLocation[Top][cx],BlobLocation[Botton][cx]#,BlobLocation[Right][cy]
      
      
      return FormType,Loaction0,Location1
      

      寻找Apriltags

      def Find_Apriltags(img):
      X = -1
      Y = -1
      FormType = 0xff
      for tag in img.find_apriltags(families=image.TAG16H5):
      img.draw_rectangle(tag.rect(), color = (255, 0, 0)) #在图像上绘制一个矩形。
      img.draw_cross(tag.cx(), tag.cy(), color = (0, 255, 0)) #在图像上绘制一个十字
      X = tag.cx() #
      Y = tag.cy() #
      FormType = 100
      return FormType,X,Y

      def IS_FindApriTag(img):
      GetApriTag = False

      for tag in img.find_apriltags(families=image.TAG16H5):
          GetApriTag = True
      
      return GetApriTag
      

      Frame_Cnt = 0
      fCnt_tmp = [0,0]
      def UART_Send(FormType, Loaction0, Location1):
      global Frame_Cnt
      global fCnt_tmp
      Frame_Head = [170,170]
      Frame_End = [85,85]
      fFormType_tmp = [FormType]
      Frame_Cnt += 1

      if Frame_Cnt > 65534 :
          FrameCnt = 0
      
      fHead = bytes(Frame_Head)
      
      fCnt_tmp[0] = Frame_Cnt & 0xFF
      fCnt_tmp[1] = Frame_Cnt >> 8
      fCnt = bytes(fCnt_tmp)
      
      fFormType = bytes(fFormType_tmp)
      fLoaction0 = bytes(ExceptionVar(Loaction0))
      fLoaction1 = bytes(ExceptionVar(Location1))
      fEnd = bytes(Frame_End)
      

      OpenMV串口发送的数据结构

      FrameBuffe = fHead + fCnt + fFormType + fLoaction0 + fLoaction1 + fEnd
      return FrameBuffe
      

      sensor.reset() # 初始化相机传感器Initialize the camera sensor.
      #sensor.set_vflip(True)
      sensor.set_pixformat(sensor.GRAYSCALE) # 使用灰度use grayscale.
      sensor.set_framesize(sensor.QQVGA) # 使用QVGA获得速度use QVGA for speed. 80 * 60
      sensor.skip_frames(30) # 让新设置生效Let new settings take affect.
      sensor.set_auto_gain(False) # 必须关闭才能进行颜色跟踪must be turned off for color tracking
      sensor.set_auto_whitebal(False) # must be turned off for color tracking
      uart = UART(3, 115200, timeout_char = 1000)
      clock = time.clock()
      i = 0

      WIFI调试配置

      SSID ='OPENMV_AP' # Network SSID网络名称
      KEY ='1234567890' # Network key (must be 10 chars)网络密钥(必须是10个字符)
      HOST = '' # Use first available interface使用第一个可用界面
      PORT = 8080 # Arbitrary non-privileged port任意非特权端口

      Init wlan module in AP mode.

      THRESHOLD = (0, 100) # 暗物质的灰度阈值
      BINARY_VISIBLE = True # 首先是二进制,所以你可以看到正在运行的线性回归...可能会降低FPS。

      CountDown = 100
      Find_ApriTag_ENABLE = False # 寻找ApriTag
      Find_Line_ENABLE = False # 找线
      while(True):
      CountDown -= 1
      img = sensor.snapshot() # 获取图像
      #sensor.snapshot()-使用相机拍摄一张照片,并返回image对象
      (Type,P0,P1) = Find_Apriltags(img)

      if Type == 100:
          Find_ApriTag_ENABLE = True
          Find_Line_ENABLE = False
          break
      else:
          Find_Line_ENABLE = True
          Find_ApriTag_ENABLE = False
      
      if CountDown <= 0:
          red_led.off()
          green_led.off()
          break
      
      i+=1
      if i % 5 == 0:
          green_led.on()
          red_led.on()
      if i % 10 == 0:
          green_led.off()
          red_led.off()
      pass
      

      if Find_Line_ENABLE:
      sensor.reset() # Initialize the camera sensor.
      #sensor.set_vflip(True)
      sensor.set_pixformat(sensor.GRAYSCALE) # use grayscale.
      sensor.set_framesize(sensor.QQQVGA) # use QVGA for speed. 80 * 60
      sensor.skip_frames(30) # Let new settings take affect.
      sensor.set_auto_gain(False) # must be turned off for color tracking
      sensor.set_auto_whitebal(False)

      while(True):
      img = sensor.snapshot()

      if Find_Line_ENABLE:
          All_Line = find_all_Line(img)
          Line_Info = line_info_process(All_Line)
      
          (Type,P0,P1) = RecognitionForm(ProcessImg(img),img)
      
          if Line_Info[0] == 0:
              img.draw_circle(Line_Info[1],Line_Info[2], 3, color = 200, thickness = 2, fill = False)
          if All_Line:
              for ii in All_Line:
                  img.draw_line(ii.line())
      
      if Find_ApriTag_ENABLE:
          (Type,P0,P1) = Find_Apriltags(img)
          pass
      
      print(Type,P0,P1)
      uart.write(UART_Send(Type,P0,P1))
      
      i+=1
      if i % 5 == 0:
          if Find_ApriTag_ENABLE:
              green_led.on()
          else:
              red_led.on()
      if i % 10 == 0:
          if Find_ApriTag_ENABLE:
              green_led.off()
          else:
              red_led.off()
      




    • OpenMV可以用其他串口助手吧?



    • @zgir 串口助手都一样,但是推荐使用星瞳串口助手。