树莓派视觉小车 -- 小球追踪(颜色追踪)(OpenCV色彩空间HSV)

2023-11-20

目录

效果展示 

基础理论(HSV)

为什么用HSV空间而不是RGB空间?

HSV

1、Hue(色相)

2、Value(明度)

3、Saturation(饱和度)

一、初始化

滑动条初始化

1、创建回调函数

2、窗口设置(名称) 

3、滑动条设置

代码

二、运动函数

三、舵机控制

四、在HSV空间下获取二值图

1、获取滑动条的值

2、转HSV(三通道:H、S、V)

3、转二值图(单通道阈值处理)

4、结合HSV三个通道,得到最终二值图

代码

五、图像处理(总)

1、打开摄像头

2、获取HSV色彩空间得到的二值图

3、高斯滤波

4、开运算去噪

5、闭运算

6、霍夫圆检测

原理

API

 6-1、霍夫圆检测

6-2、获取圆心和半径坐标

6-3、画圆

代码

六、运动控制

总代码


效果展示 

 

 

基础理论(HSV)

为什么用HSV空间而不是RGB空间?

因为RGB通道并不能很好地反映出物体具体的颜色信息

HSV空间能够非常直观的表达色彩的明暗、色调、以及鲜艳程度,方便进行颜色之间的对比。

