I am trying to generate a color histogram of an image. I am using PIL for reading image files and trying to plot the same through matplotlib.
im = Image.open(sys.argv[1])
w, h = im.size
colors = im.getcolors(w*h) #Returns a list [(pixel_count, (R, G, B))]
Update: After some trial and error this code plots the histogram, but not the colors! (Takes laboriously long consumes ton loads of memory even for a 320x480 jpeg)
for idx, c in enumerate(colors):
plt.bar(idx, c[0], color=hexencode(c[1]))
plt.show()
Where,
def hexencode(rgb):
return '#%02x%02x%02x' % rgb
On execution, the program begins to consume infinite memory and no display is provided. OS memory usage went from < 380 MB to > 2.5 GB in matter of couple of minutes; post which I terminated the execution. How can I get solve the problem?
Here is an example of a color histogram of image with dominant Red shades:
matplotlib provides the hist method which is used to draw the histogram on specified data. Example: As per the above steps, First imported the required modules, and next we loaded an image using imread() method and using calcHist() method to get the RGB colors from Image and then plot the Histograms using the RGB data.
In image processing and photography, a color histogram is a representation of the distribution of colors in an image. For digital images, a color histogram represents the number of pixels that have colors in each of a fixed list of color ranges, that span the image's color space, the set of all possible colors.
To create an image histogram, use the imhist function. This function creates a histogram plot by making n equally spaced bins, each representing a range of data values. It then calculates the number of pixels within each range. The following example displays an image of grains of rice and a histogram based on 64 bins.
Histograms that deal with the specific color channels that are involved in generating the colors of your photo are referred to as RGB histograms, which represent red, green, and blue – the three primary colors used to produce all the colors that can be found in your photo.
I tried your update code and it worked fine. Here is exactly what I am trying:
import PIL
from PIL import Image
from matplotlib import pyplot as plt
im = Image.open('./color_gradient.png')
w, h = im.size
colors = im.getcolors(w*h)
def hexencode(rgb):
r=rgb[0]
g=rgb[1]
b=rgb[2]
return '#%02x%02x%02x' % (r,g,b)
for idx, c in enumerate(colors):
plt.bar(idx, c[0], color=hexencode(c[1]))
plt.show()
Update:
I think matplotlib is trying to put a black border around every bar. If there are too many bars, the bar is too thin to have color. If you have the toolbar, you can zoom in on the plot and see that the bars do indeed have color. So, if you set the edge color by:
for idx, c in enumerate(colors):
plt.bar(idx, c[0], color=hexencode(c[1]),edgecolor=hexencode(c[1]))
It works!
Image to be processed:
Result:
Profiling
Sorted by tottime:
ncalls tottime percall cumtime percall filename:lineno(function)
1 23.424 23.424 24.672 24.672 {built-in method mainloop}
460645 8.626 0.000 8.626 0.000 {numpy.core.multiarray.array}
22941 7.909 0.000 18.447 0.001 C:\Python27\lib\site-packages\matplotlib\artist.py:805(get_aliases)
6814123 3.900 0.000 3.900 0.000 {method 'startswith' of 'str' objects}
22941 2.244 0.000 2.244 0.000 {dir}
276714 2.140 0.000 2.140 0.000 C:\Python27\lib\weakref.py:243(__init__)
4336835 2.029 0.000 2.029 0.000 {getattr}
1927044 1.962 0.000 3.027 0.000 C:\Python27\lib\site-packages\matplotlib\artist.py:886(is_alias)
114811 1.852 0.000 3.883 0.000 C:\Python27\lib\site-packages\matplotlib\colors.py:317(to_rgba)
69559 1.653 0.000 2.841 0.000 C:\Python27\lib\site-packages\matplotlib\path.py:86(__init__)
68869 1.425 0.000 11.700 0.000 C:\Python27\lib\site-packages\matplotlib\patches.py:533(_update_patch_transform)
161205 1.316 0.000 1.618 0.000 C:\Python27\lib\site-packages\matplotlib\cbook.py:381(is_string_like)
1 1.232 1.232 1.232 1.232 {gc.collect}
344698 1.116 0.000 1.513 0.000 C:\Python27\lib\site-packages\matplotlib\cbook.py:372(iterable)
22947 1.111 0.000 3.768 0.000 {built-in method draw_path}
276692 1.024 0.000 3.164 0.000 C:\Python27\lib\site-packages\matplotlib\transforms.py:80(__init__)
2 1.021 0.510 1.801 0.900 C:\Python27\lib\site-packages\matplotlib\colors.py:355(to_rgba_array)
22947 0.818 0.000 14.677 0.001 C:\Python27\lib\site-packages\matplotlib\patches.py:371(draw)
183546/183539 0.793 0.000 2.030 0.000 C:\Python27\lib\site-packages\matplotlib\units.py:117(get_converter)
138006 0.756 0.000 1.267 0.000 C:\Python27\lib\site-packages\matplotlib\transforms.py:126(set_children)
Sorted by Cumulative Time
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.001 0.001 84.923 84.923 C:\Python27\test.py:23(imageProcess)
1 0.013 0.013 44.079 44.079 C:\Python27\lib\site-packages\matplotlib\pyplot.py:2080(bar)
1 0.286 0.286 43.825 43.825 C:\Python27\lib\site-packages\matplotlib\axes.py:4556(bar)
1 0.000 0.000 40.533 40.533 C:\Python27\lib\site-packages\matplotlib\pyplot.py:123(show)
1 0.000 0.000 40.533 40.533 C:\Python27\lib\site-packages\matplotlib\backend_bases.py:69(__call__)
22943 0.171 0.000 24.964 0.001 C:\Python27\lib\site-packages\matplotlib\patches.py:508(__init__)
1 0.000 0.000 24.672 24.672 C:\Python27\lib\site-packages\matplotlib\backends\backend_tkagg.py:68(mainloop)
1 0.000 0.000 24.672 24.672 C:\Python27\lib\lib-tk\Tkinter.py:323(mainloop)
1 23.424 23.424 24.672 24.672 {built-in method mainloop}
22947 0.499 0.000 24.654 0.001 C:\Python27\lib\site-packages\matplotlib\patches.py:55(__init__)
22941 0.492 0.000 20.180 0.001 C:\Python27\lib\site-packages\matplotlib\artist.py:1136(setp)
22941 0.135 0.000 18.730 0.001 C:\Python27\lib\site-packages\matplotlib\artist.py:788(__init__)
22941 7.909 0.000 18.447 0.001 C:\Python27\lib\site-packages\matplotlib\artist.py:805(get_aliases)
72/65 0.071 0.001 17.118 0.263 {built-in method call}
24/12 0.000 0.000 17.095 1.425 C:\Python27\lib\lib-tk\Tkinter.py:1405(__call__)
22941 0.188 0.000 16.647 0.001 C:\Python27\lib\site-packages\matplotlib\axes.py:1476(add_patch)
1 0.000 0.000 15.861 15.861 C:\Python27\lib\site-packages\matplotlib\backends\backend_tkagg.py:429(show)
1 0.000 0.000 15.861 15.861 C:\Python27\lib\lib-tk\Tkinter.py:909(update)
1 0.000 0.000 15.846 15.846 C:\Python27\lib\site-packages\matplotlib\backends\backend_tkagg.py:219(resize)
1 0.000 0.000 15.503 15.503 C:\Python27\lib\site-packages\matplotlib\backends\backend_tkagg.py:238(draw)
It seems that all the time is spent in matplotlib. If you want to speed it up, you can either find a different plotting tool or reduce the number of 'bars'. Try doing it yourself with rectangle on a canvas.
Timing:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With