Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Histogram of an Image's "Black Ink Level" by Horizontal Axis

I have a black and white image (or pdf) file, and want to get a histogram of the image's horizontal profile. That is, for each column in the image I want the sum of the grayscale values of the pixels in the column. If the image is X by Y pixels, I will end up with X numbers between 0 (for an entirely black column) and 255*Y (for an entirely white column).

Please see the second panel of this comic Comic

I would like a histogram like this, but each bin would represent all the 'black ink' in the image at that x-coordinate (pixel).

As a poor graduate student, I'm constrained by using only the Linux command line, FOSS programs (ImageMagick, gnuplot, Perl, g++, etc). Something like the GIMP would only be helpful if I can run the command via terminal, as I won't have access to a GUI. A visual output file would be helpful for later, but is not necessary.

Does anyone know a way I can extract this information? Searches for "image profile" just lead to information on color profiles.

like image 428
user1717828 Avatar asked Oct 30 '12 23:10

user1717828


1 Answers

I will give an answer in two acts, using two of my favorite free utilities: python and gnuplot.

As a fellow (computational) graduate student, my advice is that if you want to do things for free python is one of the most versatile tools you can learn to use.

Here's a python script that does the first part, counting the grayscale value (from 0 for white to 255 for black):

#!/usr/bin/python

import Image            # basic image processing/manipulation, just what we want

im = Image.open('img.png')       # open the image file as a python image object
with open('data.dat', 'w') as f: # open the data file to be written
    for i in range(im.size[0]):  # loop over columns
        counter = sum(im.getpixel((i,j)) for j in range(im.size[1]))
        f.write(str(i)+'\t'+str(counter)+'\n')  # write to data file

Shockingly painless! Now to have gnuplot make a histogram*:

#!/usr/bin/gnuplot

set terminal pngcairo size 925,900
set output 'plot.png'
#set terminal pdfcairo
#set output 'plot.pdf'
set multiplot

## first plot
set origin 0,0.025              # this plot will be on the bottom
set size 1,0.75                 # and fill 3/4 of the whole canvas

set title "Black count in XKCD 'Self-Description'"
set xlabel 'Column'
set ylabel "Black\ncount" norotate offset screen 0.0125

set lmargin at screen 0.15      # make plot area correct size
set rmargin at screen 0.95      # width = 740 px = (0.95-0.15)*925 px

set border 0                    # these settings are just to make the data
set grid                        # stand out and not overlap with the tics, etc.
set tics nomirror
set xtics scale 0.5 out 
set ytics scale 0

set xr [0:740]                  # x range such that there is one spike/pixel

## uncomment if gnuplot version >= 4.6.0
## this will autoset the x and y ranges
#stats 'data.dat'
#set xr [STATS_min_x:STATS_max_x+1]
#set yr [STATS_min_y:STATS_may_y]

plot 'data.dat' with impulse notitle lc 'black'

## second plot
set origin 0,0.75               # this plot will be on top
set size 1,0.25                 # and fill 1/4 of the canvas

unset ylabel; unset xlabel      # clean up a bit...
unset border; unset grid; unset tics; unset title

set size ratio -1               # ensures image proper ratio
plot 'img.png' binary filetype=png with rgbimage

unset multiplot         # important to unset multiplot!

To run these scripts, save them in the same directory with the image you want to plot (in this case the XKCD comic, which I saved as img.png). Make them executable. In bash this is

$ chmod 755 grayscalecount.py plot.plt

Then (if python+image module+gnuplot are all installed), you can run

$ ./grayscalecount.py
$ ./plot.plt

On my computer, running Ubuntu 11.10 with gnuplot 4.4.3, I get this cool plot at the end:

enter image description here

**Side note*: there are a lot of different histogram plots gnuplot can make. I thought this style showed off the data well, but you can look into formatting your data for gnuplot histograms.

There are many ways to make python make plots itself or with gnuplot (matplotlib, pygnuplot, gnuplot-py), but I am not as facile with those. Gnuplot is awesomely scriptable for plotting, and there are lots of ways to make it play nicely with python, bash, C++, etc.

like image 71
andyras Avatar answered Oct 02 '22 21:10

andyras