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

遍历图像像素时NumPy数组切片shape意外变化问题

NumPy切片shape不符合预期问题排查

问题背景

修改边缘检测代码,通过自定义kernel实现航拍照片的边缘检测。所用测试图像初始shape为(876, 921, 3),实际读入后打印的shape为(611, 1400, 3)。

异常表现

调整行切片范围时,返回的数组shape不符合NumPy左闭右开切片规则的预期,测试结果如下:

horizontal_local_pixels = img[row-1:row+5, col-1:col+4, -1] 
# 实际返回shape =(5,6)
horizontal_local_pixels = img[row-1:row+6, col-1:col+4, -1] 
# 实际返回shape = (5,6)
horizontal_local_pixels = img[row-1:row+7, col-1:col+4, -1] 
# 实际返回shape = (5,8)

理论上row-1:row+6切片应返回shape为(7,5)的数组,但实际返回结果和row-1:row+5切片完全一致,均为(5,6)。

复现代码

import matplotlib.pyplot as plt
import numpy as np

# 定义垂直方向滤波器
vertical_filter = np.array([[-4, -3, -2, 0, 2, 3, 4],
                   [-3, -2, -1, 0, 1, 2, 3],
                   [-2, -1, -0.5, 0, 0.5, 1, 2],
                   [-3, -2, -1, 0, 1, 2, 3],
                   [-4, -3, -2, 0, 2, 3, 4]])

# 定义水平方向滤波器
horizontal_filter = np.array([[-4, -3, -2, -3, -4],
                     [-3, -2, -1, -2, -3],
                     [-1, -0.5, -0.25, -0.5, -1],
                     [0, 0, 0, 0, 0],
                     [1, 0.5, 0.25, 0.5, 1],
                     [3, 2, 1, 2, 3],
                     [4, 3, 2, 3, 4]])

# 读入测试图像
img = plt.imread('test.png')


# 获取图像维度
n,m,d = img.shape

# 初始化边缘检测结果图像
edges_img = img.copy()

# 遍历图像所有像素
for row in range(3, n-2):
    for col in range(3, m-2):
        
        # 提取水平滤波用局部像素块
        horizontal_local_pixels = img[row-1:row+6, col-1:col+4, 0]
        
        # 提取垂直滤波用局部像素块
        vertical_local_pixels = img[row-1:row+4, col-1:col+6, 0]
         
        # 应用垂直滤波器计算得分
        vertical_transformed_pixels = vertical_local_pixels.transpose().dot(vertical_filter)
        vertical_score = vertical_transformed_pixels.sum()/4
            
        # 应用水平滤波器计算得分
        horizontal_transformed_pixels = horizontal_local_pixels.transpose().dot(horizontal_filter)
        horizontal_score = horizontal_transformed_pixels.sum()/4
        
        # 合并两个方向的边缘得分
        edge_score = (vertical_score**2 + horizontal_score**2)**.5
        
        # 将得分写入结果图像
        edges_img[row, col] = [edge_score]*3
        
# 将结果值重映射到0-1区间,避免数值越界
edges_img = edges_img/edges_img.max()

异常原因

  • NumPy切片的边界截断机制:和Python原生列表切片逻辑一致,当切片的起始索引小于0,或结束索引大于数组最大索引时,不会抛出索引错误,会自动将切片范围截断到数组的实际起止位置。
  • 循环遍历范围没有给卷积核预留足够padding:7行5列的水平卷积核,需要提取的局部块是7行5列,对应切片img[row-1:row+6, col-1:col+4, :],要求row-1 >= 0且row+5 <= n-1、col-1 >=0且col+3 <=m-1,推导可得合法的row范围是1 <= row <=n-6,合法的col范围是1<=col <=m-4。现有代码写的遍历范围是range(3, n-2),row最大值为n-3,此时row+5 = n+2,远大于图像最大行索引n-1,切片会被直接截断到图像末尾,返回的行数自然达不到预期的7。列维度shape异常也是同样的截断逻辑导致。

修复方案

  • 调整循环的遍历范围,给卷积核预留足够的边缘padding,确保每次切片都不会超出图像边界:行遍历范围修改为range(3, n-5),列遍历范围修改为range(3, m-3)。
  • 如果需要处理图像边缘的像素,可以先用np.pad对原图做边缘填充,再执行卷积遍历。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 21:03:39