计算机视觉第九课:颜色 + 形状 联合识别

一、核心思路(3 步)

  1. 转 HSV:用 HSV 空间做颜色过滤(比 RGB 稳)。
  2. 轮廓检测 + 形状判断 :用 approxPolyDP 数角点。
  3. 颜色 + 形状组合输出:给每个物体打标签(如 "Blue Rectangle")。

二、代码

python 复制代码
import cv2
import numpy as np

# ---------------------- 1. 颜色识别函数 ----------------------
def get_color(h, s, v):
    if s < 100 or v < 100:
        return "White/Gray"
    if (h >= 0 and h < 10) or (h >= 170 and h <= 180):
        return "Red"
    elif h >= 40 and h < 80:
        return "Green"
    elif h >= 100 and h < 130:
        return "Blue"
    else:
        return "Other"

# ---------------------- 2. 形状识别函数 ----------------------
def get_shape(approx):
    sides = len(approx)
    if sides == 3:
        return "Triangle"
    elif sides == 4:
        return "Rectangle"
    elif sides >= 6:
        return "Circle"
    else:
        return "Unknown"

# ---------------------- 3. 主程序 ----------------------
img = cv2.imread("shapes.png")  # 换成你的图片路径
h, w = img.shape[:2]
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 二值化 + 轮廓
_, thresh = cv2.threshold(gray, 240, 255, cv2.THRESH_BINARY_INV)
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

for cnt in contours:
    area = cv2.contourArea(cnt)
    if area < 500:  # 过滤噪点
        continue

    # 形状判断
    epsilon = 0.04 * cv2.arcLength(cnt, True)
    approx = cv2.approxPolyDP(cnt, epsilon, True)
    shape = get_shape(approx)

    # 找轮廓中心(用于取颜色)
    M = cv2.moments(cnt)
    if M["m00"] == 0:
        continue
    cx = int(M["m10"] / M["m00"])
    cy = int(M["m01"] / M["m00"])

    # 取中心像素的HSV → 判断颜色
    h_val, s_val, v_val = hsv[cy, cx]
    color = get_color(h_val, s_val, v_val)

    # 画轮廓 + 写文字
    cv2.drawContours(img, [approx], -1, (0,255,0), 2)
    text = f"{color} {shape}"
    cv2.putText(img, text, (cx-40, cy),
                cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255,0,0), 2)

cv2.imshow("Result", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

三、关键代码与原理说明

python 复制代码
h, w = img.shape[:2]

cv2.imread()得到的img是一个h,w,c的三维数组

python 复制代码
_, thresh = cv2.threshold(gray, 240, 255, cv2.THRESH_BINARY_INV)

240是阈值,表示阈值为240

255是最大值

cv2.THRESH_BINARY_INV 表示黑白反转

意思是:灰度值>=240的变成黑色,<240 变成白色

反二值化规则:

  • 像素值 > 240 → 设为 0(黑)
  • 像素值 ≤ 240 → 设为 255(白)

findContours 的 "怪脾气"

它只在:

  • 黑色背景(0)
  • 白色物体(255)

这种图里,才能正确找到物体轮廓。反过来:白底、黑 / 彩色物体 → 直接找不到或乱找

python 复制代码
_, thresh = cv2.threshold(gray, 240, 255, cv2.THRESH_BINARY)

白底黑物 ,findContours 不认,检测不到轮廓

python 复制代码
epsilon = 0.04 * cv2.arcLength(cnt, True)

周长的0.04倍作为误差值,True表示闭合曲线

python 复制代码
M = cv2.moments(cnt)
if area < 500:  # 过滤噪点
        continue
cx = int(M["m10"] / M["m00"])
cy = int(M["m01"] / M["m00"])

返回M是一个字典,计算这个轮廓的 "矩",M["m10"] 里的 m = moment(矩) ,后面的 0 和 10 是公式编号

其中:M["m00"] = 物体的面积, 如果面积 = 0 → 这个轮廓是空的,跳过它

M"m10"表示x的所有点的 X 坐标总和

M"m01"= 所有点的 Y 坐标总和

  • cx = X 坐标总和 ÷ 总面积(得到中心 X)
  • cy = Y 坐标总和 ÷ 总面积(得到中心 Y)
python 复制代码
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
#hsv是一张图片
  • 每个像素 = [蓝, 绿, 红]
  • hsv 是 HSV 空间每个像素 = [色相H, 饱和度S, 亮度V]

都是图片,都是三维数组(高度 × 宽度 × 3)

它和你最开始的 img 结构完全一样 ,只是颜色空间变了

  • img 是 BGR 空间每个像素 = [蓝, 绿, 红]
  • hsv 是 HSV 空间每个像素 = [色相H, 饱和度S, 亮度V

那我们为什么要取 hsv cy, cx

因为我们要拿物体中心点的像素值

  • 在 HSV 图片里
  • cy 行 ,第 cx 列
  • 拿出这个像素的 H、S、V 三个值
相关推荐
GitCode官方2 分钟前
开源鸿蒙跨平台直播|QRN 跨端鸿蒙一体化实战
人工智能·华为·开源·harmonyos·atomgit
IvorySQL26 分钟前
从双解析器到循环工程:IvorySQL 五年技术演进路线的深度观察
大数据·数据库·人工智能·postgresql·开源
YHHLAI29 分钟前
Agent 智能体开发实战 · 第四课:完整工具集 —— 打造 AI 编程 Agent 的工具箱
人工智能·windows·microsoft
ZZZMMM.zip38 分钟前
演示架构师-PPT大纲生成的HarmonyOS开发实践
人工智能·华为·powerpoint·harmonyos·鸿蒙·鸿蒙系统
青岛前景互联信息技术有限公司38 分钟前
以新标准为底座,前景互联打造高危场景智能接处警新体系
大数据·网络·人工智能
2601_9568657739 分钟前
怎么用AI生成带货视频?电商内容创作工具推荐与选择思路
人工智能·aigc·音视频
正在走向自律39 分钟前
怎样区分人工智能、离身智能、具身智能、智能机器人与人形机器人
人工智能·机器人·具身智能·人形机器人·智能机器人·离身智能
MEIXIFU140 分钟前
深夜里的温暖灯塔与便捷生活
大数据·人工智能·生活·迭代加深
坚持学习前端日记44 分钟前
国产化适配全流程适配英伟达本地开发
人工智能·python
执笔论英雄1 小时前
【;Agent】SWEET-RL:在协同推理任务上训练多轮大语言模型智能体
人工智能·语言模型·自然语言处理