Python新手提问:如何用Python识别魔方上不同颜色块的数量?
下图由黄,红,绿,蓝方块组成,如何获取每种颜色方块的数量?
如果用 python 来实现的话,有第三方库或思路推荐吗,谢谢
![]()
我首先想到了 openCV,如果实在没思路的话,就去 GayHub 找个 python-opencv 的库试试看,考虑到可能会绕圈子,所以在这里问问 pythoner 大佬,感想~
Python新手提问:如何用Python识别魔方上不同颜色块的数量?
颜色空间直方图了解一下。
import cv2
import numpy as np
from collections import Counter
def detect_cube_colors(image_path):
"""
识别魔方图像中不同颜色块的数量
参数:
image_path: 魔方图像文件路径
返回:
dict: 颜色名称到数量的映射
"""
# 1. 读取图像
img = cv2.imread(image_path)
if img is None:
raise ValueError("无法读取图像,请检查文件路径")
# 2. 转换为HSV颜色空间(对光照变化更鲁棒)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 3. 定义魔方标准颜色范围(HSV格式)
# 注意:这些阈值可能需要根据实际图像调整
color_ranges = {
'red': [(0, 100, 100), (10, 255, 255)], # 红色范围1
'red2': [(170, 100, 100), (180, 255, 255)], # 红色范围2(HSV中红色在0°和180°附近)
'orange': [(10, 100, 100), (25, 255, 255)],
'yellow': [(25, 100, 100), (35, 255, 255)],
'green': [(35, 100, 100), (85, 255, 255)],
'blue': [(85, 100, 100), (130, 255, 255)],
'white': [(0, 0, 200), (180, 50, 255)], # 高亮度,低饱和度
'black': [(0, 0, 0), (180, 255, 50)] # 低亮度
}
# 4. 创建掩码并统计每个颜色的像素数
color_counts = {}
height, width = img.shape[:2]
total_pixels = height * width
for color_name, (lower, upper) in color_ranges.items():
# 处理红色(两个范围)
if color_name == 'red':
mask1 = cv2.inRange(hsv, tuple(lower), tuple(upper))
mask2 = cv2.inRange(hsv, tuple(color_ranges['red2'][0]),
tuple(color_ranges['red2'][1]))
mask = cv2.bitwise_or(mask1, mask2)
color_counts['red'] = np.sum(mask > 0)
else:
mask = cv2.inRange(hsv, tuple(lower), tuple(upper))
color_counts[color_name] = np.sum(mask > 0)
# 5. 过滤噪声(假设每个色块至少占图像的0.5%)
min_pixels = total_pixels * 0.005
filtered_counts = {k: v for k, v in color_counts.items() if v > min_pixels}
# 6. 估算块数(假设每个色块大致等大)
# 找到最大的颜色计数作为参考
if filtered_counts:
max_count = max(filtered_counts.values())
# 估算每个色块的平均像素数(取最大值的1/9,因为一个面有9个块)
avg_per_piece = max_count / 9
# 计算每个颜色的块数
piece_counts = {}
for color, count in filtered_counts.items():
pieces = round(count / avg_per_piece)
if pieces > 0:
piece_counts[color] = pieces
return piece_counts
return {}
# 使用示例
if __name__ == "__main__":
# 替换为你的图像路径
result = detect_cube_colors("rubiks_cube.jpg")
print("魔方颜色块统计:")
print("-" * 30)
for color, count in result.items():
print(f"{color}: {count}块")
print(f"总块数: {sum(result.values())}块")
# 可选:显示处理结果
img = cv2.imread("rubiks_cube.jpg")
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 创建组合掩码
masks = []
for color_name in result.keys():
if color_name == 'red':
mask1 = cv2.inRange(hsv, (0, 100, 100), (10, 255, 255))
mask2 = cv2.inRange(hsv, (170, 100, 100), (180, 255, 255))
masks.append(cv2.bitwise_or(mask1, mask2))
else:
lower, upper = color_ranges[color_name]
masks.append(cv2.inRange(hsv, tuple(lower), tuple(upper)))
if masks:
combined_mask = sum(masks)
result_img = cv2.bitwise_and(img, img, mask=combined_mask)
cv2.imshow('Original', img)
cv2.imshow('Detected Colors', result_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
核心思路:
- 用HSV颜色空间替代RGB,对光照更稳定
- 定义常见魔方颜色的HSV阈值范围
- 通过颜色阈值分割统计各颜色像素
- 根据像素比例估算实际色块数量
关键点说明:
- 红色在HSV中需要两个范围(0-10°和170-180°)
- 需要根据实际魔方颜色调整阈值
- 假设每个色块大小相近来估算块数
一句话建议: 实际使用时先用几张图调整好颜色阈值。
谢谢,我查查相关资料
我的思路是,按颜色设置阈值,分割之后计算每种颜色轮廓的面积,和总面积一比就可以了
好像跟直方图原理差不多 hhh 都是计算像素数量
不知道用一个和方块一样大小的 scanner 一路扫过去,结合 PIL 库有没有戏。
如果方块大小是固定和一致的,如果是的话 使用 PIL 库 隔多少像素去一个点,获得 rgb 值即可。
卖垫子的?
1. 需要被统计的块是否可能本身是白色的?
2. 是否保证存在白色缝隙?
3. 是否对精度有绝对要求?
哈哈,卖地胶的,白色的块无需统计,保证存在白色缝隙,对精度有要求。但是图片分辨率都会和上面的第一张图一样清楚。
如果你有思路可以聊下,我可以付一些辛苦费,告诉我思路自己去实现,嘿嘿
有个简单粗暴的方法,直接遍历所有点的 RGB 值,然后拿同颜色的点( RGB 相近)的数量 除以 1 块的像素点数量(宽*高) 就能得到大概值了。
不过半块的之类的会导致少算一些。
查了很多资料,GayHub 也翻了半天没找到好的办法,我看最终的办法只能靠肉眼去数了 = =!
from skimage.color import rgb2hsv, rgba2rgb
from skimage import data, io, filters
import numpy as np
image = io.imread(‘1.png’)
hsv = rgb2hsv(rgba2rgb(image))
h_hist, h = np.histogram(hsv[…,0].flatten(), bins=30)
1. 把你的图转成 hsv,在 h 空间求 histogram,黑 /白色的 h 值会是 0 所以不用在意。选择合适的 bins,使峰个数和颜色个数相等。忽略小于某值的 h,因为是白色。这里如果你的图里每个颜色都是纯色,bins 原则多大都是准确的。
2. 建议你尽量把图的 dpi 搞成一样的,也就是说每个方块大小相等,图总大小只和方块数有关。这样你只要算出一个方块有多少像素,用上述的 h_hist 值去除就可以了。因为不到一个方块按一个方块计算,所以向上取整 int(h_hist/square_size)+1 即可。
我没怎么折腾过这类问题,你最好看看 rgb2hsv 和 rgba2rgb 之类的函数,了解一下 hsv 模型。理论上说,白色的话 hsv 里 s 是 0, v 是 1,rgb2hsv 里给出的 h 也应该是 0,但近白色 h 不一定是 0,所以纯色最好。你这图不知道为啥好像不完全是纯色,所以筛选起来可能会比较麻烦,求 histogram 之前可以考虑像 hsv = hsv[np.logical_and(hsv[…,1]>0.05, hsv[…,2]<0.95)]这样按照 s, v (白色 s 值比较小接近 0,v 值比较大接近 1 )尽可能地把白色去掉,以增加准确度。
可以看看这里:
http://www.voidcn.com/article/p-dntnbcyb-ro.html
有常见颜色的 HSV 范围参考。
P.S. 地胶市场咋样?这么丑的设计地胶能卖出去么……
如果要大致计算的话,就用直方图。如果要精确计算的话,就划分网格,然后一个个中心取 RGB 值。不规则形状的话,用一个 mask 来遮住空白区域
第一个图横竖遍历,每个方格中心点像素值取出来,最后统计像素值数量就行。
第二个不规则图形,细节还是小方格,我觉得先把不规则图形补成规则的长方形,再横竖遍历,最后求像素个数,
一般图形颜色不会那么整齐,考虑颜色值的一个偏移范围,
腐蚀好像可以消去细线和封闭区块内的点
这个图只是方便客户,计算需要的数量,实际不是这个样子,市场挺好的
参考图片二值化的做法,把颜色进行三值化就可以了。然后就可以直接数块状大小了。
反正你这每一个格子大小应该都是固定的,用 opencv 查询每个格子中间像素的数值就很好统计
每个格子的大小是固定的,图都是美工做的,「用 opencv 查询每个格子中间像素的数值」这个有点难 = =!
简单提供一个思路,不知道符不符合你的要求:
分别针对 4 个颜色,做 cv::threshold、cv::findContours 等操作,得到各个颜色的总面积。后面就可以除以每个色块的面积得到大概的色块数量了
我试一下
直接通过颜色做阈值分割,分别拿到各种颜色的面积,然后除以单个方块的面积就行了
细线一定存在?都存在的话按细线切割开就行了呀
下午摸鱼写了一下,4 个颜色分别 181 731 14 34 个?
红色我肉眼数了下 37 个
颜色识别有点问题,晚上回去研究一下 HSV
计算一下间隙距离(从左到右遇到白色块的距离)切割图片,遍历所有小图
我和同事也实现了下,有点误差。你的计算还挺准确的,能提供下思路吗?
谢谢你的回复,我去试试。另外一个不情之请,方便的话能不能提供下部分代码,作为感谢,一本 python 相关的书作为感谢~京东上可以自选,报酬很低,见谅~
可以的,留个邮箱吧
[email protected]
谢谢,顺便把书的京东链接、收货地址一起发送吧~
已发,请注意查收,有问题直接回邮件就是
我觉得可以写个拼图的工具
hsv 了解一下
直接把所有的像素转换成 rgb 编码,然后 计算所有不同 RGB 编码的数量,就是像素量,然后除以每个色块的像素量就是色块数。
条条大路通罗马,等我实现了把代码贴一下
有的方块可能是半块(不满一块按一块算)所以您的方法可能会有误差



