利用opencv实现检测特定颜色物体,并追踪其移动

写在前面:思路、代码方法参考了https://github.com/akshaybahadur21

利用OpenCV将实时读取视频流,将每一帧的图像转换为hsv类型,将特定hsv颜色区间的物体的像素值置为255,将区间之外的像素值置为0,形成黑白图像,再利用erode对图像进行腐蚀消除部分噪音区域和dilate对图像进行膨胀,将检测到的物体放大,最后在进行绘制操作。

特别注意:因为我用的是绿色的笔来作为待检测物体,所以颜色接近绿色的物体都可能会被检测到。这个方法容易受到外界光线,背景颜色的影响,通过试验:1.划分ROI区域可消除部分外界的影响,2.hsv的颜色区间也是影响识别成功与否的一个因素。 3.背景单一,待检测物体颜色鲜艳的情况下,效果最好。

 如果大家有什么更好的方法提出,麻烦在下方评论区留个言,,抱抱大腿。

效果图如下:

import numpy as np
import cv2
import argparse
from collections import deque

cap = cv2.VideoCapture(0)

pts = deque(maxlen=128)

lower_red = np.array([0, 80, 50])
upper_red = np.array([8, 255, 220])

lower_green = np.array([50, 120, 50])
upper_green = np.array([77, 255, 255])

while True:
    ret, img = cap.read()
    img = img[:, :-50]
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)  # 将捕获的视频帧由RBG转HSV

    kernel = np.ones((3, 3), np.uint8)
    # 将处于lower_green 和upper_green 区间外的值全部置为0,区间内的值置为255
    mask = cv2.inRange(hsv, lower_green, upper_green)

    # mask_pencil = cv2.inRange()
    # 对mask图像进行腐蚀,将一些小的白色区域消除,将图像“变瘦”, iterations代表使用erode的次数
    # erode就是让图像中白色部分变小
    mask = cv2.erode(mask, kernel, iterations=2)
    # 开运算 (MORPH_OPEN):先腐蚀再膨胀
    # 删除不能包含结构元素的对象区域,平滑图像的轮廓,使拐点的地方更加连贯,断开一些狭窄的链接,去掉细小的突出部分。
    # 在这里使用开运算就是为了使除笔头外的噪声区域尽量的消除
    mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel, iterations=1)

    # dilate膨胀就是将白色区域变大,黑色的区域减小
    mask = cv2.dilate(mask, kernel, iterations=5)
    # bitwise_and对二进制数据进行“与”操作,即对图像(灰度图像或彩色图像均可)每个像素值进行二进制“与”操作
    # 与操作后,白色区域的部分就会保存下来,黑色区域(为0)与后就还是为0
    res = cv2.bitwise_and(img, img, mask=mask)

    '''
    findContours() 查找检测物体的轮廓。
    第一个参数是寻找轮廓的图像;
    第二个参数表示轮廓的检索模式,有四种(本文介绍的都是新的cv2接口):
        cv2.RETR_EXTERNAL表示只检测外轮廓
        cv2.RETR_LIST检测的轮廓不建立等级关系
        cv2.RETR_CCOMP建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。
        如果内孔内还有一个连通物体,这个物体的边界也在顶层。
        cv2.RETR_TREE建立一个等级树结构的轮廓。

    第三个参数method为轮廓的近似办法
        cv2.CHAIN_APPROX_NONE存储所有的轮廓点,相邻的两个点的像素位置差不超过1,
        即max(abs(x1-x2),abs(y2-y1))==1
        cv2.CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,
        例如一个矩形轮廓只需4个点来保存轮廓信息

        cv2.findContours()函数返回两个值:contours:hierarchy,一个是轮廓本身,还有一个是每条轮廓对应的属性。
        findContours函数首先返回一个list(即contours),list中每个元素都是图像中的一个轮廓,用numpy中的ndarray表示

    '''
    cnts, heir = cv2.findContours(mask.copy(), cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)[-2:]
    center = None

    if len(cnts) > 0:  # 如果检测出了轮廓
        c = max(cnts, key=cv2.contourArea)  # 以轮廓的面积为条件,找出最大的面积
        ((x, y), radius) = cv2.minEnclosingCircle(c)  # 找出最小的圆

        M = cv2.moments(c)
        center = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"]))
        if radius > 5:
            cv2.circle(img, (int(x), int(y)), int(radius), (0, 255, 255), 2)
            cv2.circle(img, center, 5, (0, 0, 255), -1)

    pts.appendleft(center)
    for i in range(1, len(pts)):
        if pts[i - 1] is None or pts[i] is None:
                # if pts[i - 1] == pts[i]:
            continue
        thick = int(np.sqrt(len(pts) / float(i + 1)) * 2.5)
        cv2.line(img, pts[i - 1], pts[i], (0, 0, 225), thick)  # 画线

    cv2.imshow("img", img)
    cv2.imshow("mask", mask)
    cv2.imshow("res", res)


    k = cv2.waitKey(30) & 0xFF
    if k == 32:
        break
# cleanup the camera and close any open windows
cap.release()
cv2.destroyAllWindows()

 

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值