【OpenCV-python】颜色检测

<链接>:point_left:这个帖子里介绍了怎么读取摄像头,并显示到qt窗口上。

这里在他的基础上,加入颜色检测功能,将图像中所有蓝色的东西都用一个框标记出来

颜色检测核心api介绍

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

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)

基本测试代码

blue_detect.rar (2.8 KB)

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)
                
                # 按比例缩放
                h, w, ch = rgbImage.shape
                aspect_ratio = w / h
                new_width = self.label.width()
                new_height = int(new_width / aspect_ratio)
                if new_height > self.label.height():
                    new_height = self.label.height()
                    new_width = int(new_height * aspect_ratio)
                rgbImage = cv2.resize(rgbImage, (new_width, new_height))
                
                # 显示到label
                bytesPerLine = ch * new_width
                self.signal_update_label.emit(QPixmap.fromImage(QImage(rgbImage.data, new_width, new_height, bytesPerLine, QImage.Format_RGB888)))
            else :
                print("cap read error")
                return

class WINDOW(QMainWindow):
    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.close()
    def paintEvent(self,event):
        new_width = int(window.width()/10*8)
        new_height = int(window.height()/10*8)
        lab_x = int((window.width() - new_width) / 2)
        lab_y = int((window.height() - new_height) / 2)
        ui.label.setGeometry( lab_x, lab_y, new_width, new_height)


import sys
app = QApplication(sys.argv)
window = WINDOW()
ui = Ui_MainWindow()
ui.setupUi(window)
window.showFullScreen() #全屏显示
# window.show() #按绘制时的尺寸显示

# 创建读取摄像头并显示的线程
work = Work()
work.label = ui.label
work.start()

sys.exit(app.exec_())

再分享一个代码

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

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

(不介绍具体写法了,直接给个代码吧,有问题去群里问吧)

hsv_detect.rar (5.6 KB)

1 Like