Python - 将图像转换为一串像素值

Python - Convert image to a string of pixel values

我有一个从网络摄像头捕获的 .jpg 图像。这是一个灰度图像。我需要将图像转换为像素字符串,如下所示:

"255 232 45 678 56 23....345 76 44 767 433 345"

我该怎么做?

另外,改变图像的大小会改变这些值吗?

使用PILnumpy

from PIL import Image
import numpy as np 

img = Image.open('lena_bw.jpg')
print (np.array(img))

[[135 137 138 ..., 148 131  92]
 [136 137 138 ..., 149 134  96]
 [137 138 138 ..., 149 135  96]
 ..., 
 [ 20  21  24 ...,  71  71  70]
 [ 21  22  26 ...,  68  70  73]
 [ 23  24  28 ...,  67  69  75]]

结果是一个图像像素数组,由您决定是否转换为字符串。

假设您将图像表示为一个 numpy 数组(因为问题被标记为与 OpenCV 相关,那么很可能是这种情况),那么为了获得您想要的结果,我将采取以下步骤。

  • 首先flatten数组使其线性化。
  • 然后使用 tolist
  • 将其变成常规 python 列表
  • 使用map and str
  • 将所有元素转换为字符串
  • Join 所有元素都使用空格。

在步骤中它看起来像

# img is our input image represented by a numpy array
lin_img = img.flatten()
pixel_list = lin_img.tolist()
pixel_str_list = map(str, pixel_list)
img_str = ' '.join(pixel_str_list)

或者,放在一起

# img is our input image represented by a numpy array
img_str = ' '.join(map(str,img.flatten().tolist()))

为了性能测试的目的,我们称其为 变体 2


更新 1

由于numpy数组本身是可迭代的,我们可以跳过第二步。

# img is our input image represented by a numpy array
img_str = ' '.join(map(str,img.flatten()))

不幸的是,跳过这一步似乎对性能有相当大的负面影响。

我们称此为 变体 3 以进行性能测试。


更新 2

用户Manel Fornos(已删除)的回答给了我另一个想法。虽然这种方法有点hackish,但速度更快。

要点是使用现有工具获取列表的字符串表示,并过滤掉不需要的字符。

str_rep = str(img.flatten().tolist())
img_str = str_rep.strip('[]').replace(',','')

我们称此为 变体 4 以进行性能测试。

变体 1 将是 Liam Lawrence 代码的修正版本:

pxList = ''
# The height and width of your Mat
height = np.size(img, 0)
width = np.size(img, 1)

# Iterates through the values of your Mat and stores them in pxList
for i in range(height): 
    for j in range(width):
        pxList = pxList + " " + str(img[i][j])

pxList = pxList[1:] # Drop the first space

我写了一个简单的小脚本来比较算法(完整代码在 pastebin 上)。以下是结果:

# Pixels, Variant 1 (ms), Variant 2 (ms), Variant 3 (ms), Variant 4 (ms)
(1024, 2.8326225819203277, 0.13493335046772717, 1.5932890912113131, 0.09023493209332506)
(4096, 13.339841376487794, 0.5257651461289086, 6.325210327010836, 0.3265428986086241)
(9216, 32.98282323591406, 1.1823080866422975, 14.354809759340927, 0.7088365979475153)
(16384, 75.67087786296861, 2.1013669335069043, 26.917736751458644, 1.2577715882884644)
(25600, 137.34306664673863, 3.3527305844737176, 39.52922089259947, 1.9327700867009523)
(36864, 253.29441311675095, 4.734033934480575, 59.513813906516, 2.9113162427067962)
(50176, 451.560393848939, 6.5756611524649955, 80.0690276278131, 3.998343364868928)
(65536, 730.1453117644841, 8.744634443763166, 103.20875278841335, 5.7598277155337385)
(82944, 1111.2658522242352, 11.029055368769303, 131.75812149309473, 7.009532636131244)
(102400, 1660.044328259597, 13.671936656754369, 163.50234457172607, 8.832774137495392)
(123904, 3752.484254283715, 16.593065599119328, 196.8919234148476, 10.672515640955282)
(147456, 6808.498583618867, 20.05951524565397, 238.21070485215222, 13.339090582743296)
(173056, 11572.846199726502, 23.518125208653373, 275.5151841924039, 15.51396546209105)
(200704, 17107.24135330049, 27.29446060882168, 319.9635533287051, 17.9888784747817)
(230400, 24915.183616213795, 31.83344531218779, 368.9712484407863, 21.44858843792008)
(262144, 34914.46058437594, 36.754758635524354, 423.5016077462319, 24.536341210961155)


