如何在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()
关键逻辑说明
- 轮廓层级获取:
cv2.RETR_TREE会保留所有轮廓的嵌套关系,每个轮廓的层级信息hierarchy[0][i]包含[下一个轮廓索引, 上一个轮廓索引, 子轮廓索引, 父轮廓索引],通过父轮廓索引可以追溯当前轮廓的嵌套深度。 - 深度计算:从当前轮廓开始,不断向上查找父轮廓,每找到一个父轮廓深度+1,直到无父轮廓(父索引为-1),最终得到的数值就是该轮廓的嵌套深度。
- 交替填充:根据深度的奇偶性选择填充颜色,确保每向内嵌套一层颜色就切换一次,多个独立轮廓组会各自按自身的嵌套层级进行交替填充,互不干扰。
内容的提问来源于stack exchange,提问作者Vanhanen_
相关产品推荐
相关产品推荐

