首页 > 解决方案 > 在 python 中使用 for 循环将 skimage.filters.threshold_otsu() 应用于图像/数组中的段列表时面临问题

问题描述

我的问题在下面得到了清楚的解释:

import numpy as np
from skimage.util.shape import view_as_blocks
from skimage.filters import threshold_otsu

我已将灰度图像读取为数组“arr”,其形状为:

>>arr.shape

(10000, 15200)

我将该图像分割为 25*38 块。其中,每个块中有 400*400 像素,使用:

>>img= view_as_blocks(arr, block_shape=(400,400))
>>img.shape
(25, 38, 400, 400)

现在,当我使用 threshold_otsu() 分别查找每个段的阈值时,我得到了这些值:

print(threshold_otsu(img[11,6],16))
-14.606459

print(threshold_otsu(img[11,7],16))
-15.792943

print(threshold_otsu(img[11,11],16))
-15.547393

print(threshold_otsu(img[12,16],16))
-16.170353

但是当我使用for 循环一次获取所有阈值时,我得到了不同的值。

>>crdf
array([[11,  6],
       [11,  7],
       [11, 11],
       [12, 16],
       [10,  9],
       [21, 26],
       [15, 15],
       [12, 17],
       [12, 12],
       [14, 10],
       [20, 26]], dtype=int64) 

>>for i in range(0,4):
    >>print(threshold_otsu(img[crdf[i]],16))

-14.187654
-14.187654
-14.187654
-13.238304

我在 for 循环中做错了吗?如果没有,为什么当我为每个段单独执行时以及当我使用 for 循环对相同的相应段进行迭代时,我会得到不同的阈值。

标签: pythonimagenumpymultidimensional-arrayscikit-image

解决方案


当您使用 Numpy 数组索引到另一个 Numpy 数组时,您会触发高级索引,它的工作方式与基本索引不同,因此会产生您意想不到的结果。

为了使用基本索引,您需要确保使用逗号分隔的整数或标准 Python 元组进行索引。

因此,快速解决方法是将索引转换为元组:

img[tuple(crdf[i])]

但最好不要将 Numpy 数组用于索引列表。如果您不对索引批量执行数学运算或索引列表很短,则将其设为数组不会在性能上获得任何收益,甚至可能会因创建初始数组并将其转换回元组的开销而损失一些之后。

尝试一个简单的索引对列表,其中索引对本身就是元组:

crdf = [
    (11,  6),
    (11,  7),
    (11, 11),
    (12, 16),
    (10,  9),
    (21, 26),
    (15, 15),
    (12, 17),
    (12, 12),
    (14, 10),
    (20, 26)
]

# then you can iterate and index directly, without conversion:

for i in range(0, 4):
    print(threshold_otsu(img[crdf[i]], 16))

# or even like this, which is usually more idiomatic and easier to read:

for pair in crdf[:4]:
    print(threshold_otsu(img[pair], 16))

如果您crdf从其他处理中收到结果并且它已经是一个 Numpy 数组,您也可以先将其转换为元组列表:

crdf = [tuple(pair) for pair in crdf]

推荐阅读