OpenCV颜色识别

38 篇文章 15 订阅
29 篇文章 6 订阅

颜色分辨

在这里插入图片描述

单个颜色识别

代码

import cv2
import numpy as np


def color(lower, upper, name):
    Img = cv2.imread('image/origin/all.png')  # 读入一幅图像

    kernel_3 = np.ones((3, 3), np.uint8)  # 3x3的卷积核

    if Img is not None:  # 判断图片是否读入
        HSV = cv2.cvtColor(Img, cv2.COLOR_BGR2HSV)  # 把BGR图像转换为HSV格式

        # mask是把HSV图片中在颜色范围内的区域变成白色,其他区域变成黑色
        if name == 'red':
            mask = cv2.inRange(HSV, lower[:3], upper[:3])
            mask = mask + cv2.inRange(HSV, lower[3:], upper[3:])
        else:
            mask = cv2.inRange(HSV, lower, upper)

        # 下面四行是用卷积进行滤波
        # erode()函数可以对输入图像用特定结构元素进行腐蚀操作,该结构元素确定腐蚀操作过程中的邻域的形状,
        # 各点像素值将被替换为对应邻域上的最小值:
        erosion = cv2.erode(mask, kernel_3, iterations=1)
        erosion = cv2.erode(erosion, kernel_3, iterations=1)
        # dilate()函数可以对输入图像用特定结构元素进行膨胀操作,该结构元素确定膨胀操作过程中的邻域的形状,
        # 各点像素值将被替换为对应邻域上的最大值:
        dilation = cv2.dilate(erosion, kernel_3, iterations=1)
        dilation = cv2.dilate(dilation, kernel_3, iterations=1)

        # target是把原图中的非目标颜色区域去掉剩下的图像
        cv2.bitwise_and(Img, Img, mask=dilation)

        # 将滤波后的图像变成二值图像放在binary中
        ret, binary = cv2.threshold(dilation, 127, 255, cv2.THRESH_BINARY)

        # 在binary中发现轮廓,轮廓按照面积从小到大排列
        contours, hierarchy = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        for index, contour in enumerate(contours):  # 遍历所有的轮廓
            x, y, w, h = cv2.boundingRect(contour)  # 将轮廓分解为识别对象的左上角坐标和宽、高
            # 在图像上画上矩形(图片、左上角坐标、右下角坐标、颜色、线条宽度)
            cv2.rectangle(Img, (x, y), (x + w, y + h), (0, 255,), 3)
            # 给识别对象写上标号
            font = cv2.FONT_HERSHEY_SIMPLEX
            cv2.putText(Img, name + str(index+1), (x - 10, y + 10), font, 1, (0, 0, 255), 2)  # 加减10是调整字符位置

        print(name, '方块的数量是', len(contours), '个')  # 终端输出目标数量

        # cv2.imshow('target', target)
        # cv2.imshow('Mask', mask)
        # cv2.imshow("prod", dilation)
        cv2.namedWindow('Img', 0)
        cv2.imshow('Img', Img)
        cv2.imwrite('./image/' + name + '.png', Img)  # 将画上矩形的图形保存到当前目录

    while True:
        key = cv2.waitKey(10) & 0xFF
        if key == 27 or cv2.getWindowProperty('Img', cv2.WND_PROP_VISIBLE) < 1.0:
            break


if __name__ == '__main__':
    # 下面两个值是要识别的颜色范围
    lower_yellow = np.array([20, 20, 20])  # 黄色的下限
    upper_yellow = np.array([30, 255, 255])  # 黄色上限
    # color(lower_yellow, upper_yellow, 'yellow')

    # 红色需要特殊处理
    lower_red = np.array([0, 43, 46, 156, 43, 46])  # 红色阈值下界
    higher_red = np.array([10, 255, 255, 180, 255, 255])  # 红色阈值上界
    # color(lower_red, higher_red, 'red')

    lower_green = np.array([35, 110, 106])  # 绿色阈值下界
    higher_green = np.array([77, 255, 255])  # 绿色阈值上界
    # color(lower_green, higher_green, 'green')

    lower_blue = np.array([78, 43, 46])  # 蓝色阈值下界
    upper_blue = np.array([110, 255, 255])  # 蓝色阈值下界
    color(lower_blue, upper_blue, 'blue')

