【问题标题】:finding height and width of an image using numpy and pixel locations使用 numpy 和像素位置查找图像的高度和宽度
【发布时间】:2019-03-26 15:03:40
【问题描述】:

我已将两个图像转换为 numpy 数组

image1Array

image2Array

两个图像都已转换为灰度,因此只有0255 值。

在这两个示例中,顶部(​​和底部)都有很多行白色:

[255 255 255 255 .... 255 255 255 255]

我相信我所说的“行”实际上是一个数组。我是使用 Numpy 的新手。因此,图像中的每一行都有一个数组,该行中的每个像素都用0255 表示。

如何找到包含黑色0 像素的第一行和包含黑色0 像素的最后一行?我应该可以用它来计算高度。在这些示例中,这应该是大致相同的数字。

我相信numpy.where(image1Array == 0)[0] 正在返回每个黑色像素的行; min()max() 这似乎是我正在寻找的东西,但我还不确定。

相反,如何找到每张图片的宽度?在这些示例中,Image 2 的宽度数应大于 Image 1

编辑

我想我只需要这样的东西:

高度(第一行黑色像素与最后一行黑色像素的差):

(max(numpy.where(image1Array == 0)[0])) - (min(numpy.where(image1Array == 0)[0]))

宽度(黑色像素的最低列值与黑色像素的最高列值之差):

(max(numpy.where(image1Array == 0)[1])) - (min(numpy.where(image1Array == 0)[1]))

到目前为止,我的测试表明这是正确的。比较上例中的两个图像,它们的高度相等,而 image2Array 的宽度是 image1Array 的两倍。

【问题讨论】:

  • 您可能对boolean array indexingnp.anynp.where 感兴趣。
  • @Rock Li,我正在寻找“盒子”内形状的大小。我需要从等式中消除所有边上的空白。
  • 对不起。我明白你现在想要做什么。我认为你可以做的是x, y = np.where(array==0) 然后shape = (np.amax(x) - np.amin(x) + 1, same for y + 1)
  • 那么你想要白色边距的大小(上、右、下、左)、黑色方块的大小(宽度和高度)还是包含黑色方块的数组?
  • @Rocky Li,我不确定是不是这样。我要返回成对的相同号码。 (55, 55) 和 (81,81)。当第二个看起来应该是 (55, 110) 时

标签: python numpy


【解决方案1】:

你会想要这样的:

mask = x == 0  # or `x != 255` where x is your array

columns_indices = np.where(np.any(mask, axis=0))[0]
rows_indices = np.where(np.any(mask, axis=1))[0]

first_column_index, last_column_index = columns_indices[0], columns_indices[-1]
first_row_index, last_row_index = rows_indices[0], rows_indices[-1]

说明:

让我们使用np.pad1

创建一个示例数组
import numpy as np


x = np.pad(array=np.zeros((3, 4)), 
           pad_width=((1, 2), (3, 4)),
           mode='constant',
           constant_values=255)
print(x)

[[255. 255. 255. 255. 255. 255. 255. 255. 255. 255. 255.]
 [255. 255. 255.   0.   0.   0.   0. 255. 255. 255. 255.]
 [255. 255. 255.   0.   0.   0.   0. 255. 255. 255. 255.]
 [255. 255. 255.   0.   0.   0.   0. 255. 255. 255. 255.]
 [255. 255. 255. 255. 255. 255. 255. 255. 255. 255. 255.]
 [255. 255. 255. 255. 255. 255. 255. 255. 255. 255. 255.]]

从这里我们可以得到一个零元素的boolean mask array,就这么简单:

mask = x == 0
print(mask)

[[False False False False False False False False False False False]
 [False False False  True  True  True  True False False False False]
 [False False False  True  True  True  True False False False False]
 [False False False  True  True  True  True False False False False]
 [False False False False False False False False False False False]
 [False False False False False False False False False False False]]

现在我们可以使用np.any 来获取那些至少有一个零元素的行。
对于列:

print(np.any(mask, axis=0))
>>> [False False False  True  True  True  True False False False False]

对于行:

