As I understand it right now Processing uses a 32bit value for each pixel in an image, devided into 8bits for each color plus an alpha channel.
However I would like load, modify and save grayscale images with a single 16bit channel. This type of image is often used as a heightmap. I attatched an image of the grand canyon as an example.
As of now I can load this image in processing, however I end up with the 3 collor channels containing identical 8bit values and so loose half of the 16bits I want to work with.
How many images are we talking about?
I want to load 2 of those images and output one. However the size of my example picture is not representative, I want to work with images up to 4100x4100 pixels. Speed is not an issue by the way.
I had a poke at it and here is what I got so far.
I’m using a .raw format now which I actually have easier acess to.
What I display in the green channel is already quite promissing. I still need to figure out what to do with the stuff I display in red though.
int HeightmapWidth = 100; //Width of the heightmap in pixels
byte[] Bytes; //Where I read my file to
short[] Shorts; //Hopeing to fill this with useful height data
color[] Colors; //Using this for easier debuging
void setup() {
size(100, 100);
Bytes = loadBytes("heightmap.raw"); //loading file into my Bytes array
Shorts = new short[Bytes.length / 2]; //initialising to the correct size
Colors = new color[Bytes.length / 2]; //initialising to the correct size
for ( int i = 0; i < Bytes.length; i=i+2) {
Shorts[i/2] = (short)(Bytes[i] << 8 | Bytes[i+1]); //not sure how the endianness works out yet
Colors[i/2] = color(Bytes[i], Bytes[i+1], 0); //just to visualise better
}
background(0);
for ( int j = 0; j < Colors.length; j++) {
set(j%HeightmapWidth, j/HeightmapWidth, Colors[j]); //just to visualise better
}
}
void draw() {
//nothing to do here
}
Apparently I can’t attatch my heightmap.raw so I uploaded it somewhere else. Please let me know if there is a better way to do this: https://www.file-upload.net/download-13590186/heightmap.raw.html
And here is the result of my code:
I think I actually got done what I wanted. Signed and unsigned datatypes had me tripped up.
So here is my code in case anyone searches for this.
For this example I just invert the height values of my heightmap.raw and save it as output.raw
int HeightmapWidth = 100; //Width of the heightmap in pixels
char[] input; //Where I read my file to
char[] chars; //Hopeing to fill this with useful height data
byte[] output; //I put my output in here
void setup() {
size(100, 100);
input = char(loadBytes("heightmap.raw")); //loading file into my Bytes array
chars = new char[input.length / 2]; //initialising to the correct size
output = new byte[input.length]; //initialising to the correct size
for ( int i = 0; i < input.length; i=i+2) {
chars[i/2] = (char)(input[i+1] << 8 | input[i]); //This endianess is the right for my application
}
background(0);
for ( int j = 0; j < chars.length; j++) {
chars[j] = char(65535-chars[j]); //Inverting the height values just to try it out
int gray8bit = int(map(chars[j], 0, 65535, 0, 255)); //turning it back into a regular color, just for display purposes
color gray = color(gray8bit, gray8bit, gray8bit);
set(j%HeightmapWidth, j/HeightmapWidth, gray); //displaying my result (yes would be faster with the pixels[] array)
}
for ( int k = 0; k < input.length; k++) {
if (k%2 == 1) { //getting it back in the correct byte order
output[k] = byte(chars[k/2]>>8);
} else {
output[k] = byte(chars[k/2]);
}
}
saveBytes("output.raw", output); //saving my output
}
void draw() {
//nothing to do here
}
And here is the result. I turned into a .png for ease of posting:
Thanks for sharing your results!
One small note, variable names should be with lowercase.
I’m not to keen on java conventions, but this one is important.
So int HeightmapWidth = 100;
should be int heightmapWidth = 100;
.
This makes it more readable for other programmers, specially if you have classes.
Cause if you have the instance of a class with a uppercase you can have thins like this:
Wrong:
class Foo {
int x = 10;
}
Foo Foo = new Foo();
println(Foo.x);
Now the println(Foo.x);
makes it look like we are printing a static variable from the class Foo while we actually print a variable local to the instance.