更新 3

看看时间,变体 1 的一个显着问题是它的性能并不像人们预期的那样与输入的大小(像素数)成线性关系。相反,它看起来更像是 O(n^2)。明显的罪魁祸首是字符串添加——因为 Python 中的字符串是不可变的,我们在添加每个像素值时不断复制越来越长的字符串。

缓解此问题的一种可能方法是使用 cStringIO 模块。

output = cStringIO.StringIO()
# The height and width of your Mat
height = np.size(img, 0)
width = np.size(img, 1)

# Iterates through the values of your Mat and stores them in pxList
for i in range(height): 
    for j in range(width):
        output.write(str(img[i][j]) + " ")

output.truncate(output.tell() - 1)
img_str = output.getvalue()

我们称此为 变体 5 以进行性能测试。

为了完整性,我们还包括 Manel Fornos' 选项、理解列表(变体 6)和生成器(变体 7) .

# Number of pixels, variants 1..7 (ms)
1024, 2.7356, 0.1330, 1.5844, 0.0870, 2.5578, 1.7027, 1.7354
4096, 13.0483, 0.5250, 6.3810, 0.3227, 10.3566, 6.7979, 6.9346
9216, 34.9096, 1.1787, 14.2764, 0.7047, 23.0620, 15.1704, 15.3179
16384, 72.0128, 2.1126, 25.5553, 1.2306, 41.0506, 27.7385, 28.6510
25600, 142.5863, 3.2655, 40.1804, 1.9044, 64.5345, 42.0542, 42.7847
36864, 265.1944, 4.7110, 57.3741, 2.9238, 94.8722, 62.3143, 61.8108
50176, 444.3202, 6.6906, 78.9869, 4.1656, 126.9877, 82.6736, 84.2270
65536, 739.3482, 8.6936, 101.6483, 5.5619, 163.1796, 110.7537, 111.7517
82944, 1125.0065, 11.1771, 133.8886, 7.0509, 209.9322, 137.3384, 143.7916
102400, 1700.3401, 13.8166, 161.2337, 8.7119, 261.8374, 171.3757, 175.0435
123904, 2304.6573, 16.8627, 196.3455, 10.8982, 314.8287, 205.1966, 210.4597
147456, 5595.0777, 19.8212, 240.1495, 12.9097, 381.7084, 251.7319, 253.3573
173056, 10813.7815, 23.5161, 273.9376, 15.6852, 441.5994, 291.8913, 295.0038
200704, 17561.0637, 27.4871, 322.6305, 17.9567, 517.7028, 340.2233, 342.6525
230400, 25331.5150, 31.6211, 368.3908, 21.0858, 597.7710, 387.3542, 398.9715
262144, 34097.1663, 36.3708, 420.1081, 23.9135, 677.7977, 443.1318, 453.0447

此示例使用了 (1216, 1024) 像素的图像。

In [1]: from PIL import Image
        import numpy as np

        img = np.array(Image.open("image_path"))

1)用户Dan Mašek原回答(使用map):

In [2]: %timeit -n10 to_string = ' '.join(map(str, img.flatten().tolist()))
Out[2]: 10 loops, best of 3: 187 ms per loop

2) 用户 Dan Mašek 替代和更快的答案(在我卑微的帮助下):

In [3]: %timeit -n10 to_string = str(img.flatten().tolist()).strip('[]').replace(',','')
Out[3]: 10 loops, best of 3: 96.4 ms per loop

但是,我想与您分享另外两个选项,当然,比以前的答案慢,但也是正确有效的方式。

3) 使用 综合列表:

In [4]: %timeit -n10 to_string = ' '.join([str(x) for x in img.flatten()])
Out[4]: 10 loops, best of 3: 1.41 s per loop

4) 使用 生成器:

In [5]: %timeit -n10 to_string = ' '.join((str(x) for x in img.flatten()))
Out[5]: 10 loops, best of 3: 1.37 s per loop

生成器要快一些,因为它使用迭代器协议一个一个地生成项目,而不是构建一个完整的列表来提供给另一个构造函数,因此它节省了内存。