print(np.any(mask, axis=1))
>>> [False  True  True  True False False]

现在我们只需要将布尔数组转换为索引数组2

columns_indices = np.where(np.any(mask, axis=0))[0]
print(columns_indices)
>>> [3 4 5 6]

rows_indices = np.where(np.any(mask, axis=1))[0]
print(rows_indices)
>>> [1 2 3]

从这里获取第一个和最后一个行/列索引非常简单:

first_column_index, last_column_index = columns_indices[0], columns_indices[-1]
first_row_index, last_row_index = rows_indices[0], rows_indices[-1]

时间安排:
我使用以下代码计算时间并绘制它们:Plot timings for a range of inputs.
将我的版本与您的版本进行比较,但重构如下:

indices = np.where(x == 0)
first_row_index, last_row_index = indices[0][0], indices[0][-1]
first_column_index, last_column_index = indices[1][0], indices[1][-1]
plot_times([georgy_solution, yodish_solution],
           np.arange(10, 200, 5), 
           repeats=500)

plot_times([georgy_solution, yodish_solution],
           np.arange(200, 10000, 800), 
           repeats=1)


1 请参阅How to pad numpy array with zeros 以获取很好的示例。
2How to turn a boolean array into index array in numpy

【讨论】:

  • 谢谢你。我很欣赏这个步骤。我很好奇,您是否发现我在对原始帖子的编辑中描述的方法有任何明显的缺陷?如果是这样,我一定会尝试一下。
  • 在您的示例中,您计算​​了四次numpy.where(image1Array == 0),这非常低效并且违反了DRY。此外,您也可以获取第一个和最后一个索引,而不是搜索 minmax。重构后,您的示例将如下所示:indices = np.where(image1Array == 0); first_row_index, last_row_index = indices[0][0], indices[0][-1]; first_column_index, last_column_index = indices[1][0], indices[1][-1]...
  • ... 实际上,对于较小的阵列,这会比我的解决方案更快。但对于更大的阵列,np.any 的解决方案将获胜。我会尽力提供一些证据。
  • @yodish 添加了一些图作为证明
  • 非常感谢,我相信我的方式也容易出错。当未填充形状时(如示例中),我遇到了问题。
【解决方案2】:

这是一个适用于 python 2 或 python 3 的脚本。如果您使用 IPython 或 jupyter,“魔术”%pylab 会为您完成所有导入,您不需要所有 from... 语句。在这些声明之后,我们会创建一张与您发布的图片类似的图片。

from __future__ import print_function # makes script work with python 2 and python 3
from matplotlib.pyplot import show, imshow, imread
from matplotlib.mlab import find
from numpy import zeros, int8, sum

img1 = zeros((256, 256), dtype=int8)
img1[50:200, 100:150] = 100
imshow(img1) 
show() # You don't need this call if you are using ipython or jupyter
# You now see a figure like the first one you posted
print('Axis 0 blob limits', find(sum(img1, axis=0) != 0)[[0, -1]]) 
print('Axis 1 blob limits', find(sum(img1, axis=1) != 0)[[0, -1]])

sum 函数与axis 的显式规范一起使用,使其沿给定方向返回总和。 find 函数返回条件为真的所有索引的数组,在这种情况下“列或行总和为零?”最后,切片[0, -1] 选择找到的第一列和最后一列。

如果您的图像没有任何行或任何全为零的列,find 返回一个空数组,并且索引尝试[0, -1] 引发IndexError。如果你在它周围包裹一个try...except 块,你可以美化错误条件。

【讨论】:

  • find 很感兴趣,...我在 Python2 或 Python3 中都没有任何弃用警告。它的替代品是什么?
  • @FrankM numpy.__version__ 返回什么?除非是 2.2 或更高版本,否则您不会收到警告
  • 我很感激,我试图避免使用 matplotlib 并找出一个仅使用 numpy 的更简单的解决方案。
  • @yodish:您可以使用 numpy 库中的“非零”而不是“查找”。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-09
  • 2011-08-28
  • 1970-01-01
  • 2012-03-01
相关资源
最近更新 更多