首页 > 解决方案 > 将 2 个图像转换为 numpy 数组并逐像素比较

问题描述

我正在使用 Pillow 加载 2 张图像(显然是黑白的,但采用 RGB 格式)并转换为灰度。我不能使用opencv。

aImage = Image.open(imageA.visualFilename).convert("L")
bImage = Image.open(imageB.visualFilename).convert("L")

我将它们转换为 numpy 数组。

aArray = np.array(aImage)
bArray = np.array(bImage)

我最终想要做的是(1)计算每个数组中的所有黑色像素,(2)逐像素比较 aArray 和 bArray 并计算匹配黑色像素的数量。

目前让我感到困惑的是,当我打印其中一个数组print aArray.shape时,我不明白我在看什么。我np.set_printoptions(threshold='nan')用来打印整个数组,但它似乎是一系列元素,其值比我预期的要多。我认为每个元素将包含单个 255 或 0?

为了使用黑白像素,我是否以正确的方式执行此操作?当我尝试转换为二进制“1”时,我得到了“True”/“False”结果,这让我更加困惑。

此外,假设 aArray 和 bArray 看起来相同,但实际上相差几个像素,那么将“模糊逻辑”结合到两者的逐像素比较中的最佳方法是什么?

仅用于获取更多信息,aImage.size然后aImage.mode返回

(184, 184)
L

标签: pythonarraysnumpypython-imaging-library

解决方案


对于初学者,L模式中的模式Image.open(visualFilename).convert("L")不会将图像转换为黑白,而是使用以下公式将图像转换为灰度:

L = R * 299/1000 + G * 587/1000 + B * 114/1000

分别为R、G、B,红、绿、蓝

此公式贯穿整个图像,并将 3 (RGB) 通道像素更改为最接近 3 通道配色方案的 1(灰度)通道像素。这就是为什么最后你不会只得到值 0 和 255。相反,你会得到一个值从 0 到 255 的像素。

要首先比较两个灰度图像之间的所有黑色像素,您必须定义黑色的真正含义。像 10 这样的值是否足够黑或 25 对您来说已经是黑的了?您必须记住,颜色不是绝对的,它的含义可能会根据您的操作而改变。

因此,解决此问题的一种方法是设置一个阈值,您将在其中定义“什么对您来说是黑色的”。使用一个简单的阈值函数就可以了。所以,我认为这个简单的代码可能会解决你的问题:

import numpy as np

def threshold(array, th=50, above_to_max = False):
  #check type numpy
  if type(array) is np.ndarray:
    #Creates a copy to not mess with original
    array = array.copy()
     #set all values below threshold to 0
    array[array<=th] = 0
    if above_to_max:
      #set all values above threshold to 0
      array[array>th] = 255
    return array
  else:
    raise Exception("Array must be a numpy array")

#Example images
image1 = [[ 0,  5, 10, 15, 20],
          [ 25, 30, 35, 40, 45],
          [ 50, 55, 60, 65, 70],
          [175,180,185,190,195],
          [200,210,215,240,255]]

image2 = [[ 5,  5, 110,  5,  0],
          [ 25, 30, 35,  0, 15],
          [150, 55, 60, 65, 70],
          [275,280,285,290,295],
          [ 20, 10, 15,240,255]]

#Transform to array
array1 = np.asarray(image1, dtype=np.uint8)
array2 = np.asarray(image2, dtype=np.uint8)

#Apply threshold
tsh_array1 = threshold(array1)
tsh_array2 = threshold(array2)

print(' Array1\n', array1, '\n', 'Thresholded1\n',tsh_array1,'\n' )
print(' Array2\n', array2, '\n', 'Thresholded2\n',tsh_array2,'\n' )
equals = (tsh_array1==0)[tsh_array2==0]

print("Number of pixels in the same position equal to zero: {}".format(sum(equals)))

此代码呈现以下内容:

Array1
[[  0   5  10  15  20]
 [ 25  30  35  40  45]
 [ 50  55  60  65  70]
 [175 180 185 190 195]
 [200 210 215 240 255]] 
Thresholded1
[[  0   0   0   0   0]
 [  0   0   0   0   0]
 [  0  55  60  65  70]
 [175 180 185 190 195]
 [200 210 215 240 255]] 

Array2
[[  5   5 110   5   0]
 [ 25  30  35   0  15]
 [150  55  60  65  70]
 [ 19  24  29  34  39]
 [ 20  10  15 240 255]] 
Thresholded2
[[  0   0 110   0   0]
 [  0   0   0   0   0]
 [150  55  60  65  70]
 [  0   0   0   0   0]
 [  0   0   0 240 255]] 

Number of pixels in the same position equal to zero: 9

编辑:

让我们更好地看一下以下行:(tsh_array1==0)[tsh_array2==0]

  • (tsh_array1==0)返回一个与0 值位置的tsh_array1值具有相同形状的数组,否则返回TrueFalse

  • [tsh_array2==0]与 where 分句相同。它过滤上一个项目,其中tsh_array2==0

结果是一个如下所示的数组:

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

由于 True 与 1 相同,因此该数组的和将返回两个数组中相同位置的零的个数

我希望它有帮助!


推荐阅读