Skimage技术问询:阈值化图像加黑边及旋转防裁切方法
Skimage图像处理问题解决方案
刚好处理过类似的图像需求,给你两个问题的具体实现方案,都是基于Skimage的原生函数,不用额外依赖:
问题1:为阈值化图像的顶部、底部及两侧添加黑色像素区域
这个需求其实很常见,Skimage专门提供了skimage.util.pad工具来做这件事,不用自己手动拼接数组。下面是完整的代码示例:
首先导入需要的库:
from skimage import io, filters, util import numpy as np
然后读取图像并完成阈值化处理:
# 读取灰度图像(如果是彩色图,记得先转灰度:img = rgb2gray(img)) img = io.imread('your_image_path.png', as_gray=True) # 用Otsu自动阈值化(你也可以换成手动阈值,比如thresh = 0.5) thresh = filters.threshold_otsu(img) binary_img = img > thresh
接下来就是添加黑边了,你可以自定义各边的像素宽度:
# 设置各边的填充宽度:格式为 ((顶部填充像素, 底部填充像素), (左侧填充像素, 右侧填充像素)) pad_width = ((80, 80), (40, 40)) # 示例:上下各加80像素,左右各加40像素 # 填充黑色(灰度图中0代表黑色,彩色图的话constant_values改成(0,0,0)) padded_binary_img = util.pad(binary_img, pad_width=pad_width, mode='constant', constant_values=0)
运行这段代码后,你就能得到四边带有指定宽度黑边的阈值化图像了。
问题2:旋转至主轴垂直+避免裁切的补边方法
这里的核心思路是先补边再旋转——因为旋转后被裁切的内容是无法恢复的,所以我们得先算出需要提前添加多少黑边,确保旋转后所有内容都能完整保留,同时四边的黑边等量。
步骤1:计算需要旋转的角度
首先我们要找到图像中前景区域的主轴方向,用skimage.measure.regionprops就能轻松获取:
from skimage import measure, transform # 给二值图打标签(获取前景区域的属性) labeled_img = measure.label(binary_img) # 获取第一个前景区域的属性(如果图像只有一个目标区域,直接取[0]即可) region_props = measure.regionprops(labeled_img)[0] # 将主轴方向的弧度值转成角度 orientation_deg = np.rad2deg(region_props.orientation) # 计算旋转角度:让主轴垂直,需要旋转的角度 = 90° - 主轴方向角度(注意符号可能需要微调,根据你的图像实际情况调整) rotate_angle = 90 - orientation_deg
步骤2:计算需要添加的黑边宽度
根据旋转角度,我们可以用三角函数算出旋转后的图像尺寸,然后计算需要给原图添加的padding,确保原图居中放置:
H, W = binary_img.shape theta_rad = np.deg2rad(rotate_angle) # 计算旋转后的理论尺寸(确保能装下所有内容) new_height = int(W * abs(np.sin(theta_rad)) + H * abs(np.cos(theta_rad))) new_width = int(W * abs(np.cos(theta_rad)) + H * abs(np.sin(theta_rad))) # 计算上下、左右需要添加的padding,保证原图居中 pad_top = (new_height - H) // 2 pad_bottom = new_height - H - pad_top pad_left = (new_width - W) // 2 pad_right = new_width - W - pad_left # 给原图添加黑边padding padded_for_rotate = util.pad(binary_img, pad_width=((pad_top, pad_bottom), (pad_left, pad_right)), mode='constant', constant_values=0)
步骤3:执行旋转
现在旋转图像就不会裁切内容了,用transform.rotate完成旋转:
# 旋转图像,保持尺寸不变(因为我们已经提前适配了合适的尺寸) rotated_img = transform.rotate(padded_for_rotate, rotate_angle, resize=False, preserve_range=True) # 转回二值图(rotate会把图像转成float类型,所以需要重新阈值化) rotated_binary_img = rotated_img > 0.5
这样得到的图像不仅主轴垂直、副轴水平,所有内容都完整保留,而且四边的黑边也是等量的。
内容的提问来源于stack exchange,提问作者Dante Martin
相关产品推荐
相关产品推荐

