3

I've been working on a script, and I need it to basically:

  • Make the image greyscale (or bitonal, I will play with both to see which one works better).
  • Process each individual column and create a net intensity value for each column.
  • Spit the results into an ordered list.

There is a really easy way to do this with ImageMagick (although you need a few Linux utilities to process the output text), but I'm not really seeing how to do this with Python and PIL.

Here's what I have so far:

from PIL import Image

image_file = 'test.tiff'

image = Image.open(image_file).convert('L')

histo = image.histogram()
histo_string = ''

for i in histo:
  histo_string += str(i) + "\n"

print(histo_string)

This outputs something (I am looking to graph the results), but it looks nothing like the ImageMagick output. I'm using this to detect the seam and content of a scanned book.

Thanks to anyone who helps!


I've got a (nasty-looking) solution that works, for now:

from PIL import Image
import numpy

def smoothListGaussian(list,degree=5):
  window=degree*2-1
  weight=numpy.array([1.0]*window)
  weightGauss=[]

  for i in range(window):
    i=i-degree+1
    frac=i/float(window)
    gauss=1/(numpy.exp((4*(frac))**2))
    weightGauss.append(gauss)

  weight=numpy.array(weightGauss)*weight
  smoothed=[0.0]*(len(list)-window)

  for i in range(len(smoothed)):
    smoothed[i]=sum(numpy.array(list[i:i+window])*weight)/sum(weight)

  return smoothed

image_file = 'verypurple.jpg'
out_file = 'out.tiff'

image = Image.open(image_file).convert('1')
image2 = image.load()
image.save(out_file)

intensities = []

for x in xrange(image.size[0]):
  intensities.append([])

  for y in xrange(image.size[1]):
    intensities[x].append(image2[x, y] )

plot = []

for x in xrange(image.size[0]):
  plot.append(0)

  for y in xrange(image.size[1]):
    plot[x] += intensities[x][y]

plot = smoothListGaussian(plot, 10)

plot_str = ''

for x in range(len(plot)):
  plot_str += str(plot[x]) + "\n"

print(plot_str)
Olli
  • 1,231
  • 15
  • 31
Blender
  • 289,723
  • 53
  • 439
  • 496

2 Answers2

11

I see you are using numpy. I would convert the greyscale image to a numpy array first, then use numpy to sum along an axis. Bonus: You'll probably find your smoothing function runs a lot faster when you fix it to accept an 1D array as input.

>>> from PIL import Image
>>> import numpy as np
>>> i = Image.open(r'C:\Pictures\pics\test.png')
>>> a = np.array(i.convert('L'))
>>> a.shape
(2000, 2000)
>>> b = a.sum(0) # or 1 depending on the axis you want to sum across
>>> b.shape
(2000,)
Paul
  • 42,322
  • 15
  • 106
  • 123
7

From the docs for PIL, histogram gives you a list of pixel counts for each pixel value in the image. If you have a grayscale image, there will be 256 different possible values, ranging from 0 to 255, and the list returned from image.histogram will have 256 entries.

Jason Sundram
  • 12,225
  • 19
  • 71
  • 86
  • It seems that I've been confusing a histogram with something else... It does give me the correct output, but it's not really what I'm looking for. I wanted to have basically a list of brightness (or intensity, I'm not familiar with this terminology) for every vertical column of pixels in the image. The histogram just gives me how many pixels fall into what color range. – Blender Nov 15 '10 at 20:00
  • 1
    The PIL maintainers moved that documentation link [here](http://www.effbot.org/imagingbook/image.htm#tag-Image.Image.histogram). – Lloyd MacLea May 08 '17 at 17:48
  • @Blender you definitely should have looked up the definition of "histogram" before you asked the question. PIL uses it the way I've known it for 35 years. – Mark Ransom Feb 06 '23 at 23:09