导航

    全志在线开发者论坛

    • 注册
    • 登录
    • 搜索
    • 版块
    • 话题
    • 在线文档
    • 社区主页

    在核桃派上实现USB摄像头的OpenCV颜色检测

    H/F/TV Series
    1
    1
    1186
    正在加载更多帖子
    • 从旧到新
    • 从新到旧
    • 最多赞同
    回复
    • 在新帖中回复
    登录后回复
    此主题已被删除。只有拥有主题管理权限的用户可以查看。
    • livpo
      livpo LV 6 最后由 编辑

      在给核桃派开发板用OpenCV读取图像并显示到pyqt5的窗口上并加入颜色检测功能,尝试将图像中所有蓝色的东西都用一个框标记出来。

      3fa3e94a2f7991df84a9650d37e153cf0a2049d2.png

      颜色检测核心api

      按照惯例,先要介绍一下opencv中常用的hsv像素格式。颜色还是那个颜色,只是描述颜色用的参数变了。h代表色调,s代表饱和度,v代表明度,比使用rgb格式更方便计算与思考。

      e75c63555c89991ebc679bcc64b2d04e0771f8d6.png

      opencv中也提供了将rgb bgr等转为hsv图片的api:

      hsvImage  = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
      

      cv2.inRange,给定一个要检测的hsv颜色范围,返回一张黑白图。将hsv值在该范围内的像素点全部变为白色,不在的则为黑色。

      import numpy as np
      hsv_upper=np.array([125, 250, 250])
      hsv_lower=np.array([95, 40, 40])
      grayImage = cv2.inRange(hsvImage, hsv_lower, hsv_upper) # 颜色二值化
      

      findContours,传入黑白图像,寻找所有轮廓。返回两个列表,contours里是找到的所有轮廓,hierarchy是那些轮廓之间的相对位置关系

      contours, hierarchy = cv2.findContours(grayImage, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
      

      minAreaRect,传入一个轮廓,计算最小外接矩形

      # 画最小外接矩形
      for cts in contours :
          rect = cv2.minAreaRect(cts)
      

      drawContours, 绘制轮廓

      box = np.int0(cv2.boxPoints(rect)) 
          cv2.drawContours(rgbImage, [box], 0, (255, 0, 0), 2)
      

      基本测试代码

      3fa3e94a2f7991df84a9650d37e153cf0a2049d2 (1).png

      
      import cv2
      from  ui_main import Ui_MainWindow
      import numpy as np
      
      import PyQt5
      from PyQt5.QtCore import *
      from PyQt5.QtGui import *
      from PyQt5.QtWidgets import *
      
      # 修正qt的plugin路径,因为某些程序(cv2)会将其改到其他路径
      import os
      os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = os.path.dirname(PyQt5.__file__)
      
      
      #【可选代码】允许Thonny远程运行
      import os
      os.environ["DISPLAY"] = ":0.0"
      
      #【建议代码】允许终端通过ctrl+c中断窗口,方便调试
      import signal
      signal.signal(signal.SIGINT, signal.SIG_DFL)
      timer = QTimer()
      timer.start(100)  # You may change this if you wish.
      timer.timeout.connect(lambda: None)  # Let the interpreter run each 100 ms
      
      # 线程类
      class Work(QThread):
          signal_update_label = pyqtSignal(QPixmap)
          label:QLabel
          def sloat_update_label( self, pixmap:QPixmap):
              self.label.setPixmap(pixmap)
      
          def run(self):
              print("label.width()=", self.label.width())
              print("label.height()=", self.label.height())
              self.signal_update_label.connect(self.sloat_update_label)
              cap = cv2.VideoCapture(1)
              while True:
                  ret, frame = cap.read()
                  if ret:
      
                      # 颜色转换
                      rgbImage = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                      hsvImage  = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
                      
                      # 二值化
                      hsv_upper=np.array([125, 250, 250])
                      hsv_lower=np.array([95, 40, 40])
                      grayImage = cv2.inRange(hsvImage, hsv_lower, hsv_upper) # 颜色二值化
      
                      # 查找并绘制最小外接矩形
                      contours, hierarchy = cv2.findContours(grayImage, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
                      for cts in contours :
                          rect = cv2.minAreaRect(cts)  
                          box = np.int0(cv2.boxPoints(rect)) 
                          cv2.drawContours(rgbImage, [box], 0, (255, 0, 0), 2)
      

      由于摄像头拍出来的噪点很多,而物体由于本身材质反光导致拍出来也有一些部分的颜色变了。所以实际应用时需要对图像进行一些滤波模糊化处理。或是直接对生成后的黑白图像进行一定膨胀与收缩。

      0653b67aed75179c07b5bfe12a9c957c02688bfa.png

      再把各个参数做成pyqt窗口的选项,查看各项搭配后的效果,快速找到合适的参数选择。

      # 图像缩小并转换颜色格式
      frame = cv2.resize(frame, (320, 240))
      rgbImage = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
      h, w, ch = rgbImage.shape
      
      # 图像模糊
      if self.blur.flag :
        rgbImage = cv2.blur(rgbImage,(self.blur.num, self.blur.num))
      if self.median.flag :
        rgbImage = cv2.medianBlur(rgbImage,self.median.num)
      if self.gaussian.flag :
        rgbImage = cv2.GaussianBlur(rgbImage, (self.gaussian.num, self.gaussian.num), 0)
      
      # 二值化
      hsvImage = cv2.cvtColor(rgbImage, cv2.COLOR_RGB2HSV)
      grayImage = cv2.inRange(hsvImage, np.array([self.hl.num, self.sl.num, self.vl.num]), np.array([self.hu.num, self.su.num, self.vu.num])) # 颜色二值化
                      
      # 图像操作
      if self.dilate.flag :
        grayImage = cv2.dilate(grayImage, np.ones((self.dilate.num, self.dilate.num), dtype=np.uint8), 1) # 膨胀
      if self.erode.flag :
        grayImage = cv2.erode(grayImage, np.ones((self.erode.num, self.erode.num), dtype=np.uint8), 1)  # 腐蚀
      
      # 获取中心点的颜色,画上十字光标
      height, width = rgbImage.shape[:2]
      center_y, center_x = height // 2, width // 2
      color = tuple(map(int, rgbImage[center_y, center_x, :]))
      cv2.line(rgbImage, (center_x, 0), (center_x, height-1), color, 3)
      cv2.line(rgbImage, (0, center_y), (width-1, center_y), color, 3)
      
      contours, hierarchy = cv2.findContours(grayImage, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
      

      本文内容转载自:https://forum.walnutpi.com/t/topic/88

      1 条回复 最后回复 回复 引用 分享 0
      • 1 / 1
      • First post
        Last post

      Copyright © 2024 深圳全志在线有限公司 粤ICP备2021084185号 粤公网安备44030502007680号

      行为准则 | 用户协议 | 隐私权政策