(RGB受光线影响很大,所以采取HSV

这里用HSV的目的:得到合适的二值图

HSV

 

 

Hue(H):色调、色相(具体的颜色)

Saturation(S):饱和度、色彩纯净度

Value(V):明度

Hue范围是[0,179],饱和范围是[0,255],值范围是[0,255]

(写代码的时候,犯了蠢错误:把3个都设成了179,发现死活调不对)

1、Hue(色相)

Hue:色相(具体的颜色)


2、Value(明度)

明度:色彩的明亮程度,单通道亮度(并不等同于整体发光量)。

(明度越高越白,越低越黑,一般提高明度会同时提高R、G、B三通道的数值)

3、Saturation(饱和度)

Saturation:饱和度、色彩纯度(越低越灰,越高越纯)  。

(一般调高饱和度会降低RGB中相对较低的数值,凸显主要颜色的纯度。 )

B站视频讲解:

短动画慢语速1分钟讲清影视调色中色彩形成原理基础——RGB与HSV

一、初始化

滑动条初始化

这次的初始化,除了电机、舵机、窗口等等的初始化,还有滑动条的初始设置。 

在创建滑动条之前:

1、需要设置窗口名称,不然窗口都没有,自然也就无法设置滑动条了。

2、创建回调函数。

1、创建回调函数

def nothing(*arg):
    pass

2、窗口设置(名称) 

def Trackbar_Init():
    # 1 create windows
    cv2.namedWindow('h_binary')
    cv2.namedWindow('s_binary')
    cv2.namedWindow('v_binary')

3、滑动条设置

# 2 Create Trackbar
    cv2.createTrackbar('hmin', 'h_binary', 6, 179, nothing)  
    cv2.createTrackbar('hmax', 'h_binary', 26, 179, nothing)  
    cv2.createTrackbar('smin', 's_binary', 110, 255, nothing)
    cv2.createTrackbar('smax', 's_binary', 255, 255, nothing)
    cv2.createTrackbar('vmin', 'v_binary', 140, 255, nothing)
    cv2.createTrackbar('vmax', 'v_binary', 255, 255, nothing)
    #   创建滑动条     滑动条值名称 窗口名称   滑动条值 滑动条阈值 回调函数

代码

def Motor_Init():
    global L_Motor, R_Motor
    L_Motor= GPIO.PWM(l_motor,100)
    R_Motor = GPIO.PWM(r_motor,100)
    L_Motor.start(0)
    R_Motor.start(0)


def Direction_Init():
    GPIO.setup(left_back,GPIO.OUT)
    GPIO.setup(left_front,GPIO.OUT)
    GPIO.setup(l_motor,GPIO.OUT)
    
    GPIO.setup(right_front,GPIO.OUT)
    GPIO.setup(right_back,GPIO.OUT)
    GPIO.setup(r_motor,GPIO.OUT)


def Servo_Init():
    global pwm_servo
    pwm_servo=Adafruit_PCA9685.PCA9685()


def Trackbar_Init():
    # 1 create windows
    cv2.namedWindow('h_binary')
    cv2.namedWindow('s_binary')
    cv2.namedWindow('v_binary')
    # 2 Create Trackbar
    cv2.createTrackbar('hmin', 'h_binary', 6, 179, nothing)  
    cv2.createTrackbar('hmax', 'h_binary', 26, 179, nothing)  
    cv2.createTrackbar('smin', 's_binary', 110, 255, nothing)
    cv2.createTrackbar('smax', 's_binary', 255, 255, nothing)
    cv2.createTrackbar('vmin', 'v_binary', 140, 255, nothing)
    cv2.createTrackbar('vmax', 'v_binary', 255, 255, nothing)
    #   创建滑动条     滑动条值名称 窗口名称   滑动条值 滑动条阈值 回调函数


def Init():
    GPIO.setwarnings(False) 
    GPIO.setmode(GPIO.BCM)
    Direction_Init()
    Servo_Init()
    Motor_Init()
    Trackbar_Init()


# 回调函数
def nothing(*arg):
    pass

二、运动函数

常规操作:向前、向后、向左、向右、停止。 

def Front(speed):
    L_Motor.ChangeDutyCycle(speed)
    GPIO.output(left_front,1)   #left_front
    GPIO.output(left_back,0)    #left_back

    R_Motor.ChangeDutyCycle(speed)
    GPIO.output(right_front,1)  #right_front
    GPIO.output(right_back,0)   #right_back
     
    
def Back(speed):
    L_Motor.ChangeDutyCycle(speed)
    GPIO.output(left_front,0)   #left_front
    GPIO.output(left_back,1)    #left_back

    R_Motor.ChangeDutyCycle(speed)
    GPIO.output(right_front,0)  #right_front
    GPIO.output(right_back,1)   #right_back


def Left(speed):
    L_Motor.ChangeDutyCycle(speed)
    GPIO.output(left_front,0)   #left_front
    GPIO.output(left_back,1)    #left_back

    R_Motor.ChangeDutyCycle(speed)
    GPIO.output(right_front,1)  #right_front
    GPIO.output(right_back,0)   #right_back


def Right(speed):
    L_Motor.ChangeDutyCycle(speed)
    GPIO.output(left_front,1)   #left_front
    GPIO.output(left_back,0)    #left_back

    R_Motor.ChangeDutyCycle(speed)
    GPIO.output(right_front,0)  #right_front
    GPIO.output(right_back,1)   #right_back


def Stop():
    L_Motor.ChangeDutyCycle(0)
    GPIO.output(left_front,0)   #left_front
    GPIO.output(left_back,0)    #left_back

    R_Motor.ChangeDutyCycle(0)
    GPIO.output(right_front,0)  #right_front
    GPIO.output(right_back,0)   #right_back    

三、舵机控制

def set_servo_angle(channel,angle):
    angle=4096*((angle*11)+500)/20000
    pwm_servo.set_pwm_freq(50)                #frequency==50Hz (servo)
    pwm_servo.set_pwm(channel,0,int(angle))
set_servo_angle(4, 110)     #top servo     lengthwise
    #0:back    180:front    
    set_servo_angle(5, 90)     #bottom servo  crosswise
    #0:left    180:right  

四、在HSV空间下获取二值图

1、获取滑动条的值

# 1 get trackbar's value
    hmin = cv2.getTrackbarPos('hmin', 'h_binary')
    hmax = cv2.getTrackbarPos('hmax', 'h_binary')
    smin = cv2.getTrackbarPos('smin', 's_binary')
    smax = cv2.getTrackbarPos('smax', 's_binary')
    vmin = cv2.getTrackbarPos('vmin', 'v_binary')
    vmax = cv2.getTrackbarPos('vmax', 'v_binary')

2、转HSV(三通道:H、S、V)

# 2 to HSV
    hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
    cv2.imshow('hsv', hsv)
    h, s, v = cv2.split(hsv)

 

3、转二值图(单通道阈值处理)

分别对H、S、V三个道阈值处理:

# 3 set threshold (binary image)
    # if value in (min, max):white; otherwise:black
    h_binary = cv2.inRange(np.array(h), np.array(hmin), np.array(hmax))
    s_binary = cv2.inRange(np.array(s), np.array(smin), np.array(smax))
    v_binary = cv2.inRange(np.array(v), np.array(vmin), np.array(vmax))

# 5 Show
    cv2.imshow('h_binary', h_binary)
    cv2.imshow('s_binary', s_binary)
    cv2.imshow('v_binary', v_binary)

4、结合HSV三个通道,得到最终二值图

对H、S、V三个通道与操作。(H&&S&&V)

# 4 get binary
    binary = cv2.bitwise_and(h_binary, cv2.bitwise_and(s_binary, v_binary))

代码

# 在HSV色彩空间下得到二值图
def Get_HSV(image):
    # 1 get trackbar's value
    hmin = cv2.getTrackbarPos('hmin', 'h_binary')
    hmax = cv2.getTrackbarPos('hmax', 'h_binary')
    smin = cv2.getTrackbarPos('smin', 's_binary')
    smax = cv2.getTrackbarPos('smax', 's_binary')
    vmin = cv2.getTrackbarPos('vmin', 'v_binary')
    vmax = cv2.getTrackbarPos('vmax', 'v_binary')
    
    # 2 to HSV
    hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
    cv2.imshow('hsv', hsv)
    h, s, v = cv2.split(hsv)
    
    # 3 set threshold (binary image)
    # if value in (min, max):white; otherwise:black
    h_binary = cv2.inRange(np.array(h), np.array(hmin), np.array(hmax))
    s_binary = cv2.inRange(np.array(s), np.array(smin), np.array(smax))
    v_binary = cv2.inRange(np.array(v), np.array(vmin), np.array(vmax))
    
    # 4 get binary(对H、S、V三个通道分别与操作)
    binary = cv2.bitwise_and(h_binary, cv2.bitwise_and(s_binary, v_binary))
    
    # 5 Show
    cv2.imshow('h_binary', h_binary)
    cv2.imshow('s_binary', s_binary)
    cv2.imshow('v_binary', v_binary)
    cv2.imshow('binary', binary)
    
    return binary

五、图像处理(总)

1、打开摄像头

# 1 Capture the frames
    ret, frame = camera.read()
    image = frame
    cv2.imshow('frame', frame)

2、获取HSV色彩空间得到的二值图

(Get_HSV(frame)其实就是步骤四的HSV处理)

# 2 get HSV
    binary = Get_HSV(frame)

3、高斯滤波

# 3 Gausi blur
    blur = cv2.GaussianBlur(binary,(9,9),0)

4、开运算去噪

# 4 Open
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9,9))
    Open = cv2.morphologyEx(blur, cv2.MORPH_OPEN, kernel)
    cv2.imshow('Open',Open)

