extract_block_features.c

Go to the documentation of this file.
00001 /* -*- mode: c -*- 
00002 */
00003 /* 
00004 
00005     GIFT, a flexible content based image retrieval system.
00006     Copyright (C) 1998, 1999, 2000, 2001, 2002, CUI University of Geneva
00007 
00008     This program is free software; you can redistribute it and/or modify
00009     it under the terms of the GNU General Public License as published by
00010     the Free Software Foundation; either version 2 of the License, or
00011     (at your option) any later version.
00012 
00013     This program is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016     GNU General Public License for more details.
00017 
00018     You should have received a copy of the GNU General Public License
00019     along with this program; if not, write to the Free Software
00020     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021 
00022 */
00023 
00024 /* for fprintf(), fopen(), EOF... */
00025 #include <stdio.h>
00026 
00027 /* for memalign() */
00028 #include <malloc.h>
00029 
00030 /* for M_PI */
00031 #include <math.h>
00032 
00033 /* for uint32_t */
00034 #include <stdint.h>
00035 
00036 #ifdef HAVE_CONFIG_H
00037 #include "gift-config.h"
00038 #endif
00039 
00040 #include <ppm.h>
00041 
00042 /* for type FEATURE_DATA, FREQ_MAX, and freq_type */
00043 #include <gift_features.h>
00044 
00045 //#include "gabor.h"
00046 //#include "extract_features.proto"
00047 
00048 #define square(x) ((x)*(x))
00049 
00050 /* This determines the number of bands into which the gabor filter energies
00051  * are quantized.
00052  *
00053  * valid values are 10 or 16.
00054  *
00055  */
00056 #define num_gabor_ranges 10
00057 
00058 /* define these here, so we dont have to include gabor.h */
00059 
00060 /* the number of scales to recognise features at */
00061 #define num_gabor_scales 3
00062 /* the number of directions to apply the filters. (top-bottom, left-right, bottom-top, right-left?) */
00063 #define num_gabors_per_scale 4
00064 
00065 /* parts surrounded in OLDFIXED are dependant on the image being a 256x256 image */
00066 #define OLDFIXED 1
00067 
00068 /* FIXME: broken code. relies on OLDFIXED */
00069 #ifdef OLDFIXED
00070 /* width AND height of the target image */
00071 #define image_size 256
00072 /* the number of color blocks we're going to break the image into (overlapping) */
00073 #define num_total_colour_blocks (256+64+16+4)
00074 /* the width and height of the smallest blocks of region colour averages */
00075 #define smallest_colour_block 16
00076 #endif
00077 
00078 /* FIXME: ??? */
00079 #define gabor_block_size 16
00080 
00081 #ifdef OLDFIXED 
00082 /* num_colour_scales=what_power_of_two(r). r=image_size/smallest_colour_block. EG ?r==16:ncs=4;?r==256:ncs=8 */
00083 /* this tells us how many levels we're going to sample this image at. first sample is 256 16x16 blocks, then 64 32x32.. then.. */
00084 #define num_colour_scales 4
00085 #define num_blocks_at_scale(i) (256>>i*2)
00086 #endif
00087 
00088 /* This specifies the bands into which the gabor filter energies are
00089  * quantized.
00090  */
00091 
00092 #if num_gabor_ranges==16
00093 #define gabor_ranges(i) gabor_ranges_var[i]
00094 double gabor_ranges_var[num_gabor_ranges] = {0.0625, 0.125, 0.25, 0.5, 1, 1.5, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100000};
00095 #else
00096 #if num_gabor_ranges==10
00097 /* this is magic, as far as i'm concerned. [2..10,100000] */
00098 #define gabor_ranges(i) (i+2+99989*(((i>>3)&1)&(i&1)))
00099 #else
00100 #error invalid setting for num_gabor_ranges
00101 #endif
00102 #endif
00103 
00104 /* this version just does the work. no variable width/height information is taken into account. 256x256. */
00105 void init_feature_variables(uint32_t colmap_size, uint32_t ** col_counts, uint32_t *** block_gabor_class, uint32_t *** gabor_histogram) {
00106 
00107   uint32_t i, j, k=0;
00108   /* colour features */
00109   for (i = 0; i < num_colour_scales; i++) {
00110     for (j = 0; j < num_blocks_at_scale(i); j++) {
00111       col_counts[k++] = (uint32_t *)malloc(colmap_size*sizeof(uint32_t));
00112     }
00113   }
00114 
00115   /* Gabor features */
00116   for (i = 0; i < num_gabor_scales; i++) {
00117     block_gabor_class[i] = (uint32_t **)malloc(num_gabors_per_scale*sizeof(uint32_t *));
00118     gabor_histogram[i] = (uint32_t **)malloc(num_gabors_per_scale*sizeof(uint32_t *));
00119     for (j = 0; j < num_gabors_per_scale; j++) {
00120       block_gabor_class[i][j] = (uint32_t *)malloc(square(image_size/gabor_block_size)*sizeof(uint32_t));
00121       gabor_histogram[i][j] = (uint32_t *)calloc(num_gabor_ranges, sizeof(uint32_t));
00122     }
00123   }
00124 }
00125 
00126 void extract_gabor_features(PPM *im_hsv, uint32_t *** block_gabor_class, uint32_t *** gabor_histogram) {
00127 
00128   int i, j, x, y, k;
00129   int scale, orientation;
00130   int energy_class;
00131   PPM *value_plane;
00132   double *value_image_dbl, *filtered_image;
00133   double *conv;
00134   double *conv2;
00135   double gabor_mean;
00136   double * kernelsxy[num_gabor_scales*num_gabors_per_scale];
00137 
00138   /* for Gabor features, this is what I'm going to do:
00139     - Apply each of the 12 filters (3 scales, 4 orientations) to each
00140       pixel in the image.
00141     - Use 16x16 blocks only.
00142     - In each block find the rms energy of each filter.
00143     - quantize these into num_gabor_ranges levels, as specified in the
00144       "array" gabor_ranges[]
00145   */
00146 
00147   /* this is all created with one malloc, so that it can be cleared in one memset() call */
00148   filtered_image = (double *)malloc(im_hsv->width*im_hsv->height*sizeof(double)*3);
00149   conv=&filtered_image[im_hsv->width*im_hsv->height];
00150   conv2=&conv[im_hsv->width*im_hsv->height];
00151 
00152   create_filter_kernels(kernelsxy);
00153 
00154   /* apply each filter to the image */
00155   for (scale = 0; scale < num_gabor_scales; scale++) {
00156     for (orientation = 0; orientation < num_gabors_per_scale; orientation++) {
00157 
00158       /* this clears conv, conv2, and filtered_image in one call. */
00159       memset(filtered_image, 0, MAX_WIDTH*MAX_HEIGHT*sizeof(double)*3);
00160 
00161       /* filter the image */
00162       gabor_filter(im_hsv->value_plane_double_reversed, im_hsv->width, im_hsv->height, scale, orientation, kernelsxy, conv, conv2, filtered_image);
00163 
00164       /* extract the rms energy for each block */
00165       k = 0; /* block counter */
00166       for (y = 0; y < im_hsv->height; y += gabor_block_size) {
00167       for (x = 0; x < im_hsv->width; x += gabor_block_size) {
00168         gabor_mean = 0;
00169         for (i = 0; (i < gabor_block_size) &&  (y+i < im_hsv->height); i++) {
00170         for (j = 0; (j < gabor_block_size) &&  (x+j < im_hsv->height); j++) {
00171           gabor_mean += square((filtered_image[(y + i)*im_hsv->width + (x + j)]));
00172         }
00173         }
00174         gabor_mean /= square(gabor_block_size);
00175         gabor_mean = sqrt(gabor_mean);
00176 
00177         /* find the energy class for this block */
00178         for (energy_class = 0; energy_class < num_gabor_ranges; energy_class++) {
00179           if (gabor_mean < gabor_ranges(energy_class))
00180             break;
00181         }
00182 
00183         /* store this class in the appropriate place */
00184         block_gabor_class[scale][orientation][k] = energy_class;
00185 
00186         /* increment the histogram entry for this combination */
00187         gabor_histogram[scale][orientation][energy_class]++;
00188         
00189         k++; /* increment block counter */
00190       }
00191       }
00192     }
00193   }
00194 }
00195 
00196 void extract_mode_features(PPM *im, uint32_t *colmap, uint32_t colmap_size, uint32_t ** col_counts, byte * block_mode, uint32_t * col_histogram) {
00197 
00198   int i, j, k, last_k, k1, m, n, r, x, y;
00199   byte colour;
00200   int scale, block_size, num_blocks, old_num_blocks;
00201   int max_count, mode_index;
00202   int b1, b2, b3, b4;
00203 #ifdef GENERATE_BLOCK_IMAGES
00204   PPM *out_image, *out_image_hsv, *out_image_rgb;
00205   enum ppm_error the_error;
00206   FILE *outfile;
00207   char out_fname[256];
00208 #endif
00209 
00210 #ifdef GENERATE_BLOCK_IMAGES
00211     /* make space for an HSV image of the same size as that read */
00212     out_image = new_ppm();
00213     out_image->type = PGM_RAW;
00214     out_image->width = im->width;
00215     out_image->height = im->height;
00216     out_image->max_col_comp = im->max_col_comp;
00217     out_image->bytes_per_pixel = 1;
00218     out_image->pixel = (byte *)malloc(out_image->width*out_image->height*sizeof(byte));
00219 #endif
00220 
00221   /* first extract the lowest level blocks, directly from the pixels of
00222   the PGM image */
00223   scale = 0;
00224   block_size = smallest_colour_block;
00225   num_blocks = square(image_size/block_size);
00226   k = last_k = 0;
00227   for (y = 0; y < im->height; y += block_size) {
00228   for (x = 0; x < im->width; x += block_size) {
00229     for (n = 0; n < colmap_size; n++) {
00230       col_counts[k][n] = 0; 
00231     }
00232     for (i = 0; (i < block_size) && (y+i < im->height); i++) {
00233       for (j = 0; (j < block_size) && (x+j < im->width); j++) {
00234         colour = im->pixel[(y + j)*im->width + (x + i)];
00235         col_counts[k][colour]++;
00236       }
00237     }
00238 
00239     /* find the mode */
00240     max_count = mode_index = 0;
00241     for (n = 0; n < colmap_size; n++) {
00242       if (col_counts[k][n] > max_count) {
00243         max_count = col_counts[k][n];
00244         mode_index = n;
00245       }
00246     }
00247     block_mode[k] = mode_index;
00248     k++;
00249   }
00250   }
00251 
00252 #ifdef GENERATE_BLOCK_IMAGES
00253   /* generate an image with this */ 
00254   k1 = 0;
00255   for (y = 0; y < im->height; y += block_size) {
00256   for (x = 0; x < im->width; x += block_size) {
00257     for (i = 0; i < block_size; i++) {
00258     for (j = 0; j < block_size; j++) {
00259       out_image->pixel[(y + j)*im->width + (x + i)] = block_mode[k1];
00260     }
00261     }
00262     k1++;
00263   }
00264   }
00265   /* convert from the colour map to an HSV image */
00266   if ((the_error = colmap2rgb_ppm(out_image, colmap, colmap_size, &out_image_hsv)) != PPM_OK) {
00267     ppm_handle_error(the_error);
00268     exit(1);
00269   }
00270   /* convert to RGB */
00271   if ((the_error = hsv2rgb_ppm(out_image_hsv, &out_image_rgb)) != PPM_OK) {
00272     ppm_handle_error(the_error);
00273     exit(1);
00274   }
00275   /* write it */
00276   sprintf(out_fname, "blocks_%dx%d.ppm", block_size, block_size);
00277   outfile = fopen(out_fname, "wb");
00278   if ((the_error = write_ppm(outfile, out_image_rgb, PPM_RAW)) != PPM_OK) {
00279     ppm_handle_error(the_error);
00280     exit(1);
00281   }
00282   fclose(outfile);
00283   destroy_ppm(&out_image_rgb);
00284   destroy_ppm(&out_image_hsv);
00285 #endif
00286 
00287 
00288   /* now do the other scales */
00289   for (scale = 1; scale < num_colour_scales; scale++) {
00290     block_size *= 2;
00291     num_blocks /= 4;
00292     r = (int)sqrt((double)num_blocks);
00293     for (i = 0; i < num_blocks; i++) {
00294       m = (i/r)*2*r; /* note: this first is *integer* division */
00295       b1 = last_k + 2*i + m;
00296       b2 = last_k + 2*i + m + 1;
00297       b3 = last_k + 2*i + m + 2*r;
00298       b4 = last_k + 2*i + m + 2*r + 1;
00299       max_count = mode_index = 0;
00300       for (n = 0; n < colmap_size; n++) {
00301         col_counts[k + i][n] = 
00302           col_counts[b1][n] + col_counts[b2][n] + 
00303           col_counts[b3][n] + col_counts[b4][n];
00304         if (col_counts[k + i][n] > max_count) {
00305           max_count = col_counts[k + i][n];
00306           mode_index = n;
00307         }
00308       }
00309       block_mode[k + i] = mode_index;
00310     }
00311 #ifdef GENERATE_BLOCK_IMAGES
00312     /* generate an image with this */ 
00313     for (y = 0; y < im->height; y += block_size) {
00314     for (x = 0; x < im->width; x += block_size) {
00315       for (i = 0; i < block_size; i++) {
00316       for (j = 0; j < block_size; j++) {
00317         out_image->pixel[(y + j)*im->width + (x + i)] = block_mode[k1];
00318       }
00319       }
00320       k1++;
00321     }
00322     }
00323     /* convert from the colour map to an HSV image */
00324     if ((the_error = colmap2rgb_ppm(out_image, colmap, colmap_size, &out_image_hsv)) != PPM_OK) {
00325       ppm_handle_error(the_error);
00326       exit(1);
00327     }
00328     /* convert to RGB */
00329     if ((the_error = hsv2rgb_ppm(out_image_hsv, &out_image_rgb)) != PPM_OK) {
00330       ppm_handle_error(the_error);
00331       exit(1);
00332     }
00333     /* write it */
00334     sprintf(out_fname, "blocks_%dx%d.ppm", block_size, block_size);
00335     outfile = fopen(out_fname, "wb");
00336     if ((the_error = write_ppm(outfile, out_image_rgb, PPM_RAW)) != PPM_OK) {
00337       ppm_handle_error(the_error);
00338       exit(1);
00339     }
00340     fclose(outfile);
00341     destroy_ppm(&out_image_rgb);
00342     destroy_ppm(&out_image_hsv);
00343 #endif
00344     last_k = k;
00345     k += num_blocks;
00346   }
00347 
00348   /* now finally consolidate all the colour counts to produce the
00349   histogram for the whole image */
00350   k -= num_blocks;
00351   for (n = 0; n < colmap_size; n++)
00352     col_histogram[n] = 
00353       col_counts[k][n] + col_counts[k + 1][n] + 
00354       col_counts[k + 2][n] + col_counts[k + 3][n];
00355 }
00356 
00357 enum ppm_error write_mode_features(char *out_fname, uint32_t colmap_size, uint32_t * col_histogram, uint32_t *** block_gabor_class, uint32_t *** gabor_histogram, byte * block_mode) {
00358 
00359   FILE *out_file = NULL;
00360   int feature_index;
00361   int block_features_offset;
00362   int scale, orientation, energy_class;
00363   int num_features;
00364   FEATURE_DATA *feature;
00365   int i;
00366 
00367   /***** count the features *****/
00368 
00369   /* we know that there will be a mode color for each block */
00370   num_features = num_total_colour_blocks;
00371 
00372   /* and there will be one for each non-zero histogram entry. Convert
00373   histogram entries to range [0, FREQ_MAX] while we're at it */
00374   for (i = 0; i < colmap_size; i++) {
00375     col_histogram[i] = (int)(rint(FREQ_MAX*(double)col_histogram[i]/(double)(square(image_size))));
00376     if (col_histogram[i] != 0)
00377       num_features++;
00378   }
00379 
00380 #ifdef NO_FLAT_FEATURES
00381   /* count the block entries which are not of class zero (which indicates
00382   a filter response too low to write), and the non-zero gabor histogram
00383   entries */
00384   for (scale = 0; scale < num_gabor_scales; scale++) {
00385     for (orientation = 0; orientation < num_gabors_per_scale; orientation++) {
00386       /* blocks */
00387       for (i = 0; i < square((image_size/gabor_block_size)); i++) {
00388         if (block_gabor_class[scale][orientation][i] != 0)
00389           num_features++;
00390       }
00391 
00392       /* histogram */
00393       for (energy_class = 0; energy_class < num_gabor_ranges; energy_class++) {
00394         if (gabor_histogram[scale][orientation][energy_class] != 0)
00395           num_features++;
00396       }
00397     }
00398   }
00399 #else
00400   /* here we ARE storing features for filter responses in the lowest
00401    * energy band, so the number of block features is fixed (and v.
00402    * large!). We also count the non-zero gabor histogram entries */
00403 
00404   /* blocks */
00405   num_features += num_gabor_scales*num_gabors_per_scale*square((image_size/gabor_block_size));
00406 
00407   /* histogram */
00408   for (scale = 0; scale < num_gabor_scales; scale++) {
00409     for (orientation = 0; orientation < num_gabors_per_scale; orientation++) {
00410       for (energy_class = 0; energy_class < num_gabor_ranges; energy_class++) {
00411         if (gabor_histogram[scale][orientation][energy_class] != 0)
00412           num_features++;
00413       }
00414     }
00415   }
00416 #endif
00417 
00418 #ifdef DEBUG
00419   fprintf(stderr, "Image contains %d features.\n", num_features);
00420 #endif
00421 
00422   /* allocate space to store the features */
00423   feature = (FEATURE_DATA *)malloc(num_features*sizeof(FEATURE_DATA));
00424 
00425   /***** store the features in the array *****/
00426   feature_index = 0;
00427 
00428   /* colour block features */
00429   for (i = 0; i < num_total_colour_blocks; i++) {
00430     /* note that each block can have colmap_size values */
00431     feature[feature_index].id = i*colmap_size + (int)block_mode[i];
00432     feature[feature_index].frequency = FREQ_MAX; /* binary features */
00433     feature_index++;
00434   }
00435   block_features_offset = num_total_colour_blocks*colmap_size;
00436 
00437   /* colour histogram features */
00438   for (i = 0; i < colmap_size; i++) {
00439     if (col_histogram[i] != 0) {
00440       feature[feature_index].id = block_features_offset + i;
00441       feature[feature_index].frequency = (freq_type)col_histogram[i];
00442       feature_index++;
00443     }
00444   }
00445   block_features_offset += colmap_size;
00446 
00447   /* gabor block features */
00448   for (scale = 0; scale < num_gabor_scales; scale++) {
00449     for (orientation = 0; orientation < num_gabors_per_scale; orientation++) {
00450       /* blocks */
00451       for (i = 0; i < square((image_size/gabor_block_size)); i++) {
00452 #ifdef NO_FLAT_FEATURES
00453         if (block_gabor_class[scale][orientation][i] != 0) {
00454           feature[feature_index].id = block_features_offset + block_gabor_class[scale][orientation][i];
00455           feature[feature_index].frequency = FREQ_MAX;
00456           feature_index++;
00457         }
00458 #else
00459         feature[feature_index].id = block_features_offset + block_gabor_class[scale][orientation][i];
00460         feature[feature_index].frequency = FREQ_MAX;
00461         feature_index++;
00462 #endif
00463         block_features_offset += num_gabor_ranges;
00464       }
00465     }
00466   }
00467 
00468   /* gabor histogram features */
00469   for (scale = 0; scale < num_gabor_scales; scale++) {
00470     for (orientation = 0; orientation < num_gabors_per_scale; orientation++) {
00471       for (energy_class = 0; energy_class < num_gabor_ranges; energy_class++) {
00472         if (gabor_histogram[scale][orientation][energy_class] != 0) {
00473           feature[feature_index].id = block_features_offset;
00474           feature[feature_index].frequency = (freq_type)rint(FREQ_MAX*(double)gabor_histogram[scale][orientation][energy_class]/(double)square((image_size/gabor_block_size)));
00475           feature_index++;
00476         }
00477         block_features_offset++;
00478       }
00479     }
00480   }
00481 
00482 #ifdef DEBUG
00483   fprintf(stderr, "%d features found.\n", feature_index);
00484   fprintf(stderr, "block_features_offset = %d.\n", block_features_offset);
00485 #endif  
00486 
00487     
00488   /***** now write the file *****/
00489 
00490   /* open it */
00491   if ((out_file = fopen(out_fname, "wb")) == NULL) {
00492     fprintf(stderr, "Error opening file %s for writing.\n\n", out_fname);
00493     return(FILE_OPEN_ERROR);
00494   }
00495 
00496   /* write the number of features */
00497   if (fwrite(&num_features, sizeof(int), 1, out_file) != 1) {
00498     fprintf(stderr, "Error writing file %s.\n\n", out_fname);
00499     return(FILE_WRITE_ERROR);
00500   }
00501 
00511   for(i=0;
00512       i<num_features;
00513       i++){
00514     *((float*)&(feature[i].frequency))=((float)feature[i].frequency/(float)FREQ_MAX);//(WM HACK)
00515   };
00516 
00517   /* write the features, as a block */
00518   if (fwrite(feature, sizeof(FEATURE_DATA), num_features, out_file) != num_features) {
00519     fprintf(stderr, "Error writing file %s.\n\n", out_fname);
00520     return(FILE_WRITE_ERROR);
00521   }
00522 
00523   if (fclose(out_file) == EOF) {
00524     fprintf(stderr, "Error closing file %s.\n\n", out_fname);
00525     return(FILE_CLOSE_ERROR);
00526   }
00527 
00528   /* everything is OK if we got this far */
00529   return(PPM_OK);
00530 }
00531 
00532 void fts2blocks(char *fts_fname, byte * block_mode, uint32_t * col_histogram) {
00533   
00534   FILE *fts_file, *outfile;
00535   int num_features, feature_index;
00536   FEATURE_DATA *feature;
00537   int block_features_offset;
00538   int block_size, num_blocks, scale;
00539   int *colmap;
00540   int colmap_size = 18*3*3 + 4;
00541   int x, y, i, j, k;
00542   PPM *hsv_image, *qimage, *rgb_image;
00543   enum ppm_error the_error;
00544   char out_fname[256];
00545  
00546   /* read the number of features */
00547   fts_file = fopen(fts_fname, "rb");
00548   fread(&num_features, sizeof(int), 1, fts_file);
00549   
00550   /* allocate space for the features */
00551   feature = (FEATURE_DATA *)malloc(num_features*sizeof(FEATURE_DATA));
00552  
00553   /* read the features */
00554   fread(feature, sizeof(FEATURE_DATA), num_features, fts_file);
00555 
00556   fclose(fts_file);
00557 
00558   /* "unpack" the features in the array */
00559   feature_index = 0;
00560 
00561   /* block features */
00562   for (i = 0; i < num_total_colour_blocks; i++) {
00563     /* note that each block can have colmap_size values */
00564     block_mode[i] = feature[feature_index].id - i*colmap_size;
00565     feature_index++;
00566   }
00567   block_features_offset = num_total_colour_blocks*colmap_size;
00568 
00569   /* colour histogram features */
00570   for (i = 0; i < colmap_size; i++)
00571     col_histogram[i] = 0;
00572 
00573   for (; feature_index < num_features; feature_index++) {
00574     i = feature[feature_index].id - block_features_offset;
00575     col_histogram[i] = (byte)(feature[feature_index].frequency);
00576   }
00577 
00578   /* make a dummy image so that we can generate a colour map */
00579     hsv_image = new_ppm();
00580     hsv_image->type = PPM_RAW;
00581     hsv_image->width = 256;
00582     hsv_image->height = 256;
00583     hsv_image->max_col_comp = 255;
00584     hsv_image->bytes_per_pixel = 3;
00585     hsv_image->pixel = (byte *)malloc(3*256*256*sizeof(byte));
00586   hsv_quantize_ppm(hsv_image, &qimage, &colmap, 18, 3, 3, 4);
00587   destroy_ppm(&hsv_image);
00588 
00589   /* now write the block images */
00590   k = 0;
00591     block_size = smallest_colour_block;
00592     num_blocks = square(image_size/block_size);
00593   for (scale = 0; scale < num_colour_scales; scale++) {
00594     for (y = 0; y < 256; y += block_size) {
00595     for (x = 0; x < 256; x += block_size) {
00596       for (i = 0; i < block_size; i++) {
00597       for (j = 0; j < block_size; j++) {
00598         qimage->pixel[(y + j)*256 + (x + i)] = block_mode[k];
00599       }
00600       }
00601       k++;
00602     }
00603     }
00604     /* convert from the colour map to an HSV image */
00605     if ((the_error = colmap2rgb_ppm(qimage, colmap, colmap_size, &hsv_image)) != PPM_OK) {
00606       ppm_handle_error(the_error);
00607       exit(1);
00608     }
00609     /* convert to RGB */
00610     if ((the_error = hsv2rgb_ppm(hsv_image, &rgb_image)) != PPM_OK) {
00611       ppm_handle_error(the_error);
00612       exit(1);
00613     }
00614     /* write it */
00615     sprintf(out_fname, "fts2blocks_%dx%d.ppm", block_size, block_size);
00616     outfile = fopen(out_fname, "wb");
00617     if ((the_error = write_ppm(outfile, rgb_image, PPM_RAW)) != PPM_OK) {
00618       ppm_handle_error(the_error);
00619       exit(1);
00620     }
00621     fclose(outfile);
00622     destroy_ppm(&hsv_image);
00623     destroy_ppm(&rgb_image);
00624     block_size *= 2;
00625     num_blocks /= 4;
00626   }
00627 }
00628 
00629 enum ppm_error write_feature_descriptions(FILE *out_file, int *colmap, int colmap_size) {
00630 
00631   int feature_index = 0;
00632   int block_size;
00633   int i, j, k;
00634   int scale, orientation;
00635 
00636   /* block features */
00637   block_size = smallest_colour_block;
00638   for (i = 0; i < num_colour_scales; i++) {
00639     for (j = 0; j < num_blocks_at_scale(i); j++) {
00640       for (k = 0; k < colmap_size; k++) {
00641         fprintf(out_file, "%d %d COL_POS block size = %dx%d position = %d H,S,V = %d, %d, %d\n", feature_index, COL_POS, block_size, block_size, j, colmap[3*k + HUE], colmap[3*k + SATURATION], colmap[3*k + VALUE]);
00642         feature_index++;
00643       }
00644     }
00645     block_size *= 2;
00646   }
00647 
00648   /* colour histogram features */
00649   for (i = 0; i < colmap_size; i++) {
00650     fprintf(out_file, "%d %d COL_HST H,S,V = %d, %d, %d\n", feature_index, COL_HST, colmap[3*i + HUE], colmap[3*i + SATURATION], colmap[3*i + VALUE]);
00651     feature_index++;
00652   }
00653     
00654   /* gabor block features */
00655   for (scale = 0; scale < num_gabor_scales; scale++) {
00656     for (orientation = 0; orientation < num_gabors_per_scale; orientation++) {
00657       /* blocks */
00658       for (i = 0; i < square((image_size/gabor_block_size)); i++) {
00659         for (j = 0; j < num_gabor_ranges; j++) {
00660 #if num_gabor_ranges==16 /* technically, we should be checking the type.. */
00661           fprintf(out_file, "%d %d GABOR_POS block size = %dx%d position = %d SCALE, ORIENTATION, ENERGY = %d, %d, %f\n", feature_index, GABOR_POS, gabor_block_size, gabor_block_size, i, scale, orientation, gabor_ranges(j));
00662 #else
00663 #if num_gabor_ranges==10
00664           fprintf(out_file, "%d %d GABOR_POS block size = %dx%d position = %d SCALE, ORIENTATION, ENERGY = %d, %d, %d.000000\n", feature_index, GABOR_POS, gabor_block_size, gabor_block_size, i, scale, orientation, gabor_ranges(j));
00665 #endif
00666 #endif
00667         feature_index++;
00668         }
00669       }
00670     }
00671   }
00672 
00673   /* gabor histogram features */
00674   for (scale = 0; scale < num_gabor_scales; scale++) {
00675     for (orientation = 0; orientation < num_gabors_per_scale; orientation++) {
00676       for (j = 0; j < num_gabor_ranges; j++) {
00677         fprintf(out_file, "%d %d GABOR_HST SCALE, ORIENTATION, ENERGY UPPER BOUND = %d, %d, %f\n", feature_index, GABOR_HST, scale, orientation, j);
00678         feature_index++;
00679       }
00680     }
00681   }
00682 
00683   /* everything is OK if we got this far */
00684   return(PPM_OK);
00685 }

Generated on Tue Jan 6 00:30:37 2009 for Gift by  doxygen 1.5.6