You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用OpenCV检测无贴纸魔方(Stickerless Rubik's Cube)的面颜色?

如何用OpenCV识别无贴纸魔方的面颜色

我需要实现用OpenCV识别无贴纸魔方的面颜色,但找不到最优方案。网上多数方案采用Canny边缘检测,这种方法对带黑底贴纸的魔方效果很好:
带贴纸的魔方
但对无贴纸魔方效果极差,例如:
无贴纸魔方

我的问题是:如何用OpenCV检测这类无贴纸魔方的面颜色?

我目前尝试的代码如下:

import cv2 as cv
import numpy as np
from google.colab.patches import cv2_imshow

image = cv.imread('cube.png')

grey_frame = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
noiseless_frame = cv.fastNlMeansDenoising(grey_frame, None, 20, 7, 7)
blurred_frame = cv.blur(noiseless_frame, (3, 3))
canny_frame = cv.Canny(blurred_frame, 30, 60, 3)
dilated_frame = cv.dilate(canny_frame, cv.getStructuringElement(cv.MORPH_RECT, (9, 9)))

contours, _ = cv.findContours(dilated_frame, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)

square_contours = []

for contour in contours:
    approx = cv.approxPolyDP(contour, 0.1*cv.arcLength(contour, True), True)
    if len(approx) == 4 or True:
        x, y, w, h = cv.boundingRect(approx)
        ratio = float(w) / h
        area = cv.contourArea(approx)
        if ratio >= 0.8 and ratio <= 1.2 and w >= 30 and w <= 80 and area >= 900:
            square_contours.append({"x": x, "y": y, "w": w, "h": h})

new_img = image.copy()
for contour in square_contours:
    x, y, w, h = contour["x"], contour["y"], contour["w"], contour["h"]
    cv.rectangle(new_img, (x, y), (x + w, y + h), (0, 255, 0), 2)

cv2.imshow(new_img)

但这段代码大多时候无法检测到无贴纸魔方的色块,且当相邻色块颜色相近、边界不清晰时,会将它们识别为同一轮廓。附一张无贴纸魔方图片:
无贴纸魔方


针对无贴纸魔方的改进方案

无贴纸魔方的色块没有黑边,灰度差异极小,Canny边缘检测自然失效,得换思路从颜色或局部灰度特征入手:

1. 基于HSV颜色空间分割(优先推荐)

无贴纸魔方的核心特征是色块颜色差异,直接在HSV空间做分割更稳定,HSV对光照变化的鲁棒性远优于BGR:

  • 先将图像转换为HSV格式
  • 针对魔方的6种颜色(白、黄、红、橙、绿、蓝),用取色工具获取对应HSV阈值范围(需根据实际光照微调)
  • 用cv.inRange()生成单颜色掩码,再通过形态学闭操作(膨胀+腐蚀)去除噪声
  • 对每个掩码提取轮廓,筛选出接近正方形的区域(比例0.9~1.1,面积符合实际大小)

示例代码片段:

import cv2 as cv
import numpy as np

image = cv.imread('cube.png')
hsv_img = cv.cvtColor(image, cv.COLOR_BGR2HSV)

# 示例:白色的HSV阈值(需根据实际场景调整)
lower_white = np.array([0, 0, 200])
upper_white = np.array([180, 25, 255])
white_mask = cv.inRange(hsv_img, lower_white, upper_white)

# 形态学操作去除噪声
kernel = np.ones((5, 5), np.uint8)
clean_mask = cv.morphologyEx(white_mask, cv.MORPH_CLOSE, kernel)

# 提取外部轮廓并筛选正方形
contours, _ = cv.findContours(clean_mask, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
for cnt in contours:
    approx = cv.approxPolyDP(cnt, 0.02 * cv.arcLength(cnt, True), True)
    if len(approx) == 4:
        x, y, w, h = cv.boundingRect(approx)
        aspect_ratio = w / h
        if 0.9 <= aspect_ratio <= 1.1 and cv.contourArea(cnt) > 500:
            cv.rectangle(image, (x, y), (x+w, y+h), (0, 255, 0), 2)

cv.imshow('Detected Cubes', image)
cv.waitKey(0)
cv.destroyAllWindows()

2. 自适应阈值边缘检测

如果颜色分割受光照影响大,可以试试自适应阈值,它能根据局部区域灰度调整阈值,适合边界灰度差异小的场景:

grey_img = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
# 高斯自适应阈值二值化
adaptive_thresh = cv.adaptiveThreshold(
    grey_img, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY_INV, 11, 2
)
# 提取轮廓并筛选正方形
contours, _ = cv.findContours(adaptive_thresh, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
# 后续筛选逻辑同颜色分割方案

3. 关键优化点

  • 颜色阈值需根据拍摄环境微调,可借助OpenCV的取色工具实时获取目标色块的HSV值
  • 轮廓提取优先用RETR_EXTERNAL模式,避免嵌套轮廓干扰
  • 筛选轮廓时,结合宽高比、面积、凸性三个特征,减少误检
  • 若拍摄角度倾斜,可先做透视变换校正魔方平面,再进行色块检测

内容的提问来源于stack exchange,提问作者Tripaloski

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 18:14:49