5、闭运算

# 5 Close
    Close = cv2.morphologyEx(Open, cv2.MORPH_CLOSE, kernel)
    cv2.imshow('Close',Close)

 

6、霍夫圆检测

原理

霍夫变换圆检测是基于图像梯度实现:

圆心检测的原理︰圆心是圆周法线的交汇处设置一个阈值在某点的相交的直线的条数大于这个阈值就认为该交汇点为圆心
圆半径确定原理:圆心到圆周上的距离〔半径)是相同的设置一个阈值只要相同距离的数量大于该阈值就认为该距离是该圆心的半径

API

def HoughCircles(image: Any,
                 method: Any,
                 dp: Any,
                 minDist: Any,
                 circles: Any = None,
                 param1: Any = None,
                 param2: Any = None,
                 minRadius: Any = None,
                 maxRadius: Any = None) -> None

参数: 

  • 第二个参数,int类型的method,即使用的检测方法,目前OpenCV中就霍夫梯度法一种可以使用,它的标识符为CV_HOUGH_GRADIENT,在此参数处填这个标识符即可。
  • 第三个参数,double类型的dp,用来检测圆心的累加器图像的分辨率于输入图像之比的倒数,且此参数允许创建一个比输入图像分辨率低的累加器。上述文字不好理解的话,来看例子吧。例如,如果dp= 1时,累加器和输入图像具有相同的分辨率。如果dp=2,累加器便有输入图像一半那么大的宽度和高度。
  • 第四个参数,double类型的minDist,为霍夫变换检测到的圆的圆心之间的最小距离,即让我们的算法能明显区分的两个不同圆之间的最小距离。这个参数如果太小的话,多个相邻的圆可能被错误地检测成了一个重合的圆。反之,这个参数设置太大的话,某些圆就不能被检测出来了。
  • 第五个参数,InputArray类型的circles,经过调用HoughCircles函数后此参数存储了检测到的圆的输出矢量,每个矢量由包含了3个元素的浮点矢量(x, y, radius)表示。
  • 第六个参数,double类型的param1,有默认值100。它是第三个参数method设置的检测方法的对应的参数。对当前唯一的方法霍夫梯度法CV_HOUGH_GRADIENT,它表示传递给canny边缘检测算子的高阈值,而低阈值为高阈值的一半。
  • 第七个参数,double类型的param2,也有默认值100。它是第三个参数method设置的检测方法的对应的参数。对当前唯一的方法霍夫梯度法CV_HOUGH_GRADIENT,它表示在检测阶段圆心的累加器阈值。它越小的话,就可以检测到更多根本不存在的圆,而它越大的话,能通过检测的圆就更加接近完美的圆形了
  • 第八个参数,int类型的minRadius,有默认值0,表示圆半径的最小值
  • 第九个参数,int类型的maxRadius,也有默认值0,表示圆半径的最大值

 6-1、霍夫圆检测

# 6 Hough Circle detect
    circles = cv2.HoughCircles(Close,cv2.HOUGH_GRADIENT,2,120,param1=120,param2=20,minRadius=20,maxRadius=0)
    #                                                                     param2:决定圆能否被检测到(越少越容易检测到圆,但相应的也更容易出错)

6-2、获取圆心和半径坐标

