1. 如何利用Python、OpenCV计算轮廓的中心
2. Python,OpenCV应用轮廓逼近算法,检测对象的形状,如三角形,正方形,矩形,五边形,圆。
这一节学习应用 L * a * b * 颜色空间确定对象的颜色,与其颜色的通道计算最小的欧几里得距离,得到其颜色最接近预定义的颜色。
这个方法有其缺陷,会把颜色饱和度不够的(非红、绿、蓝)的颜色也标记为红或绿或蓝。(取决于预定义的颜色空间的准确度)。
检测颜色过程:
- 预定义颜色空间(颜色:BRG的值)
- 循环遍历颜色并将其转换为 L * a * b 空间的值
- 寻找轮廓,为轮廓构建一个蒙版,计算蒙版区域的平均 L * a * b 值
- 遍历已转换后的 L * a * b 空间list,分别与蒙版计算欧几里得距离,得到最小的距离值,以及其对应的颜色。则认为该颜色就是最接近的颜色——轮廓的颜色
# 用来标记带有颜色文本标签的图像区域
# 创建一个Python类,该类可用于用关联的颜色标记图像中的形状。
# 导入必要的包
from scipy.spatial import distance as dist
from collections import OrderedDict
import numpy as np
import cv2
class ColorLabeler:
def __init__(self):
# 初始化颜色字典 包括颜色名称和RGB元组值
colors = OrderedDict({
"red": (255, 0, 0),
"green": (0, 255, 0),
"blue": (0, 0, 255)})
# 为L*a*b*图像分配内存 并且初始化颜色名称list
self.lab = np.zeros((len(colors), 1, 3), dtype="uint8")
self.colorNames = []
# 循环遍历颜色字典
for (i, (name, rgb)) in enumerate(colors.items()):
# 更新L*a*b数组 及 颜色list
self.lab[i] = rgb
self.colorNames.append(name)
# 转换 RGB颜色空间 为 L*a*b* 数组
self.lab = cv2.cvtColor(self.lab, cv2.COLOR_RGB2LAB)
# image:待检测的图像, c:轮廓
def label(self, image, c):
# 为轮廓构建一个蒙版,计算蒙版区域的 L*a*b的平均值
mask = np.zeros(image.shape[:2], dtype="uint8")
cv2.drawContours(mask, [c], -1, 255, -1)
mask = cv2.erode(mask, None, iterations=2)
mean = cv2.mean(image, mask=mask)[:3]
# 初始化到目前为止找到的最小距离
minDist = (np.inf, None)
# 遍历L*a*b 数组颜色
for (i, row) in enumerate(self.lab):
# 计算每个已知颜色与平均颜色之间的欧几里得距离
d = dist.euclidean(row[0], mean)
# 如果距离比当前距离小,更新保留的距离变量值
if d < minDist[0]:
minDist = (d, i)
# 返回最小欧几里得距离值的颜色
return self.colorNames[minDist[1]]
1. 实现
- 加载图像、缩放、高斯平滑高频噪音、灰度图、BGR空间转 L * a * b空间, 阈值化(背景黑色,前景轮廓白色)、寻找轮廓
- 遍历轮廓,寻找轮廓中心,检测颜色
- 从中心位置,绘制颜色标签文本
2. 优化
颜色是可以识别,但是有些瑕疵,颜色不饱满的检测有误,橘色的被检测成红色,黄色的检测呈绿色;优化办法用 rangeDetector或者cv2.inRange()
(1)预先定义要检测的颜色的上下限范围(可以是Lab,HSV等颜色空间);
(2)运用cv2.inRange得到匹配颜色上下限范围的蒙版图;
(3)运用cv2.bitwise_and获得按位与结果图;
# python detect_color.py --image pokens.png
# 导入必要的包
import numpy as np
import argparse
import cv2
# 构建命令行参数
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", help="path to the image")
args = vars(ap.parse_args())
# 加载图片
image = cv2.imread(args["image"])
# 定义颜色边界list 分别为红、蓝、黄、灰
# numpy以 BGR颜色空间以下限:[17, 15, 100],上限: [50, 56, 200]表示 红色
boundaries = [
([17, 15, 100], [50, 56, 200]),
([86, 31, 4], [220, 88, 50]),
([25, 146, 190], [62, 174, 250]),
([103, 86, 65], [145, 133, 128])
]
# 现在我们有了边界列表,我们可以使用cv2.inRange 功能执行实际的颜色检测。
# 遍历边界列表
for (lower, upper) in boundaries:
# 从边界列表构建 Numpy数组 由于这些像素值在[0,256]范围内,因此我们可以使用无符号8位整数数据类型。
lower = np.array(lower, dtype="uint8")
upper = np.array(upper, dtype="uint8")
# 找到固定边界中范围所匹配的颜色,并应用mask
mask = cv2.inRange(image, lower, upper)
output = cv2.bitwise_and(image, image, mask=mask)
# 展示图像
cv2.imshow("images", np.hstack([image, output]))
cv2.waitKey(0)
参考:
https://www.pyimagesearch.com/2014/08/04/opencv-python-color-detection/
https://www.pyimagesearch.com/2016/02/15/determining-object-color-with-opencv/