Implementation of the classes in mosaic.flickr

Sunday, January 3, 2010 7:22 PM

After I had the idea of coding this I had this feeling of "fuck this is so brilliant why am i not coding" whenever i was NOT at the computer and typing" , so in about 8 hours of straight coding I had pretty much the rough implementation finished. in the next few posts i'll briefly describe their conception and show off some pretty neat code.

Photostream Class:
This class was pretty easy to write considering that a fairly large amount of work has been devoted to creating a useable flickr API for java. Thanks to jickr(which unfortunately, is no longer being developed), obtaining a stream of photos based on a search string has about all the difficulty of stealing candy from a well endowed baby. Based on a few search parameters, the Photostream class returns a list of Photo objects, from which I can obtain a BufferedImage of a desireable size.

ProcessPhotostream class:
This class will omnomnom the list of Photos and eventually organize them in an accessible datastructure. For simplicity's sake, I will save the bufferedimages at the size of 75x75 in folders, since by storing the data on the harddrive we sort of create a cache that's easily acccessed at the cost of some speed and storaged. To keep track of the folders we can use an int array to keep track of number of bufferedimages in each subfolder.
This class will begin by iterating through the list of photos, obtain the corresponding BufferedImages, and by some sort of analyzation method, sort them into folders. Firstly I will try to sort them by dominant hue, then I can write the code to sort by brightness(which is considerably simpler). Therefore the flow of this class will be like this:


for(Photo p:photos){
BufferedImage i = p.getImage(Photo.Size.Square);
process(i);
}

void process(BufferedImage b){
if(b==null)return;
...//insert processing code

//obtain an 'index' value which represents the image

//increment the counter in the int array which represents the number of pages with the current counter
database.map[index]++;

/*write the image to a file with its corresponding index.*/
ImageIO.write(b,"png",new File("output/"+index+"/"+database.map[index]+".png"));
}




To process the image, a simple(probably inefficient) way would be loop through all the pixels, and do calculations on the RGB value of each pixel. Since we want to find the dominant color of an image, we can simply find the average RGB of each pixel, and the resulting RGB will be the 'dominant' color. This is, of course, a large oversimplification of image processing, but it will have to do.


/*store the overall rgb values in these three variables, might have to use long for really large images*/
int r=0;
int g=0;
int b=0;


if(Constants.colored){//have a simple control variable for colored/monotone images
for(int i =0;i<Constants.size;i++){
for(int j =0;j<Constants.size;j++){

//getRGB() returns the colorvalue in the form of 0xAARRGGBB, a signed int
int c = bi.getRGB(i,j);

//performing & operation isolates the third byte, and shifts over by 2 bytes = 0x000000RR
int red = (c & 0x00ff0000) >> 16;

//isolates the second byte, shifts over by one byte = 0x000000GG
int green = (c & 0x0000ff00) >> 8;

//isolates the first byte = 0x000000BB
int blue = c & 0x000000ff;

//add the RGB values to the tracker variables
r+=red;
g+=green;
b+=blue;
}

}
//find the avg rgb
r/=Constants.size*Constants.size;
g/=Constants.size*Constants.size;
b/=Constants.size*Constants.size;



At this point, we can get by with simply 8 bit color(256 possible colors). however, for future development we might want more colors.

The 8 bit color architecture is a bit icky. in 8 bit color, the bits are ordered as RRRGGGBB in binary, which means 3 bits are devoted to red, 3 bits to green, and 2 bits to blue.

So first we'll want to convert the corresponding rgb values to its corresponding 8 bit color value:


r=(r>>5);//r was 8 bits, now it will be 3 bits
g=(g>>5);//g was 8 bits, now it will be 3 bits
b=(b>>6);//b was 8 bits, now it will be 2 bits


//r is now 00000RRR, shifting it to the left by 5 will make it RRR00000
//g is now 00000GGG, shifting it to the left by 2 will make it 000GGG00
//b is now 000000BB, no need to shift
//adding them together will produce RRRGGGBB
int index = (r<<5)+(g<<2)+b;



Note: Just because we shift r to the right by 5, then left by 5, does not mean these 2 operations cancel out. By shifting r to the right by 5, we effectively "set" the 5 rightmost bits to 0 when we shift it back to the left.

With the index we can now store the image to the appropriate folder and increment the appropriate element in the database array.

Next: using the image database to generate a mosaic.

0 comments:

Categories