# 1 获取圆的圆心和半径
        x, y, r = int(circles[0][0][0]),int(circles[0][0][1]),int(circles[0][0][2])
        print(x, y, r)

6-3、画圆

# 2 画圆
        cv2.circle(image, (x, y), r, (255,0,255),5)
        cv2.imshow('image', image)

代码

# 图像处理
def Image_Processing():
    global h, s, v
    # 1 Capture the frames
    ret, frame = camera.read()
    image = frame
    cv2.imshow('frame', frame)
    
    # 2 get HSV
    binary = Get_HSV(frame)
    
    # 3 Gausi blur
    blur = cv2.GaussianBlur(binary,(9,9),0)
    
    # 4 Open
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9,9))
    Open = cv2.morphologyEx(blur, cv2.MORPH_OPEN, kernel)
    cv2.imshow('Open',Open)
    # 5 Close
    Close = cv2.morphologyEx(Open, cv2.MORPH_CLOSE, kernel)
    cv2.imshow('Close',Close)

    # 6 Hough Circle detect
    circles = cv2.HoughCircles(Close,cv2.HOUGH_GRADIENT,2,120,param1=120,param2=20,minRadius=20,maxRadius=0)
    #                                                                     param2:决定圆能否被检测到(越少越容易检测到圆,但相应的也更容易出错)
    # judge if circles is exist
    if circles is not None:
        # 1 获取圆的圆心和半径
        x, y, r = int(circles[0][0][0]),int(circles[0][0][1]),int(circles[0][0][2])
        print(x, y, r)
        # 2 画圆
        cv2.circle(image, (x, y), r, (255,0,255),5)
        cv2.imshow('image', image)
    else:
        (x,y),r = (0,0), 0
        
    return (x,y), r

六、运动控制

根据检测到的圆,获取到的坐标、半径,进行运动控制。

这里可以做到跟踪小球,前进和后退相配合,“敌进我退,敌退我进”。

# 运动控制(这里可以做到跟踪小球,前景和后退相配合,“敌进我退,敌退我进”)
def Move((x,y), r):
    low_xlimit = width/4
    high_xlimit = 0.75 * width
    #low_ylimit = 3/4 * height
    ylimit = 0.75 * height
    print(high_xlimit, ylimit)
    # 没检测到,停止不动
    if x==0:
        Stop()
    # 检测到在图片0.75以上的区域(距离正常)
    elif x>low_xlimit and x<high_xlimit and y<ylimit:
        Front(60)
    # 检测到在图片0.75以下的区域(距离过近,后退)
    elif x>low_xlimit and x<high_xlimit and y>=ylimit:
        Back(60)
    # 在左0.25区域,向左跟踪
    elif x<low_xlimit:
        Left(60)
    # 在右0.25区域,向右跟踪
    elif x>high_xlimit:
        Right(60)

总代码

#Ball Tracking(HSV)
import  RPi.GPIO as GPIO
import time
import Adafruit_PCA9685
import numpy as np
import cv2

#set capture window
width, height = 320, 240
camera = cv2.VideoCapture(0)
camera.set(3,width) 
camera.set(4,height) 

l_motor = 18
left_front   =  22
left_back   =  27

r_motor = 23
right_front   = 25
right_back  =  24


def Motor_Init():
    global L_Motor, R_Motor
    L_Motor= GPIO.PWM(l_motor,100)
    R_Motor = GPIO.PWM(r_motor,100)
    L_Motor.start(0)
    R_Motor.start(0)


def Direction_Init():
    GPIO.setup(left_back,GPIO.OUT)
    GPIO.setup(left_front,GPIO.OUT)
    GPIO.setup(l_motor,GPIO.OUT)
    
    GPIO.setup(right_front,GPIO.OUT)
    GPIO.setup(right_back,GPIO.OUT)
    GPIO.setup(r_motor,GPIO.OUT)


def Servo_Init():
    global pwm_servo
    pwm_servo=Adafruit_PCA9685.PCA9685()


def Trackbar_Init():
    # 1 create windows
    cv2.namedWindow('h_binary')
    cv2.namedWindow('s_binary')
    cv2.namedWindow('v_binary')
    # 2 Create Trackbar
    cv2.createTrackbar('hmin', 'h_binary', 6, 179, nothing)  
    cv2.createTrackbar('hmax', 'h_binary', 26, 179, nothing)  
    cv2.createTrackbar('smin', 's_binary', 110, 255, nothing)
    cv2.createTrackbar('smax', 's_binary', 255, 255, nothing)
    cv2.createTrackbar('vmin', 'v_binary', 140, 255, nothing)
    cv2.createTrackbar('vmax', 'v_binary', 255, 255, nothing)
    #   创建滑动条     滑动条值名称 窗口名称   滑动条值 滑动条阈值 回调函数


