Python - Convert image to a string of pixel values

那年仲夏 提交于 2021-02-07 04:01:19

问题


I have a .jpg image captured from a webcam. It is a greyscale image. I need to convert the image to a string of its pixels like so:

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

How do I go about doing this?

Also, would changing the size of the image change these values?


回答1:


Assuming you have the image represented as a numpy array (since the question is tagged as OpenCV related, then this is likely the case), then to obtain the result you want, I'd take the following steps.

  • First flatten the array to make it linear.
  • Then turn it into a regular python list using tolist
  • Convert all the elements into strings using map and str
  • Join all the elements using spaces.

In steps it would look something like

# 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)

or, put together

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

Let's call this Variant 2 for performance testing purposes.


Update 1

Since numpy arrays are themselves iterable, we can skip the second step.

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

Unfortunately it seems that skipping this step has fairly significant negative effect on performance.

Let's call this Variant 3 for performance testing purposes.


Update 2

User Manel Fornos (deleted) answer gave me another idea. Although this approach is a bit hackish, it is somewhat faster.

The gist is to use the existing facilities to get a string represenation of a list, and filter out unwanted characters.

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

Let's call this Variant 4 for performance testing purposes.

Variant 1 will be a fixed up version of Liam Lawrence's code:

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

I wrote a simple little script to compare the algorithms (the full code is on pastebin). Here are the results:

# 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)


Update 3

Looking at the timings, one striking issue with Variant 1 is that its performance doesn't scale linearly with the size of input (number of pixels), as one may expect. Instead it looks more like O(n^2). The obvious culprit is the string addition -- since strings in Python are immutable, we keep copying progressively longer and longer strings as we add each pixel value.

One possible way to mitigate this problem is to use the cStringIO module.

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()

Let's call this Variant 5 for performance testing purposes.

Let's also include Manel Fornos' options, comprehension lists (Variant 6) and generators (Variant 7) for completeness.

# 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




回答2:


Use PIL and numpy

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]]

The result is an array of image pixels, it's up to you convert to the strings.




回答3:


For this example has been used an image with (1216, 1024) pixels.

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

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

1) The user Dan Mašek original answer (using 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) The user Dan Mašek alternative and faster answer (with my lowly help):

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

However, i'd like to share with you two more options, of course, slower than previous answers but also correct and efficient way.

3) Using a comprehension list:

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) Using a generator:

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

A generator is a bit faster because it yields items one by one using the iterator protocol instead of building a whole list just to feed another constructor, so it saves memory.



来源:https://stackoverflow.com/questions/43719451/python-convert-image-to-a-string-of-pixel-values

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!