2

What is away to break up an image into a grid of square cells, color each cell with the average color it contains, and export the resulting averages as a csv file?

Since ppms are simple image formats, conversion to ppm format may be a good place start, but what next?

Motivation: I am making a game world map and wish to convert a color coded map (colors indicate biome type) into a data file (such as csv) that is readable by other source code files.

Since the game map will be updated as the game is developed, I hope to automate this process, so I feel a code based solution would be optimal; it is written in C#.

Caleb
  • 148
  • 7
  • 1
    "how to proceed efficiently onward" - why do you worry about efficientcy if do have 0 effectiveness at the moment? Just go ahead, implement it and then measure whether efficientcy is a problem or not. – Thomas Weller Jan 26 '19 at 15:57
  • Edited to eliminate the efficiency concern. But to clarify, I just would like to avoid a long manual process of csv creation each time the map is updated – Caleb Jan 26 '19 at 16:02
  • A simple google search came up with [a good place to start](https://codereview.stackexchange.com/questions/140162/pixelate-image-with-average-cell-color). – Idle_Mind Jan 26 '19 at 16:21
  • It would help if you explained what values you actually want to write to a CSV file. If rgb(r,g,b) and you really want a CSV file, then the comma separators will be confusing due to the ones in the rgb values. Also do you want rgb or hex? Do you want it as rgb(r,g,b) or just the r,g,b values. – fmw42 Jan 26 '19 at 20:02

2 Answers2

3

You can use ImageMagick which is installed on most Linux distros and is available for macOS and Windows.

Just in Terminal (or Command Prompt on Windows), starting with this 500x256 image:

enter image description here

magick start.png -resize 3x2\! -depth 8 -compress none ppm:
P3
3 2
255
189 0 66 189 0 66 189 0 66 
66 0 189 66 0 189 66 0 189

That has resized the image and averaged the colours into a 3x2 image (choose a different size if you wish) and printed the output as a textual PPM file.

The size is 3x2, and the first row is 3 pixels with rgb(189,0,66) which is largely red and the second row is 3 pixels with rgb(66,0,189) which is largely blue.

I'll leave you to format as CSV :-)


Here you can resize it down and scale it back up to see the effect of averaging over 8x3 blocks:

magick start.png -resize 8x3\! -depth 8 -scale 400x result.png

enter image description here


Depending on what you like parsing, you can produce the same information in a slightly different format:

magick start.png -resize 8x3\! -depth 8 txt:

# ImageMagick pixel enumeration: 8,3,65535,srgb
0,0: (54998,0,10537)  #D60029  srgb(214,0,41)
1,0: (54998,0,10537)  #D60029  srgb(214,0,41)
2,0: (54998,0,10537)  #D60029  srgb(214,0,41)
3,0: (54998,0,10537)  #D60029  srgb(214,0,41)
4,0: (54998,0,10537)  #D60029  srgb(214,0,41)
5,0: (54998,0,10537)  #D60029  srgb(214,0,41)
...
...
3,1: (32896,0,32896)  #800080  purple
4,1: (32896,0,32896)  #800080  purple
5,1: (32896,0,32896)  #800080  purple
6,1: (32896,0,32896)  #800080  purple
7,1: (32896,0,32896)  #800080  purple
0,2: (10537,0,54998)  #2900D6  srgb(41,0,214)
5,2: (10537,0,54998)  #2900D6  srgb(41,0,214)
6,2: (10537,0,54998)  #2900D6  srgb(41,0,214)
7,2: (10537,0,54998)  #2900D6  srgb(41,0,214)
Mark Setchell
  • 191,897
  • 31
  • 273
  • 432
2

Here is a little bash script loop using Imagemagick to get the average colors of blocks of an image and write to a csv file

Input (256x256):

enter image description here

To get the proper average for blocks of the image, one should use -scale rather than -resize. So here I get a 4x4 set of averages of 64x64 blocks of colors from the image (256/4=64). Then I loop over each block in rows then columns and get the colors. I store the colors for each row in a string "rowlist" with commas between. After collecting each row of colors, I write it to a text file. The repeat for the next row.

convert image.png -scale 4x4! image2.png
for ((j=0; j<4; j++)); do
for ((i=0; i<4; i++)); do
rowcolor=`convert image2.png -crop 1x1+$i+$j +repage -format "rgb(%[fx:round(255*u.r)]_%[fx:round(255*u.g)]_%[fx:round(255*u.b)])" info:`
if [ $i -eq 0 ]; then
rowlist="$rowcolor"
else
rowlist="$rowlist,$rowcolor"
fi
done
echo "$rowlist" >> image_colors.txt
done


The data in the resulting text file is as follows:

rgb(8_0_247),rgb(50_0_205),rgb(50_0_205),rgb(8_0_247)
rgb(50_0_205),rgb(157_0_98),rgb(157_0_98),rgb(50_0_205)
rgb(50_0_205),rgb(157_0_98),rgb(157_0_98),rgb(50_0_205)
rgb(8_0_247),rgb(50_0_205),rgb(50_0_205),rgb(8_0_247)


You can remove the rgb( ), if you want and just keep the color values. I used _ to separate values, so that the commas would only be used between the rgb(...) colors. However, you may prefer to use tabs or spaces for the file separators so that the color values would be r,g,b rather than r_g_b.

It might be better in order to avoid comma confusion that one write colors as hex values. So to do that use:

convert image.png -scale 4x4! image2.png
for ((j=0; j<4; j++)); do
for ((i=0; i<4; i++)); do
rowcolor=`convert image2.png -depth 8 -crop 1x1+$i+$j +repage -format "#%[hex:u.p]" info:`
if [ $i -eq 0 ]; then
rowlist="$rowcolor"
else
rowlist="$rowlist,$rowcolor"
fi
done
echo "$rowlist" >> image_colors.txt
done


which produces the following values in the text file.

#0800F7,#3200CD,#3200CD,#0800F7
#3200CD,#9D0062,#9D0062,#3200CD
#3200CD,#9D0062,#9D0062,#3200CD
#0800F7,#3200CD,#3200CD,#0800F7


The use of %[hex:] is new to Imagemagick as of 2017-06-01 versions of Imagemagick 6 and 7.

fmw42
  • 46,825
  • 10
  • 62
  • 80
  • Why scale rather than resize, please? – Mark Setchell Jan 26 '19 at 20:34
  • 2
    Scale averages blocks of pixel. Resize interpolates pixels and so is not a proper average unless you specify -filter box. Other filters are doing a weighting in a local neighborhood and so are not considering each pixel equally in the averaging to resize. See https://imagemagick.org/script/command-line-options.php#scale vs https://imagemagick.org/script/command-line-options.php#resize and https://imagemagick.org/Usage/filter/#interpolated – fmw42 Jan 26 '19 at 22:27