Needing a little help/direction with a project. Our task is to take in a .ppm file (the one we are required to test with is found here: http://beastie.cs.ua.edu/cs250/projects/asciiart/tux.ppm) and reprint it out on the screen using ascii characters. We are required to convert the pixels to greyscale. This is really where I am stuck. Cannot figure out how to read in every three elements (because every three is a pixel in PPM files), convert them to greyscale and move on. Again PIL is not allowed. Any help or links on what to read up on would be awesome!
-
1which part is troubling you? Reading the elements? Calculating greyscale? printing them? or the language itself? – Lie Ryan Sep 10 '11 at 05:12
-
You don't need PIL. You can just look at the RGB values of each pixel, determine its greyscale value, and output an ASCII character of approximately the right density. – Gabe Sep 10 '11 at 05:13
-
Here is an SO question regarding the how - http://stackoverflow.com/questions/394882/how-do-ascii-art-image-conversion-algorithms-work – arunkumar Sep 10 '11 at 05:14
-
@lie ryan, I guess a little bit of everything. not the language, I am pretty decent at python, just a little behind on concepts and exactly how to go about doing some things. – Sep 10 '11 at 05:18
2 Answers
The PPM isn't hard to parse.
The header:
P3
50 50
255
P3
means that the image is an ASCII pixmap (color).50 50
is the width and height.255
is the max color value.
The body:
254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
254 254 252 254 254 252 254 254 252 253 255 250 239 244 237 251 255 248
234 236 231 255 255 251 252 251 249 255 254 251 253 248 242 255 255 244
...
Just remove all newlines:
body.replace('\n', ' ')
And parse it in triplets (not too elegant):
raw = body.split(' ')
for i in range(0, len(raw), 3):
red = raw[i]
green = raw[i + 1]
blue = raw[i + 2]

- 289,723
- 53
- 439
- 496
-
I don't believe that will work in python3 because I'm reading the PPM in as a list. – Sep 10 '11 at 05:32
-
2@crwhite If you can't figure that part out, your problem is with the language itself. – agf Sep 10 '11 at 05:41
-
well then I'm here for all of the help I can get. Rather rusty from the summer off of coding, just need some direction on what topics to read on maybe. Thanks for the comments though! – Sep 10 '11 at 05:52
-
@Blender when reading in using file.read() I end up getting an index error at the end for raw[i+2]. Mind explaining why? again I don't want the project done for me, just some topics to look up and read on. But any help is seriously appreciated – Sep 10 '11 at 05:55
-
@crwhite If the index error in raw[i+2] is at the end, maybe you could fix it doing `range(0, len(raw)-1, 3)` instead. – Diego Navarro Sep 10 '11 at 15:43
Reading the ppm file you can do this:
# Open the PPM file and process the 3 first lines
f = open("tux.ppm")
color = f.readline().splitlines()
size_x, size_y = f.readline().split()
max = f.readline().splitlines()
You really don't need to know about the 3 first lines of the file. You only must know that you are working with a RGB image, which means you have 3 values (0-255) for each pixel.
To convert the image to grayscale you have two options: you can either generate another PPM file (with 3 values per pixel) or you can generate a PGM file which has the same format as the PPM but the first line is P2
instead of P3
and you will have only one value per pixel (that's the cool way).
To convert a RGB color value (r,g,b) in one grayscale intensity value you can apply this formula (better than simply apply the average):
0.21*r + 0.71*g + 0.07*b
Generate the grayscale image with one value per pixel (if you want it in 3-values you only have to repeat 3 times it for r,g,b):
# Getting the image data (if you have read the 3 first lines...)
data = f.read().split()
# Generate a new array of pixels with grayscale values (1 per pixel)
gray_data = [0.21*data[i] + 0.71*data[i+1] + 0.07*data[i+2] for i in range(0,len(data),3)]

- 9,316
- 3
- 26
- 33
-
@ Deigo NAvarro, I tried implementing what you are saying, but at the end I am getting a Value Error of : can't multiply sequence by non-int type of float. I have tried casting the list named data to a float, but am again stuck. any pointers? – Sep 10 '11 at 22:22
-
@crwhite How are you casting? data[i] is a string value, so you have to convert it to float: it would be 0.21*float(data[i]), etc... – Diego Navarro Sep 10 '11 at 23:41