如何在skimage或OpenCV中绘制内外渐变的椭圆蒙版?
嘿,这个渐变椭圆蒙版的需求其实很好实现,我给你分享两种靠谱的方案——分别用scikit-image和OpenCV来搞定,代码都加了详细注释,你可以直接跑起来试试~
方法一:用scikit-image实现
核心思路是基于距离变换:先生成椭圆蒙版,计算椭圆内部每个点到边界的距离,再把距离值映射成颜色渐变,距离越远(越靠近中心)的点用你想要的“内部色”,距离越近(靠近边界)的点过渡到“外部色”。
import numpy as np from skimage.draw import ellipse from skimage.morphology import distance_transform_edt from skimage import io, color # 1. 创建空白画布,尺寸可以自己调整 height, width = 500, 500 # 先生成椭圆蒙版的基础图 mask_base = np.zeros((height, width), dtype=np.float32) # 2. 绘制填充椭圆:参数分别是中心y坐标、中心x坐标、短半轴、长半轴 rr, cc = ellipse(height//2, width//2, 150, 200) mask_base[rr, cc] = 1 # 椭圆区域标记为1,其余为0 # 3. 计算距离变换:得到椭圆内部每个点到边界的欧氏距离 dist_map = distance_transform_edt(mask_base) # 4. 归一化距离值到0-1范围,方便映射颜色 dist_normalized = (dist_map - dist_map.min()) / (dist_map.max() - dist_map.min()) # 5. 生成自定义渐变效果:这里示例是中心深红色,边界过渡到浅粉色 # 分别给RGB通道赋值,用归一化后的距离值做权重 red_channel = dist_normalized * 255 # 中心红值最高,边界逐渐降低 green_channel = (1 - dist_normalized) * 100 # 中心绿值低,边界升高 blue_channel = (1 - dist_normalized) * 255 # 中心蓝值低,边界升高 # 合并成RGB图像 gradient_img = np.stack([red_channel, green_channel, blue_channel], axis=-1).astype(np.uint8) # 显示或保存图像 io.imshow(gradient_img) io.show() # io.imsave('ellipse_gradient_skimage.png', gradient_img)
小技巧
- 如果想要反向渐变(边界颜色深,中心浅),只需要把
dist_normalized换成1 - dist_normalized即可。 - 也可以用skimage的颜色映射函数,比如
color.apply_colormap(dist_normalized, 'viridis'),快速得到现成的渐变效果。
方法二:用OpenCV实现
OpenCV的思路和skimage类似,只是API不同,它的distanceTransform和applyColorMap能快速帮你生成渐变效果,适合习惯OpenCV的开发者。
import cv2 import numpy as np # 1. 创建空白蒙版画布 height, width = 500, 500 mask = np.zeros((height, width), dtype=np.uint8) # 2. 绘制填充椭圆:参数依次是蒙版、中心坐标、轴长(长轴、短轴)、旋转角度、起始角度、结束角度、颜色、填充厚度 center = (width//2, height//2) axes_length = (200, 150) cv2.ellipse(mask, center, axes_length, 0, 0, 360, 255, -1) # -1表示填充整个椭圆 # 3. 计算距离变换:DIST_L2是欧氏距离,5是距离变换的掩码大小 dist_map = cv2.distanceTransform(mask, cv2.DIST_L2, 5) # 4. 归一化距离值到0-255的uint8范围,方便后续颜色映射 dist_normalized = cv2.normalize(dist_map, None, 0, 255, cv2.NORM_MINMAX, dtype=cv2.CV_8U) # 5. 生成渐变效果:两种方式可选 # 方式1:用OpenCV自带的颜色映射(比如COLORMAP_JET,自带蓝到红的渐变) jet_gradient = cv2.applyColorMap(dist_normalized, cv2.COLORMAP_JET) # 方式2:自定义渐变,比如中心白色,边界黑色 custom_gradient = np.zeros((height, width, 3), dtype=np.uint8) # 三个通道都用归一化后的距离值,中心值高(白色),边界值低(黑色) custom_gradient[..., 0] = dist_normalized custom_gradient[..., 1] = dist_normalized custom_gradient[..., 2] = dist_normalized # 反向渐变的话,改成custom_gradient = 255 - dist_normalized[:, :, None] # 显示效果 cv2.imshow('Ellipse Gradient (OpenCV)', jet_gradient) cv2.waitKey(0) cv2.destroyAllWindows() # cv2.imwrite('ellipse_gradient_opencv.png', jet_gradient)
额外扩展
如果需要渐变到透明的效果,可以给图像加一个alpha通道,把归一化后的距离值映射到alpha通道的透明度(比如中心不透明,边界逐渐透明):
# 以OpenCV为例,添加alpha通道 rgba_img = cv2.cvtColor(jet_gradient, cv2.COLOR_BGR2BGRA) rgba_img[..., 3] = dist_normalized # alpha通道用距离值,中心255(不透明),边界0(透明)
内容的提问来源于stack exchange,提问作者huangbiubiu
相关产品推荐
相关产品推荐