def Init():
    GPIO.setwarnings(False) 
    GPIO.setmode(GPIO.BCM)
    Direction_Init()
    Servo_Init()
    Motor_Init()
    Trackbar_Init()


def Front(speed):
    L_Motor.ChangeDutyCycle(speed)
    GPIO.output(left_front,1)   #left_front
    GPIO.output(left_back,0)    #left_back

    R_Motor.ChangeDutyCycle(speed)
    GPIO.output(right_front,1)  #right_front
    GPIO.output(right_back,0)   #right_back
     
    
def Back(speed):
    L_Motor.ChangeDutyCycle(speed)
    GPIO.output(left_front,0)   #left_front
    GPIO.output(left_back,1)    #left_back

    R_Motor.ChangeDutyCycle(speed)
    GPIO.output(right_front,0)  #right_front
    GPIO.output(right_back,1)   #right_back


def Left(speed):
    L_Motor.ChangeDutyCycle(speed)
    GPIO.output(left_front,0)   #left_front
    GPIO.output(left_back,1)    #left_back

    R_Motor.ChangeDutyCycle(speed)
    GPIO.output(right_front,1)  #right_front
    GPIO.output(right_back,0)   #right_back


def Right(speed):
    L_Motor.ChangeDutyCycle(speed)
    GPIO.output(left_front,1)   #left_front
    GPIO.output(left_back,0)    #left_back

    R_Motor.ChangeDutyCycle(speed)
    GPIO.output(right_front,0)  #right_front
    GPIO.output(right_back,1)   #right_back


def Stop():
    L_Motor.ChangeDutyCycle(0)
    GPIO.output(left_front,0)   #left_front
    GPIO.output(left_back,0)    #left_back

    R_Motor.ChangeDutyCycle(0)
    GPIO.output(right_front,0)  #right_front
    GPIO.output(right_back,0)   #right_back


def set_servo_angle(channel,angle):
    angle=4096*((angle*11)+500)/20000
    pwm_servo.set_pwm_freq(50)                #frequency==50Hz (servo)
    pwm_servo.set_pwm(channel,0,int(angle))


# 回调函数
def nothing(*arg):
    pass


# 在HSV色彩空间下得到二值图
def Get_HSV(image):
    # 1 get trackbar's value
    hmin = cv2.getTrackbarPos('hmin', 'h_binary')
    hmax = cv2.getTrackbarPos('hmax', 'h_binary')
    smin = cv2.getTrackbarPos('smin', 's_binary')
    smax = cv2.getTrackbarPos('smax', 's_binary')
    vmin = cv2.getTrackbarPos('vmin', 'v_binary')
    vmax = cv2.getTrackbarPos('vmax', 'v_binary')
    
    # 2 to HSV
    hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
    cv2.imshow('hsv', hsv)
    h, s, v = cv2.split(hsv)
    
    # 3 set threshold (binary image)
    # if value in (min, max):white; otherwise:black
    h_binary = cv2.inRange(np.array(h), np.array(hmin), np.array(hmax))
    s_binary = cv2.inRange(np.array(s), np.array(smin), np.array(smax))
    v_binary = cv2.inRange(np.array(v), np.array(vmin), np.array(vmax))
    
    # 4 get binary(对H、S、V三个通道分别与操作)
    binary = cv2.bitwise_and(h_binary, cv2.bitwise_and(s_binary, v_binary))
    
    # 5 Show
    cv2.imshow('h_binary', h_binary)
    cv2.imshow('s_binary', s_binary)
    cv2.imshow('v_binary', v_binary)
    cv2.imshow('binary', binary)
    
    return binary


# 图像处理
def Image_Processing():
    global h, s, v
    # 1 Capture the frames
    ret, frame = camera.read()
    image = frame
    cv2.imshow('frame', frame)
    
    # 2 get HSV
    binary = Get_HSV(frame)
    
    # 3 Gausi blur
    blur = cv2.GaussianBlur(binary,(9,9),0)
    
    # 4 Open
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9,9))
    Open = cv2.morphologyEx(blur, cv2.MORPH_OPEN, kernel)
    cv2.imshow('Open',Open)
    # 5 Close
    Close = cv2.morphologyEx(Open, cv2.MORPH_CLOSE, kernel)
    cv2.imshow('Close',Close)

    # 6 Hough Circle detect
    circles = cv2.HoughCircles(Close,cv2.HOUGH_GRADIENT,2,120,param1=120,param2=20,minRadius=20,maxRadius=0)
    #                                                                     param2:决定圆能否被检测到(越少越容易检测到圆,但相应的也更容易出错)
    # judge if circles is exist
    if circles is not None:
        # 1 获取圆的圆心和半径
        x, y, r = int(circles[0][0][0]),int(circles[0][0][1]),int(circles[0][0][2])
        print(x, y, r)
        # 2 画圆
        cv2.circle(image, (x, y), r, (255,0,255),5)
        cv2.imshow('image', image)
    else:
        (x,y),r = (0,0), 0
        
    return (x,y), r


