00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <stdio.h>
00026
00027
00028 #include <malloc.h>
00029
00030
00031 #include <math.h>
00032
00033
00034 #include <stdint.h>
00035
00036 #ifdef HAVE_CONFIG_H
00037 #include "gift-config.h"
00038 #endif
00039
00040 #include <ppm.h>
00041
00042
00043 #include <gift_features.h>
00044
00045
00046
00047
00048 #define square(x) ((x)*(x))
00049
00050
00051
00052
00053
00054
00055
00056 #define num_gabor_ranges 10
00057
00058
00059
00060
00061 #define num_gabor_scales 3
00062
00063 #define num_gabors_per_scale 4
00064
00065
00066 #define OLDFIXED 1
00067
00068
00069 #ifdef OLDFIXED
00070
00071 #define image_size 256
00072
00073 #define num_total_colour_blocks (256+64+16+4)
00074
00075 #define smallest_colour_block 16
00076 #endif
00077
00078
00079 #define gabor_block_size 16
00080
00081 #ifdef OLDFIXED
00082
00083
00084 #define num_colour_scales 4
00085 #define num_blocks_at_scale(i) (256>>i*2)
00086 #endif
00087
00088
00089
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
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
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
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
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
00139
00140
00141
00142
00143
00144
00145
00146
00147
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
00155 for (scale = 0; scale < num_gabor_scales; scale++) {
00156 for (orientation = 0; orientation < num_gabors_per_scale; orientation++) {
00157
00158
00159 memset(filtered_image, 0, MAX_WIDTH*MAX_HEIGHT*sizeof(double)*3);
00160
00161
00162 gabor_filter(im_hsv->value_plane_double_reversed, im_hsv->width, im_hsv->height, scale, orientation, kernelsxy, conv, conv2, filtered_image);
00163
00164
00165 k = 0;
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
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
00184 block_gabor_class[scale][orientation][k] = energy_class;
00185
00186
00187 gabor_histogram[scale][orientation][energy_class]++;
00188
00189 k++;
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
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
00222
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
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
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
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
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
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
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;
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
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
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
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
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
00349
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
00368
00369
00370 num_features = num_total_colour_blocks;
00371
00372
00373
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
00382
00383
00384 for (scale = 0; scale < num_gabor_scales; scale++) {
00385 for (orientation = 0; orientation < num_gabors_per_scale; orientation++) {
00386
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
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
00401
00402
00403
00404
00405 num_features += num_gabor_scales*num_gabors_per_scale*square((image_size/gabor_block_size));
00406
00407
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
00423 feature = (FEATURE_DATA *)malloc(num_features*sizeof(FEATURE_DATA));
00424
00425
00426 feature_index = 0;
00427
00428
00429 for (i = 0; i < num_total_colour_blocks; i++) {
00430
00431 feature[feature_index].id = i*colmap_size + (int)block_mode[i];
00432 feature[feature_index].frequency = FREQ_MAX;
00433 feature_index++;
00434 }
00435 block_features_offset = num_total_colour_blocks*colmap_size;
00436
00437
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
00448 for (scale = 0; scale < num_gabor_scales; scale++) {
00449 for (orientation = 0; orientation < num_gabors_per_scale; orientation++) {
00450
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
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
00489
00490
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
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);
00515 };
00516
00517
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
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
00547 fts_file = fopen(fts_fname, "rb");
00548 fread(&num_features, sizeof(int), 1, fts_file);
00549
00550
00551 feature = (FEATURE_DATA *)malloc(num_features*sizeof(FEATURE_DATA));
00552
00553
00554 fread(feature, sizeof(FEATURE_DATA), num_features, fts_file);
00555
00556 fclose(fts_file);
00557
00558
00559 feature_index = 0;
00560
00561
00562 for (i = 0; i < num_total_colour_blocks; i++) {
00563
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
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
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
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
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
00610 if ((the_error = hsv2rgb_ppm(hsv_image, &rgb_image)) != PPM_OK) {
00611 ppm_handle_error(the_error);
00612 exit(1);
00613 }
00614
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
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
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
00655 for (scale = 0; scale < num_gabor_scales; scale++) {
00656 for (orientation = 0; orientation < num_gabors_per_scale; orientation++) {
00657
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
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
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
00684 return(PPM_OK);
00685 }