效果

在这里插入图片描述

多个颜色识别

代码

import cv2
import numpy as np


def bitwise_or_fun(masks):
    if len(masks) <= 1:
        return
    mask = cv2.bitwise_or(masks[0], masks[1])

    for i in range(2, len(masks)):
        mask = cv2.bitwise_or(mask, masks[i])


def color(img):
    colors, lower_highers = get_params()
    frame = cv2.imread(img)  # 读入一幅图像
    font = cv2.FONT_HERSHEY_SIMPLEX
    img_hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

    masks = []
    for index, lower_higher in enumerate(lower_highers):
        lower_color = lower_higher[0]
        higher_color = lower_higher[1]

        if colors[index] == 'red':
            mask = cv2.inRange(img_hsv, lower_color[:3], higher_color[:3])  # 可以认为是过滤出红色部分,获得红色的掩膜
            mask = mask + cv2.inRange(img_hsv, lower_color[3:], higher_color[3:])  # 可以认为是过滤出红色部分,获得红色的掩膜
        else:
            mask = cv2.inRange(img_hsv, lower_color, higher_color)
        mask = cv2.medianBlur(mask, 7)  # 中值滤波
        masks.append(mask)

    bitwise_or_fun(masks)
    cntss = []
    for mask in masks:
        cnts, hierarchy = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)  # 轮廓检测
        cntss.append(cnts)

    for (colorname, cnts) in zip(colors, cntss):
        for index, cnt in enumerate(cnts):
            (x, y, w, h) = cv2.boundingRect(cnt)  # 该函数返回矩阵四个点
            # cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 0, 0), 2)  # 将检测到的颜色框起来
            cv2.putText(frame, colorname + str(index + 1), (x, y - 5), font, 0.7, (0, 0, 0), 2)
        cv2.drawContours(frame, cnts, -1, (0, 0, 0), 3)
    # cv2.namedWindow('frame', 0)
    cv2.imshow('frame', frame)
    cv2.imwrite('image/frame.png', frame)  # 将画上矩形的图形保存到当前目录

    while True:
        key = cv2.waitKey(10) & 0xFF
        if key == 27 or cv2.getWindowProperty('frame', cv2.WND_PROP_VISIBLE) < 1.0:
            break


def get_params():
    # 下面两个值是要识别的颜色范围
    lower_yellow = np.array([20, 20, 20])  # 黄色的下限
    upper_yellow = np.array([30, 255, 255])  # 黄色上限

    # 红色需要特殊处理
    lower_red = np.array([0, 43, 46, 156, 43, 46])  # 红色阈值下界
    higher_red = np.array([10, 255, 255, 180, 255, 255])  # 红色阈值上界

    lower_green = np.array([35, 110, 106])  # 绿色阈值下界
    higher_green = np.array([77, 255, 255])  # 绿色阈值上界

    lower_blue = np.array([78, 43, 46])  # 蓝色阈值下界
    upper_blue = np.array([110, 255, 255])  # 蓝色阈值下界

    # 下面两个值是要识别的颜色范围
    lower_purple = np.array([125, 43, 46])  # 紫色的下限
    upper_purple = np.array([155, 255, 255])  # 紫色上限

    params = []
    colors = []
    params.append([lower_red, higher_red]);colors.append('red')
    params.append([lower_yellow, upper_yellow]);colors.append('yellow')
    params.append([lower_green, higher_green]);colors.append('green')
    params.append([lower_blue, upper_blue]);colors.append('blue')
    params.append([lower_purple, upper_purple]);colors.append('purple')

    return colors, params


