[Python] Understanding some kind of grid structure of a rubick's cube using OpenCV

Discussão em 'Python' iniciado por Stack, Junho 30, 2025.

  1. Stack

    Stack Membro Participativo

    So, I am trying to extract all the colors out of a rubicks cube, Right now, I have tried the following:

    import cv2
    import PIL
    import numpy as np
    import math
    import matplotlib.pyplot as plt

    def detect_colored_cubes(image_path):
    img = cv2.imread(image_path)
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

    h, w, c = img.shape
    area_min = h*w//(30*30)
    area_max = h*w//5

    print(area_min, area_max)

    color_ranges = {
    'red': ([0, 50, 50], [6, 255, 255]),
    'orange': ([7., 50, 50], [16.9, 255, 255]),
    'yellow': ([17.0, 50, 50], [34., 255, 255]),
    'green': ([34., 50, 50], [70., 255, 255]),
    'blue': ([71, 50, 50], [135, 255, 255]),
    'pink': ([136, 50, 50], [180, 255, 255]),
    'white': ([0, 0, 100], [180, 30, 255])
    }

    detected_cubes = []

    for color_name, (lower, upper) in color_ranges.items():
    # Create mask for color
    mask = cv2.inRange(hsv, np.array(lower), np.array(upper))
    masked_img = cv2.bitwise_and(img, img, mask=mask)
    bw_masked_img = cv2.cvtColor(masked_img, cv2.COLOR_BGR2GRAY)
    # _, bw_masked_img = cv2.threshold(bw_masked_img, 100, 255, cv2.THRESH_BINARY)
    bw_masked_img_rgb = cv2.cvtColor(bw_masked_img, cv2.COLOR_GRAY2RGB)

    cv2_imshow(bw_masked_img)

    small_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
    medium_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
    large_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7, 7))

    cleaned = cv2.morphologyEx(bw_masked_img, cv2.MORPH_OPEN, small_kernel, iterations=2)

    cleaned = cv2.morphologyEx(cleaned, cv2.MORPH_CLOSE, medium_kernel, iterations=1)


    dist = cv2.distanceTransform(cleaned, cv2.DIST_L2, 5)

    thres = cv2.threshold(dist, 0.15*dist.max(), 255, 0)[1].astype(np.uint8)

    #cv2_imshow(dist)
    #cv2_imshow(thres)

    contours, _ = cv2.findContours(thres, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    print(color_name)
    # cv2_imshow(cleaned)

    markers = np.zeros_like(img)
    for i, contour in enumerate(contours):
    x, y, w, h = cv2.boundingRect(contour)
    area = w*h
    # print(area)
    # print("area", area)
    if area > area_min and area < area_max:
    detected_cubes.append({
    'color': color_name,
    'position': cv2.boundingRect(contour),
    'area': area
    })


    return detected_cubes

    img_file = 'cube4.jpg'
    cubes = detect_colored_cubes(img_file)


    Basically, I am looking at all colors seperately and trying to get components from them by using distance transform. However, I am having difficulty in removing outliers and getting only the useful data from them.

    Sometimes, it detects components which span multiple cubes since same colored subes are adjacent. So, I want to ask, how do I exactly get the set of 9 colors from one face as well as leave out the outliers?

    img_face = cv2.imread(img_file)
    cubes = sorted(cubes, key=lambda x: x['area'], reverse=True)
    new = np.zeros((img_face.shape[0], img_face.shape[1], 3), dtype=np.uint8)
    for cube in cubes:
    new[cube['position'][1]:cube['position'][1] + cube['position'][3], cube['position'][0]:cube['position'][0] + cube['position'][2]] = color_codes[cube['color']]
    cv2.putText(new, cube['color'], (cube['position'][0], cube['position'][1] - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color_codes[cube['color']], 2)
    cv2_imshow(new)


    gives me the following which is majorly correct but has outliers:

    [​IMG]

    Real image: cube4.jpg

    Continue reading...

Compartilhe esta Página