# 运动控制(这里可以做到跟踪小球,前景和后退相配合,“敌进我退,敌退我进”)
def Move((x,y), r):
    low_xlimit = width/4
    high_xlimit = 0.75 * width
    #low_ylimit = 3/4 * height
    ylimit = 0.75 * height
    print(high_xlimit, ylimit)
    # 没检测到,停止不动
    if x==0:
        Stop()
    # 检测到在图片0.75以上的区域(距离正常)
    elif x>low_xlimit and x<high_xlimit and y<ylimit:
        Front(60)
    # 检测到在图片0.75以下的区域(距离过近,后退)
    elif x>low_xlimit and x<high_xlimit and y>=ylimit:
        Back(60)
    # 在左0.25区域,向左跟踪
    elif x<low_xlimit:
        Left(60)
    # 在右0.25区域,向右跟踪
    elif x>high_xlimit:
        Right(60)

    
if __name__ == '__main__':
    Init()
    
    set_servo_angle(4, 110)     #top servo     lengthwise
    #0:back    180:front    
    set_servo_angle(5, 90)     #bottom servo  crosswise
    #0:left    180:right  
    
    while 1:
        # 1 Image Process
        (x,y), r = Image_Processing()
        
        # 2 Move
        Move((x,y), r)
        
        # must include this codes(otherwise you can't open camera successfully)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            Stop()
            GPIO.cleanup()    
            break

这里的HSV是根据我自己当前的情况调节的,更改场景以后可能需要重新调节H、S、V三通道的阈值(max && min)

基础的视觉检测+运动,没有太多的运动控制算法(PID等等都没有涉及到)。有好的想法和建议欢迎交流讨论,Thanks♪(・ω・)ノ

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