if __name__ == '__main__':
    color('./image/origin/all.png')

效果

在这里插入图片描述

模板匹配+颜色识别

源码

import cv2
import numpy as np


def bitwise_or_fun(masks):
    if len(masks) <= 1:
        return
    mask = cv2.bitwise_or(masks[0], masks[1])

    for i in range(2, len(masks)):
        mask = cv2.bitwise_or(mask, masks[i])


def match_color(img,template):
    positions = match(img, template)
    colors, lower_highers = get_params()
    frame = cv2.imread(img)  # 读入一幅图像
    font = cv2.FONT_HERSHEY_SIMPLEX
    img_hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

    masks = []
    for index, lower_higher in enumerate(lower_highers):
        lower_color = lower_higher[0]
        higher_color = lower_higher[1]

        if colors[index] == 'red':
            mask = cv2.inRange(img_hsv, lower_color[:3], higher_color[:3])  # 可以认为是过滤出红色部分,获得红色的掩膜
            mask = mask + cv2.inRange(img_hsv, lower_color[3:], higher_color[3:])  # 可以认为是过滤出红色部分,获得红色的掩膜
        else:
            mask = cv2.inRange(img_hsv, lower_color, higher_color)
        mask = cv2.medianBlur(mask, 7)  # 中值滤波
        masks.append(mask)

    bitwise_or_fun(masks)
    cntss = []
    for mask in masks:
        cnts, hierarchy = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)  # 轮廓检测
        cntss.append(cnts)

    for (colorname, cnts) in zip(colors, cntss):
        index = 0
        for cnt in cnts:
            (x, y, w, h) = cv2.boundingRect(cnt)  # 该函数返回矩阵四个点
            for position in positions:
                (x1, y1, w1, h1) = position
                if x >= x1 and y >= y1 and x + w <= x1 + w1 and y + h <= y1 + h1:
                    cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 0, 0), 2)  # 将检测到的颜色框起来
                    cv2.putText(frame, colorname + str(index + 1), (x, y - 5), font, 0.7, (0, 0, 0), 2)
                    index = index + 1
                    break
    # 可以进行拉伸图片
    # cv2.namedWindow('frame', 0)
    cv2.imshow('frame', frame)

    while True:
        key = cv2.waitKey(10) & 0xFF
        if key == 27 or cv2.getWindowProperty('frame', cv2.WND_PROP_VISIBLE) < 1.0:
            break


def get_params():
    # 下面两个值是要识别的颜色范围
    lower_yellow = np.array([20, 20, 20])  # 黄色的下限
    upper_yellow = np.array([30, 255, 255])  # 黄色上限

    # 红色需要特殊处理
    lower_red = np.array([0, 43, 46, 156, 43, 46])  # 红色阈值下界
    higher_red = np.array([10, 255, 255, 180, 255, 255])  # 红色阈值上界

    lower_green = np.array([35, 110, 106])  # 绿色阈值下界
    higher_green = np.array([77, 255, 255])  # 绿色阈值上界

    lower_blue = np.array([78, 43, 46])  # 蓝色阈值下界
    upper_blue = np.array([110, 255, 255])  # 蓝色阈值下界

    # 下面两个值是要识别的颜色范围
    lower_purple = np.array([125, 43, 46])  # 紫色的下限
    upper_purple = np.array([155, 255, 255])  # 紫色上限

    params = []
    colors = []
    params.append([lower_red, higher_red]);colors.append('red')
    params.append([lower_yellow, upper_yellow]);colors.append('yellow')
    params.append([lower_green, higher_green]);colors.append('green')
    params.append([lower_blue, upper_blue]);colors.append('blue')
    params.append([lower_purple, upper_purple]);colors.append('purple')

    return colors, params


