关于 scikit-image
scikit-image 是面向科研图像分析的 Python 库,以 NumPy 数组表示图像。它涵盖滤波、分割、特征检测、图像修复和对象测量等处理。
主要功能
- 01图像滤波与降噪
- 02分割与形态学处理
- 03特征和纹理检测
- 04图像修复与变换
- 05连通区域标记和测量
适用场景
- 01预处理含噪科研图像
- 02分割细胞或颗粒
- 03检测边缘、角点或纹理
- 04测量已标记对象的属性
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ tondevrel/ scientific-agent-skills --skill scikit-image安装后在 Claude Code 中输入/scikit-image确认已加载。
详细介绍
scikit-image - 科学图像处理
scikit-image 将图像视为 NumPy 数组。它提供了一套全面的算法,用于滤波、特征检测和对象测量,是研究级图像分析的标准工具。
适用场景
- 预处理科学图像(降噪、增强对比度)。
- 图像分割(分离细胞、颗粒或感兴趣区域)。
- 特征提取(检测边缘、角点、斑点或纹理)。
- 几何变换(缩放、旋转、扭曲)。
- 形态学操作(细化、骨架化、填充孔洞)。
- 测量对象属性(面积、周长、偏心率)。
- 修复退化图像(反卷积、修复)。
参考文档
官方文档:https://scikit-image.org/
用户指南:https://scikit-image.org/docs/stable/user_guide.html
搜索模式:skimage.filters、skimage.segmentation、skimage.feature、skimage.morphology
核心原则
图像是 NumPy 数组
灰度图像是一个二维数组 (M, N)。彩色图像是一个三维数组 (M, N, 3)。多通道三维体数据的形状为 (P, M, N, C)。
坐标系
原点 (0, 0) 位于左上角。坐标始终表示为 (行, 列)。
数据类型和范围
scikit-image 支持多种具有特定范围的数据类型:
uint8:0 到 255uint16:0 到 65535float:-1 到 1 或 0 到 1
快速参考
安装
pip install scikit-image
标准导入
import numpy as np
import matplotlib.pyplot as plt
from skimage import io, filters, segmentation, feature, measure, morphology, color, util
基本模式 - 加载和滤波
from skimage import io, filters, color
# Load image
image = io.imread('data.png')
# Convert to grayscale if needed
gray_image = color.rgb2gray(image)
# Apply a filter (e.g., Gaussian blur)
blurred = filters.gaussian(gray_image, sigma=2.0)
# Display
io.imshow(blurred)
io.show()
关键规则
✅ 应该做
- 使用实用函数进行转换 - 更改数据类型时,使用
util.img_as_float、util.img_as_ubyte自动处理重新缩放。 - 分析时使用灰度图 - 大多数特征提取和分割算法都需要二维灰度数组。
- 检查图像形状 - 处理前务必检查
image.shape和image.dtype。 - 使用向量化操作 - 使用 NumPy 操作,而不是循环遍历像素。
- 先滤波再分割 - 降噪(高斯、中值)可显著改善分割效果。
- 使用 label 统计对象 -
measure.label是识别连通分量的标准方法。
❌ 不应该做
- 手动重新缩放数据类型 - 避免使用
image / 255.0;请使用util.img_as_float。 - 忽略“坐标警告” - 注意 (x, y) 与 (row, col) 的区别。scikit-image 使用 (row, col)。
- 修改输入图像 - 大多数函数会返回新数组;如果需要修改,请使用副本。
- 对灰度图应用颜色敏感型滤波器 - 某些滤波器在三维数组和二维数组上的行为不同。
反模式(绝对不要这样做)
# ❌ BAD: Manual dtype conversion (doesn't handle scaling)
image_float = image.astype(float) # Values stay 0-255 but as floats
# ✅ GOOD: Safe utility conversion
from skimage import util
image_float = util.img_as_float(image) # Values scaled to 0.0-1.0
# ❌ BAD: Looping over pixels
for r in range(rows):
for c in range(cols):
if image[r, c] > 128:
image[r, c] = 255
# ✅ GOOD: Vectorized thresholding
image[image > 0.5] = 1.0
# ❌ BAD: Plotting multiple images without a shared axis
plt.imshow(img1); plt.show()
plt.imshow(img2); plt.show()
# ✅ GOOD: Using subplots for comparison
fig, ax = plt.subplots(1, 2)
ax[0].imshow(img1, cmap='gray')
ax[1].imshow(img2, cmap='gray')
滤波与修复(skimage.filters)
降噪和边缘检测
from skimage import filters
# Edge detection
edges_sobel = filters.sobel(image)
edges_canny = feature.canny(image, sigma=3)
# Denoising
denoised = filters.median(image, morphology.disk(3))
# Thresholding (Automatic)
val = filters.threshold_otsu(image)
binary = image > val
形态学(skimage.morphology)
形状处理和结构分析
from skimage import morphology
# Binary morphology
struct_element = morphology.disk(5)
eroded = morphology.erosion(binary, struct_element)
dilated = morphology.dilation(binary, struct_element)
opened = morphology.opening(binary, struct_element) # Erosion then Dilation
# Skeletonization (Reducing objects to 1-pixel width)
skeleton = morphology.skeletonize(binary)
# Removing small objects
clean_binary = morphology.remove_small_objects(binary, min_size=64)
分割(skimage.segmentation)
分离对象
from skimage import segmentation, color
# Watershed Segmentation (Marker-based)
from scipy import ndimage as ndi
distance = ndi.distance_transform_edt(binary)
coords = feature.peak_local_max(distance, footprint=np.ones((3, 3)), labels=binary)
mask = np.zeros(distance.shape, dtype=bool)
mask[tuple(coords.T)] = True
markers, _ = ndi.label(mask)
labels = segmentation.watershed(-distance, markers, mask=binary)
# SLIC (Superpixels)
segments = segmentation.slic(image, n_segments=100, compactness=10)
out = color.label2rgb(segments, image, kind='avg')
特征检测(skimage.feature)
关键点和纹理
from skimage import feature
# Local Binary Patterns (Texture analysis)
lbp = feature.local_binary_pattern(image, P=8, R=1)
# Corner detection (Harris)
coords = feature.corner_peaks(feature.corner_harris(image), min_distance=5)
# Blob detection (Difference of Gaussian)
blobs = feature.blob_dog(image, max_sigma=30, threshold=.1)
# blobs: array of [row, col, sigma]
测量(skimage.measure)
量化结果
from skimage import measure
# Label connected components
labels = measure.label(binary)
# Calculate properties
props = measure.regionprops(labels)
for prop in props:
print(f"Label: {prop.label}")
print(f"Area: {prop.area}")
print(f"Centroid: {prop.centroid}")
print(f"Eccentricity: {prop.eccentricity}")
# Find contours
contours = measure.find_contours(binary, 0.8)
实用工作流
1. 颗粒计数流程
def count_particles(image_path):
# 1. Load and grayscale
img = color.rgb2gray(io.imread(image_path))
# 2. Denoise
img_denoised = filters.gaussian(img, sigma=1)
# 3. Threshold
thresh = filters.threshold_otsu(img_denoised)
binary = img_denoised < thresh # Assuming dark particles
# 4. Morphological cleaning
binary = morphology.remove_small_objects(binary, 50)
binary = morphology.closing(binary, morphology.disk(3))
# 5. Label and measure
labels = measure.label(binary)
return measure.regionprops(labels), labels
# properties, label_img = count_particles('samples.tif')
2. 显微图像分析(细胞核分割)
def segment_nuclei(dna_image):
"""Identify nuclei in a DAPI/Hoechst stained image."""
# Local thresholding for uneven illumination
local_thresh = filters.threshold_local(dna_image, block_size=35)
binary = dna_image > local_thresh
# Fill holes
filled = ndi.binary_fill_holes(binary)
# Separate touching nuclei
distance = ndi.distance_transform_edt(filled)
local_maxi = feature.peak_local_max(distance, indices=False, footprint=np.ones((15, 15)), labels=filled)
markers = measure.label(local_maxi)
labels = segmentation.watershed(-distance, markers, mask=filled)
return labels
3. 变化检测(图像相减)
def detect_change(img_before, img_after, threshold=0.1):
# Ensure float
im1 = util.img_as_float(color.rgb2gray(img_before))
im2 = util.img_as_float(color.rgb2gray(img_after))
# Difference
diff = np.abs(im1 - im2)
# Filter noise in difference
diff_clean = filters.median(diff, morphology.disk(2))
return diff_clean > threshold
性能优化
使用 skimage.util.view_as_windows
from skimage.util import view_as_windows
# Create overlapping patches without copying data (using strides)
# Fast for local neighborhood calculations
patches = view_as_windows(image, (64, 64), step=32)
# Shape: (n_patches_r, n_patches_c, 64, 64)
并行处理
# Many skimage functions are already Cython-optimized.
# For batch processing, use standard joblib or multiprocessing.
from joblib import Parallel, delayed
results = Parallel(n_jobs=-1)(delayed(filters.gaussian)(img) for img in image_list)
常见问题及解决方案
处理多通道图像
# ❌ Problem: Filters failing on RGB images
# result = filters.median(rgb_image) # Raises error
# ✅ Solution: Filter per channel or convert
# filters.median(color.rgb2gray(rgb_image))
# OR apply to each channel
# result = np.stack([filters.median(rgb_image[..., i]) for i in range(3)], axis=-1)
label 的内存问题
# ❌ Problem: Large noisy images produce millions of 1-pixel labels
# ✅ Solution: Clear small noise before labeling
binary = morphology.remove_small_objects(binary, min_size=10)
labels = measure.label(binary)
坐标:(X, Y) 与 (Row, Col) 混淆
# ❌ Problem: Points appear swapped on plot
# Matplotlib: plt.plot(x, y)
# scikit-image: image[row, col]
# ✅ Solution: Explicitly swap for visualization
coords = feature.peak_local_max(img) # Returns [row, col]
plt.plot(coords[:, 1], coords[:, 0], 'r.') # Plot as [x, y]
scikit-image 提供了科学发现所需的严谨数学基础。借助 NumPy 生态系统,它让从原始传感器数据到可量化洞见的工作流畅通无阻。
评论
支持 Markdown