树莓派视觉小车 -- 小球追踪(颜色追踪)(OpenCV色彩空间HSV) 的相关文章

  • OpenCV warpPerspective 性能缓慢

    在我的应用程序中 我跟踪一个物体 到达它的地方corners都在这个框架中 我发现它之间的单应性corners从最后一帧开始和 当前帧 使用单应性来做perspectiveTransform on the corners在当前帧中找到 得到
  • OpenCV:处理每一帧

    我想使用 OpenCV 编写一个跨平台应用程序进行视频捕获 在所有示例中 我发现来自相机的帧是使用抓取功能进行处理并等待一段时间 我想处理序列中的每一帧 我想定义自己的回调函数 每次当一个新帧准备好处理时都会执行该函数 例如直播对于 Win
  • 如何使用 python cv2 api 将 xy 点格式化为 unactorPoints?

    我在格式化要传递给 unactorPoints 的 x y 点列表时遇到问题 opencv 2 4 1 该错误消息是 C 特定的 并抱怨点数组不是 CV 32FC2 类型 我不应该能够传入 Nx2 numpy 数组吗 import cv2
  • 将 RGB 转换为黑色或白色

    我如何在Python中获取RGB图像并将其转换为黑白图像 不是灰度 我希望每个像素要么是全黑 0 0 0 要么是全白 255 255 255 流行的 Python 图像处理库中是否有任何内置功能可以完成此任务 如果不是 最好的方法是循环遍历
  • OpenCV Python 删除图像中的某些对象

    我正在使用带有 opencv 和 numpy 的 python 来检测天文中的星星 例如这个1 https i stack imgur com AKwEJ jpg图片 使用模板匹配 我可以用阈值检测星星 单击 2 2 https i sta
  • 使用 K 均值聚类 OpenCV 进行交通标志分割

    I used K Means Clustering to perform segmentation on this traffic sign as shown below 这些是我的代码 读取图像并模糊 img cv imread 000
  • 使用 cvcreateimage 使用 opencv 创建简单的黑色图像

    来自 OpenCV 新手的非常基本的问题 我只想创建一个图像 每个像素设置为0 黑色的 我在 main 函数中使用了以下代码 IplImage imgScribble cvCreateImage cvSize 320 240 8 3 我得到
  • 使用 Azure 机器学习检测图像中的符号

    4年前我发帖这个问题 https stackoverflow com q 6999920 411094不幸的是 得到的一些答案超出了我的技能水平 我刚刚参加了一次构建巡演会议 他们在会上谈论了机器学习 这让我想到了使用 ML 来解决我的问题
  • 检测骰子的上侧

    是否可以检测骰子的上面 虽然从顶部看这将是一项简单的任务 但从许多角度来看 可以看到多个侧面 Here is an example of a dice feel free to take your own pictures 您通常想知道自己
  • OpenCV非旋转图像拼接

    我正在 OpenCV 中进行图像拼接 从不同位置拍摄平面场景的照片并尝试构图全景图 我修改了缝合示例以满足我的需要 openCV 拼接管道的问题是 它假设相机纯粹旋转 但对我来说情况并非如此 当拍摄的照片与场景完全正交时 没有相机旋转 只是
  • 跟踪白色背景中的白球(Python/OpenCV)

    我在 Python 3 中使用 OpenCV 来检测白场上的白 黑球 并给出它的精确 x y 半径 和颜色 我使用函数 cv2 Canny 和 cv2 findContours 来找到它 但问题是 cv2 Canny 并不总是检测到圆的完整
  • OpenCV 中“IplImage”和“CvMat”的全称是什么?

    有一个IplImage and CvMat在 OpenCV 中 他们的全名是什么 IPL in IplImage代表英特尔处理库 这是Intel维护OpenCV时的残余 CV in cvMat代表计算机视觉矩阵 这是图形中常用的数据结构 I
  • OpenCV:视频录制太快

    我有一个简单的录像机 录制来自网络摄像头的视频 theVideoWriter open filename countAsString ext CV FOURCC X V I D 30 Size 1920 1080 true while re
  • OpenCV:使用 StereoCamera 系统对颜色标记进行 3D 姿态估计

    我有一个立体摄像系统并使用两者正确校准它 cv calibrateCamera and cv stereoCalibrate My reprojection error似乎没问题 凸轮0 0 401427 凸轮1 0 388200 立体声
  • OpenCV,捕获的视频比原始相机视频运行得更快!

    我正在使用 openCV 从相机捕获视频并将其存储到 avi 文件 问题是当我完成捕获并运行 avi 文件时 视频流看起来速度很快 这是代码 void main CvCapture capture cvCaptureFromCAM 0 in
  • 如何在 opencv 3.0 Beta 中从文件读取 UMat?

    我想用UMat所以我的代码可以使用 OpenCL OpenCV 3 0 0 Beta 在 GPU 和 CPU 上运行 但我找不到将图像文件读入的方法UMat或转换一个Mat to UMat 如何将图像读入UMat 样品用于Mat to UM
  • 使用 SURF 在检测到的对象周围绘制矩形

    我正在尝试从涉及冲浪检测器的以下代码中检测对象 我不想绘制匹配项 我想在检测到的对象周围绘制一个矩形 但不知何故我无法获得正确的单应性 请任何人指出在哪里我走错了 include
  • OpenCV 旋转图像而不裁剪澄清

    我想扩展这个主题 参考用户 Lars Schillingmann 给出的这个 SO 问题和接受的答案 在 C 中的 OpenCV 中旋转图像而不裁剪 https stackoverflow com questions 22041699 ro
  • python openCV 中的人口普查变换

    我开始在一个与立体视觉相关的项目中使用 openCV 和 python 我找到了关于使用 openCV 在 C 中进行人口普查转换的文档页面 link http docs opencv org 3 1 0 d2 d7f namespacec
  • 从凸点获取角点

    我编写了算法来提取图像中显示的点 它们形成凸形 我知道它们的顺序 如何从这些点中提取角点 顶部 3 个和底部 3 个 我正在使用opencv 如果你已经有了物体的凸包 并且该包包含角点 那么你需要做的就是简化包直到它只有 6 个点 有很多方