def match(img_src, template_src):
    img = cv2.imread(img_src)
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    template = cv2.imread(template_src, 0)
    h, w = template.shape[:2]

    res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)
    threshold = 0.8

    # 取匹配程度大于%80的坐标
    loc = np.where(res >= threshold)
    position = []
    for pt in zip(*loc[::-1]):  # *号表示可选参数
        position.append([pt[0], pt[1], w, h])

    return position


if __name__ == '__main__':
    img = 'color2.png'
    template = 'tmp2.png'

    match_color(img,template)

效果

注意:模板和图片中的大小应当一直
如果需要不一致的请看下面的升级版本
在这里插入图片描述

当模板和图片中的大小不一致的时候,就无法识别

在这里插入图片描述

模板匹配+颜色识别升级

代码

  • get_params() 要进行识别的颜色
  • def match(img_src, template_src, wh, ratio)
    wh为图片的宽和高,ratio为宽高比例
import cv2
import numpy as np
from imutils import contours


# 传入一个轮廓计算面积
def contourArea(cnt):
    rect = cv2.minAreaRect(cnt)  # 最小外接矩形
    box = cv2.boxPoints(rect)
    box = np.int0(box)
    return cv2.contourArea(box)


# 绘图展示
def cv_show(name, img):
    # cv2.namedWindow(name, 0)
    cv2.imshow(name, img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()


# 初始化颜色参数
def get_params():
    # 下面两个值是要识别的颜色范围
    lower_yellow = np.array([20, 20, 20])  # 黄色的下限
    upper_yellow = np.array([30, 255, 255])  # 黄色上限

    lower_green = np.array([35, 110, 106])  # 绿色阈值下界
    higher_green = np.array([77, 255, 255])  # 绿色阈值上界

    lower_blue = np.array([78, 43, 46])  # 蓝色阈值下界
    upper_blue = np.array([110, 255, 255])  # 蓝色阈值下界

    # 下面两个值是要识别的颜色范围
    lower_purple = np.array([125, 43, 46])  # 紫色的下限
    upper_purple = np.array([155, 255, 255])  # 紫色上限

    # 红色需要特殊处理
    lower_red = np.array([0, 43, 46, 156, 43, 46])  # 红色阈值下界,
    higher_red = np.array([10, 255, 255, 180, 255, 255])  # 红色阈值上界

    params = []
    colors = []

    # 进行要识别颜色的添加
    params.append([lower_red, higher_red]);colors.append('red')
    params.append([lower_yellow, upper_yellow]);colors.append('yellow')
    params.append([lower_green, higher_green]);colors.append('green')
    params.append([lower_blue, upper_blue]);colors.append('blue')
    params.append([lower_purple, upper_purple]);colors.append('purple')

    return colors, params


def match_color(img1):
    img_hsv = cv2.cvtColor(img1, cv2.COLOR_BGR2HSV)
    colors, lower_highers = get_params()

    max = 0
    i = -1
    for index, lower_higher in enumerate(lower_highers):
        area = 0
        lower_color = lower_higher[0]
        higher_color = lower_higher[1]

        if colors[index] == 'red':
            mask = cv2.inRange(img_hsv, lower_color[:3], higher_color[:3])  # 可以认为是过滤出红色部分,获得红色的掩膜
            mask = mask + cv2.inRange(img_hsv, lower_color[3:], higher_color[3:])  # 可以认为是过滤出红色部分,获得红色的掩膜
        else:
            mask = cv2.inRange(img_hsv, lower_color, higher_color)
        mask = cv2.medianBlur(mask, 7)  # 中值滤波
        cnts, hierarchy = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)  # 轮廓检测

        if len(cnts) > 0:
            for cnt in cnts:
                area = area + contourArea(cnt)
                # area = area+cv2.contourArea(cnt)
            if area > max:
                max = area
                i = index
                # print(max, colors[i])

    # print("=======================================================")
    if i > -1:
        return colors[i]
    else:
        return "no"


