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

如何在Python中实现图像轮廓的交替颜色填充?

实现轮廓交替颜色填充(白-黑-白循环)

我需要实现一种算法,能对图像轮廓进行交替颜色填充,顺序为白色→黑色→白色→黑色……,目标效果为外层白色、内层黑色、再内层白色的嵌套交替填充。

目前我已实现了外轮廓白色填充、内部轮廓留黑的代码,但当存在多个独立轮廓时,代码无法正常工作。

原实现代码

import numpy as np
import cv2

# Load the PNG image
img = cv2.imread('slice.png')

# Convert the image to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Threshold the image to create a binary image
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY)

# Find the outer contours in the binary image (using cv2.RETR_EXTERNAL)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# Create a blank image with the same dimensions as the original image
filled_img = np.zeros(img.shape[:2], dtype=np.uint8)

# Fill the outer contour with white color
cv2.drawContours(filled_img, contours, -1, 255, cv2.FILLED)

# Find contours with hierarchy, this time use cv2.RETR_TREE
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# Iterate over the contours and their hierarchies
for i, contour in enumerate(contours):
    has_grandparent = False
    has_parent = hierarchy[0][i][3] >= 0
    if has_parent:
        # Check if contour has a grandparent
        parent_idx = hierarchy[0][i][3]
        has_grandparent = hierarchy[0][parent_idx][3] >= 0

    # Draw the contour over temporary image first (for testing if it has black pixels inside).
    tmp = np.zeros_like(thresh)
    cv2.drawContours(tmp, [contour], -1, 255, cv2.FILLED)
    has_innder_black_pixels = (thresh[tmp==255].min() == 0)  # If the minimum value is 0 (value where draw contour is white) then the contour has black pixels inside

    if hierarchy[0][i][2] < 0 and has_grandparent and has_innder_black_pixels:
        # If contour has no child and has a grandparent and it has black inside, fill the contour with black color
        cv2.drawContours(filled_img, [contour], -1, 0, cv2.FILLED)

# Display the result
cv2.imshow('Original Image', img)
cv2.imshow('Filled Regions', filled_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

原代码问题

  • 单轮廓嵌套时:能实现外白内黑的效果,但无法支持更多层级的交替填充。
  • 多独立轮廓时:无法正确处理每个轮廓组的交替填充逻辑,出现颜色混乱或填充错误。

通用解决方案:基于轮廓层级深度的交替填充

核心思路是利用cv2.RETR_TREE获取的完整轮廓嵌套层级,计算每个轮廓的嵌套深度,根据深度奇偶性自动切换填充颜色,不管是单轮廓嵌套还是多独立轮廓都能适配。

完整实现代码

import numpy as np
import cv2

# 加载图像并预处理
img = cv2.imread('slice.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 使用OTSU自动阈值二值化,适配不同明暗的图像
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

# 获取带完整层级关系的轮廓
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
filled_img = np.zeros(img.shape[:2], dtype=np.uint8)

# 计算单个轮廓的嵌套深度:从当前轮廓向上查找父轮廓,统计层级
def get_contour_depth(hierarchy, contour_idx):
    depth = 0
    parent_idx = hierarchy[0][contour_idx][3]
    while parent_idx != -1:
        depth += 1
        parent_idx = hierarchy[0][parent_idx][3]
    return depth

# 遍历所有轮廓,按深度奇偶性交替填充
for idx, cnt in enumerate(contours):
    depth = get_contour_depth(hierarchy, idx)
    # 偶数深度(最外层、第三层...)填充白色,奇数深度(第二层、第四层...)填充黑色
    # 如需调换颜色顺序,反转判断条件即可
    fill_color = 255 if depth % 2 == 0 else 0
    cv2.drawContours(filled_img, [cnt], -1, fill_color, cv2.FILLED)

# 展示结果
cv2.imshow('Original Image', img)
cv2.imshow('Alternate Filled Result', filled_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

关键逻辑说明

  1. 轮廓层级获取:cv2.RETR_TREE会保留所有轮廓的嵌套关系,每个轮廓的层级信息hierarchy[0][i]包含[下一个轮廓索引, 上一个轮廓索引, 子轮廓索引, 父轮廓索引],通过父轮廓索引可以追溯当前轮廓的嵌套深度。
  2. 深度计算:从当前轮廓开始,不断向上查找父轮廓,每找到一个父轮廓深度+1,直到无父轮廓(父索引为-1),最终得到的数值就是该轮廓的嵌套深度。
  3. 交替填充:根据深度的奇偶性选择填充颜色,确保每向内嵌套一层颜色就切换一次,多个独立轮廓组会各自按自身的嵌套层级进行交替填充,互不干扰。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 21:12:16