随机推荐

  • JPEG编码原理与解码分析

    JPEG编码原理 JPEG Joint Photographic Experts Group 是JPEG标准的产物 该标准由国际标准化组织 ISO 制订 是面向连续色调静止图像的一种压缩标准 JPEG格式是最常用的图像文件格式 后缀名为 j
  • 数据挖掘—数据预处理

    文章目录 数据预处理 1 数据清洗 缺失值处理 异常值处理 2 数据集成 实体识别 冗余属性识别 数据变换 简单函数变换 规范化 连续属性离散化 属性构造 3 数据规约 属性归约 数值归约 Python主要数据预处理函数 数据预处理 数据预
  • 【uniapp】使用canvas组件编译到微信小程序兼容出错问题

    使用uniapp编译跨平台项目会遇到不少兼容问题 这里主要讲canvas组件的 编译到微信小程序会有兼容出错问题 这里给讲一下解决方案 希望有帮助 常见问题 draw无法绘制图形 如果使用CanvasContext绘制 以下代码 编译到微信
  • 值得收藏的UmiJS 教程

    点击上方关注 前端技术江湖 一起学习 天天进步 前言 网上的umi教程是真的少 很多人都只写了一点点 很多水文 所以打算自己写一篇 自己搭建umi 并封装了一下常用的功能 并用到公司实际项目中 umi介绍 Umi 是什么 Umi 中文可发音
  • maven学习笔记 maven的使用

    新建maven项目 使用mvn archetype generate命令新建一个maven项目 maven会自动下载必要的插件 还会下载一个所有项目模板的分类文件 这个文件有好几兆的大小 因此可能会持续比较长的时间 下载完毕之后 就会列出所
  • JAVA 8 新特性及使用

    1 前言 2019年9月19日java13已正式发布 感叹java社区强大 经久不衰 由于国内偏保守 新东西总要放一放 让其他人踩踩坑 等稳定了才会去用 并且企业目的还是赚钱 更不会因为一个新特性去重构代码 再开发一套程序出来 甚者国内大多
  • 不一样的联宇益通,不一样的SD-WAN+

    点击上方 中国云报 可关注 笔者有点挠头 究竟该用哪个词来描述联宇益通 Netpas 公司呢 低调 技术控 特立独行 还是自得其乐 似乎都有些影子 但又都不是最准确的表达 与联宇益通创始人兼CEO谢毅斌聊得越深入 感觉联宇益通身上矛盾的地方
  • 软件测试 app自动化02 Appium常用的元素定位工具 元素的属性 元素定位方法

    文章目录 1 Appium常用的元素定位工具 1 1 uiautomatorviewer 1 2 Appium Inspector 1 3 Weditor 2 元素的属性 3 元素定位方法 小结 1 Appium常用的元素定位工具 1 1
  • 数据库学习笔记(8)——mysql中的函数和存储过程

    1 MySQL中的函数 1 数据库主要做存储和查询操作 逻辑操作一般不在数据库中进行操作 2 MySQL中的函数主要是自定义函数 其中自定义函数格式如下 修改语句结束符 delimiter create function 函数名 参数名 数
  • 操作系统常见面试题

    1 什么是进程 Process 和线程 Thread 有何区别 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动 进程是系统进行资源分配和调度的一个独立单位 线程是进程的一个实体 是CPU调度和分派的基本单位 它是比进程更小的能
  • java-线程锁

    实现锁 1 同步代码块 2 同步方法 在方法的头部加上synchronized 3 Lock 功能比synchronized更加的强大 但是加锁的时一定不要忘记解锁unlock 在使用lock锁时 想要实现睡眠唤醒功能 就要使用condit
  • 决策报表---动态参数实现多级下拉折叠菜单

    1 描述 在报表开发中 我们会遇到报表需要对行标题实现展开收起的折叠菜单的效果 这种效果一般在分析预览或者填报中应用下拉树控件来实现 但是在分页预览或者决策报表如何实现呢 这里我们使用动态参数的方式 预期效果 1 在分页预览和决策报表中能适
  • 操作系统中的线程&进程和同步&异步和并发&并行

    操作系统中的线程 进程和同步 异步和并发 并行 一 进程和线程 1 1 进程 1 2 线程 1 3 实现多任务的方法 1 3 1 使用多进程实现多任务 1 3 2 使用多线程 单个进程包含多个线程 实现多任务 1 3 3 使用多进程 多进程
  • vue+element中如何设置单个el-date-picker开始时间和结束时间关联

    功能 选了开始时间 则结束时间只能选择开始时间之后的 选了结束时间 则开始时间只能选择结束时间之前的 重点是picker options属性 图示 代码展示 body 内部
  • JavaScript设计模式-02-单例模式

    Javascript 设计模式 02 单例模式 简介 单例就是保证一个类只有一个实例 实现的方法一般是先判断实例是否存在 如果存在直接返回 如果不存在就创建了再返回 确保了一个类只有一个实例对象 在JavaScript里 单例作为一个命名空
  • AIGC(AI Generated Content,人工智能生成内容)

    AIGC AI Generated Content 人工智能生成内容 什么是AIGC AIGC Artificial Intelligence Generated Content AI Generated Content 中文译为人工智能生
  • 读《effective modern c++》笔记总结

    文章目录 一 类型推导与auto 模板类型推导 ParamType是一个指针或引用 但不是通用引用 ParamType是一个通用引用 ParamType即不是指针也不是引用 数组实参 函数实参 auto类型推导 二 decltype的理解
  • make menuconfig报错:Build dependency: Please install Git (git-core) >= 1.6.5

    版本号为chaos calmer 15 05 1 注意 在执行make menuconfig的时候 会报一个错误 如下 Build dependency Please install Git git core gt 1 6 5 这是open
  • 节流与防抖

    1 我们先了解为什么要节流和防抖 我们给一个inpu输入框绑定一个oninput事件 此时我们输入 前端开发 四个字 我们 观察以下后台打印
  • 树莓派视觉小车 -- 小球追踪(颜色追踪)(OpenCV色彩空间HSV)

    目录 效果展示 基础理论 HSV 为什么用HSV空间而不是RGB空间 HSV 1 Hue 色相 2 Value 明度 3 Saturation 饱和度 一 初始化 滑动条初始化 1 创建回调函数 2 窗口设置 名称 3 滑动条设置 代码 二