# wh为图片的宽和高,ratio为宽高比例
def match(img_src, template_src, wh, ratio):
    # 模板处理,固定大小
    template = cv2.imread(template_src)
    ref = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
    # 二值图像
    ref = cv2.threshold(ref, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
    template = cv2.resize(ref, (wh[0], wh[1]))
    # cv_show('ref', template)

    # 图像处理
    img = cv2.imread(img_src)
    # 读取输入图像,预处理
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    gray = cv2.GaussianBlur(gray, (5, 5), 0)

    # 边缘检测第一种方法
    # thresh = cv2.Canny(gray, 10, 200)
    # 边缘检测第二种方法(105-118行)
    # Sobel算子检测元素的边缘
    gradX = cv2.Sobel(gray, ddepth=cv2.CV_32F, dx=1, dy=0, ksize=-1)  # ksize=-1相当于用3*3的
    gradX = cv2.convertScaleAbs(gradX)
    gradY = cv2.Sobel(gray, cv2.CV_32F, 0, 1, ksize=-1)
    gradY = cv2.convertScaleAbs(gradY)

    grad = cv2.addWeighted(gradX, 0.5, gradY, 0.5, 0)
    # cv_show("grad", grad)
    (minVal, maxVal) = (np.min(grad), np.max(grad))
    grad = (255 * ((grad - minVal) / (maxVal - minVal)))
    grad = grad.astype("uint8")
    # 阈值设定,THRESH_OTSU会自动寻找合适的阈值,适合双峰,
    thresh = cv2.threshold(grad, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
    cv_show("thresh", thresh)

    # 轮廓检测
    cnts, hierarchy = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    cur_img = img.copy()
    cv2.drawContours(cur_img, cnts, -1, (0, 0, 255), 3)
    cv_show("cur_img", cur_img)

    # 遍历每一个轮廓中的样本
    for (i, c) in enumerate(cnts):
        # 计算矩形
        (x, y, w, h) = cv2.boundingRect(c)
        ar = w / float(h)

        # 选择合适的区域,根据实际任务来,这里的基本都是四个数字一组
        if ratio[0] < ar < ratio[1]:
            if (30 < w) and (30 < h):
                # 符合的留下来
                roi = gray[y - 5:y + h + 5, x - 5:x + w + 5]
                roi = cv2.resize(roi, (wh[0], wh[1]))
                res = cv2.matchTemplate(roi, template, cv2.TM_CCOEFF_NORMED)
                # cv_show("roi", roi)
                if res >= 0.5:
                    # 画出来
                    name = match_color(img[y - 5:y + h + 5, x - 5:x + w + 5])
                    print(res, name)
                    # print(res, name + str(i))
                    print("=======================================================")
                    cv2.rectangle(img, (x - 5, y - 5), (x + w + 5, y + h + 5), (0, 0, 255), 1)
                    # cv2.putText(img, name + str(i), (x, y), cv2.FONT_HERSHEY_SIMPLEX, 0.65, (0, 0, 255), 2)
                    cv2.putText(img, name, (x, y), cv2.FONT_HERSHEY_SIMPLEX, 0.65, (0, 0, 255), 2)
    cv_show("img", img)
    cv2.imwrite('img.png', img)


if __name__ == '__main__':
    img = './image/testt.png'
    template = './image/test33_tmp.png'
    match(img, template, [30, 90], [0.3, 0.45])

效果

在这里插入图片描述

原图

testt.png
在这里插入图片描述
test33_tmp.png
在这里插入图片描述
color2.png
在这里插入图片描述
temp2.png
在这里插入图片描述
all.png
在这里插入图片描述

实际项目

实际项目中干扰太大效果不佳

更好的效果请查看 目标检测算法deformable detr

在这里插入图片描述

原图

control-light.jpg
在这里插入图片描述
c2.png
在这里插入图片描述

  • 7
    点赞
  • 91
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lzh~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值