Ignore:
Timestamp:
Apr 6, 2010, 11:38:23 AM (15 years ago)
Author:
Rick van der Zwet
Message:
  • Parameters
  • menu options
  • pointer exceptions fixed


TODO:

  • averages are still not right
File:
1 edited

Legend:

Unmodified
Added
Removed
  • liacs/MIR2010/SourceCode/main.cpp

    r97 r98  
    66#include <conio.h>
    77#include <iostream>
     8#include <iomanip>
     9#include <queue>
    810
    911#include "cximage/ximage.h"
    1012#include "xbrowseforfolder.h"
     13
    1114// function prototypes
    1215bool CalculateDescriptors(const char *basedir);
     
    1518bool DetermineWinterSportBatch(const char *basedir);
    1619bool LoadAverages(const char *basedir);
     20bool ShowAverages(const char *basedir);
    1721
    1822#define TRAINING_DIR_DEBUG "C:\\Documents and Settings\\rvdzwet\\Desktop\\liacs\\MIR2010\\trainingSet"
    1923#define TESTSET_DIR_DEBUG "C:\\Documents and Settings\\rvdzwet\\Desktop\\liacs\\MIR2010\\testSet"
    2024#define DEBUG 0
    21 // number of bins to use for each color
    22 // Note: number of bins must be a whole fraction of 256. if we would
    23 //       use 256 bins for each color then a single histogram would be
    24 //       64MB, so we should choose a more sensible number
    25 #define BIN_COUNT       32
    26 
    27 // names of categories
     25
     26// Names of categories (folders)
    2827#define CATEGORY_SIZE 8
    2928#define CATEGORY_1      "cat1.crowd"
     
    3635#define CATEGORY_8  "opt5.curling"
    3736
    38 const char *categories[CATEGORY_SIZE] = { CATEGORY_1, CATEGORY_2, CATEGORY_3,
    39         CATEGORY_4, CATEGORY_5, CATEGORY_6,  CATEGORY_7, CATEGORY_8}; 
     37// Nicely concat into a string array
     38const char *categories[CATEGORY_SIZE] = {
     39        CATEGORY_1, CATEGORY_2, CATEGORY_3,
     40        CATEGORY_4, CATEGORY_5, CATEGORY_6, 
     41        CATEGORY_7, CATEGORY_8};
     42
     43// number of bins to use for each color
     44// Note: number of bins must be a whole fraction of 256. if we would
     45//       use 256 bins for each color then a single histogram would be
     46//       64MB, so we should choose a more sensible number
     47#define BIN_COUNT       32
    4048float average[CATEGORY_SIZE][BIN_COUNT*BIN_COUNT*BIN_COUNT];
    4149
    4250
    4351// Find common coloured shapes as characteristics
    44 // Walk over image with SPREAD steps, if pixel -within TOLERANCE- matches previous pixel
     52// Walk over image with opt_spread steps, if pixel -within opt_tolerance- matches previous pixel
    4553// make the size of the specific block bigger.
    46 #define TOLERANCE 20
    47 #define SPREAD 20
    48 #define MAX_SIZE 500
    49 float average_block[CATEGORY_SIZE][MAX_SIZE/SPREAD];
     54// Block '0' is used an non-matcher. Not taken into account for the time beeing.
     55int opt_tolerance = 10;
     56int opt_spread = 20;
     57#define MAX_BLOCKSIZE 500
     58float average_block[CATEGORY_SIZE][MAX_BLOCKSIZE];
    5059
    5160
     
    5463#define _return(err_msg, retval) printf("DEBUG: %s\n",err_msg); cin.get(); return(retval);
    5564#define cout_status(msg,flag) cout << msg; (flag) ? cout << " off" : cout << " on"; cout << endl;
    56 
    57 
     65#define cout_point(x,y) "[" << x << "," << y << "]"
     66
     67// Default options
     68bool opt_debug = false;
    5869bool opt_verbose = false;
    59 bool opt_histogram = true;
     70bool opt_histogram = false;
    6071bool opt_block = true;
    6172
     
    92103        if (strlen(dbdir) == 0)
    93104                return 0;
    94         if (XBrowseForFolder(NULL, "Please select image testset folder", NULL, testdir, sizeof(testdir)) == FALSE)
     105        if (XBrowseForFolder(NULL, "Please select image testset batch folder, could be any folder", NULL, testdir, sizeof(testdir)) == FALSE)
    95106                return 0;
    96107        if (strlen(testdir) == 0)
     
    126137                cout << endl;
    127138                cout << "1. calculate descriptors" << endl;
    128                 cout << "2. categorize descriptors (aka averages histograms)" << endl;
    129                 cout << "3. determine winter sport" << endl;
     139                cout << "2. categorize descriptors (aka averages)" << endl;
     140                cout << "3. determine winter sport on single image" << endl;
    130141                cout << "4. batch test winter sport" << endl;
     142                cout << "9. Show averages" << endl;
     143                cout << endl;
     144                cout_status("d. Turn debug mode", opt_debug);
    131145                cout_status("v. Turn verbose mode", opt_verbose);
    132146                cout_status("h. Turn histogram classifier", opt_histogram);
    133                 cout_status("b. Turn block classifier", opt_block);
    134 
     147                cout_status("b. Turn block classifier", opt_block);     
    135148                cout << endl;
     149                cout << "==== Parameters Block Classifier ====" << endl;
     150                cout << "s. Set spread [currently: " << opt_spread << "]" << endl;
     151                cout << "t. Set Tolerance [currently: " << opt_tolerance << "]" << endl;
     152
    136153                cout << "Please select option, or type 'q' to quit: ";
    137154                char c = _getch();
     
    171188                        }
    172189                        break;
     190                case '9':
     191                        if (!LoadAverages(dbdir)){
     192                                _return("Unable to load averages",1);
     193                        }
     194                        if (!ShowAverages(testdir)) {
     195                                _return("Unable to show averages",1);
     196                        }
     197                        break;
     198                case 'd':
     199                        opt_debug = (!opt_debug);
     200                        break;
    173201                case 'v':
    174202                        opt_verbose = (!opt_verbose);
     
    180208                        opt_histogram = (!opt_histogram);
    181209                        break;
     210                case 's':
     211                        cout << "Spread value: ";
     212                        cin >> opt_spread;
     213                        cout << "WARNING: Make sure to re-classify before (Batch)Testing" << endl;
     214                        cout << "Any key to continue..." << endl; cin.get();
     215                        break;
     216                case 't':
     217                        cout << "Tolerance value: ";
     218                        cin >> opt_tolerance;
     219                        cout << "WARNING: Make sure to re-classify before (Batch)Testing" << endl;
     220                        cout << "Any key to continue..." << endl; cin.get();
     221                        break;
     222
    182223                default:
    183224                        continue;
     
    228269}
    229270
     271struct point {
     272        int x;
     273        int y;
     274};
     275
     276
    230277// histogram should be a preallocated array of size BIN_COUNT*BIN_COUNT*BIN_COUNT elements and will
    231278// be filled with the color histogram of the image where path points at
     
    236283        if (!image.IsValid())
    237284                return false;
     285
    238286        // clear histogram
    239         memset(block, 0, MAX_SIZE/SPREAD * sizeof(float));
     287        memset(block, 0, MAX_BLOCKSIZE * sizeof(float));
     288       
    240289        // walk through the pixels to fill the histogram
    241290        const int width = (int)image.GetWidth();
    242291        const int height = (int)image.GetHeight();
    243292
    244         int rgb_value = 0;
    245         int rgb_prev = 0;
    246 
     293        int * status = new int [width * height];
     294        //memset(status,0, width * height * sizeof(int));
     295
     296        queue<point> queue;
     297        int rgb_current, rgb_right, rgb_up = 0;
    247298        int block_size = 0;
    248 
    249         for (int y = 0; y < height; y += SPREAD)
    250         {
    251                 for (int x = 0; x < width; x += SPREAD)
     299        point p, p_right, p_up;
     300
     301        RGBQUAD rgb;
     302
     303        // Pixel field status
     304        // 0 = No need for processing
     305        // 1 = Need processing
     306        // 2 = Done processing
     307        for (int x = 0; x < width; x += opt_spread)
     308                for (int y = 0; y < height; y += opt_spread)
     309                        status[x * height + y] = 1;
     310
     311        for (int x = 0; x < width; x += opt_spread)
     312        {
     313                for (int y = 0; y < height; y += opt_spread)
    252314                {
    253                         // Note: CxImage library starts counting at lower-left corner of the image,
    254                         //       which is seen as the top of the image.
    255                         RGBQUAD rgb = image.BlindGetPixelColor(x, y, false);
    256                         rgb_value = (rgb.rgbRed + rgb.rgbBlue + rgb.rgbGreen);
    257 
    258                         if (abs(rgb_value - rgb_prev) > TOLERANCE) {
    259                                 block[block_size]++;
    260                                 block_size = 1;
    261                         }
    262                         rgb_prev = rgb_value;
    263                 }
    264         }
     315                        // Only process if required to and not yet done
     316                        if (status[x * height + y] != 1) {
     317                                if (opt_debug)
     318                                        cout << "Already processed point " << cout_point(x,y) << endl;
     319                                continue;
     320                        }
     321
     322                        if(opt_debug)
     323                                cout << "Testing new point " << cout_point(x,y) << endl;
     324
     325                        // Stack based expantion and evaluation
     326                        block_size = 0;
     327                        p.x = x;
     328                        p.y = y;
     329                        queue.push(p);
     330
     331                        while (!queue.empty())
     332                        {
     333                                // Note: CxImage library starts counting at lower-left corner of the image
     334                                // which is seen as the top of the image.
     335                                p = queue.front();
     336                                queue.pop();
     337
     338                                // Make sure not to process points twice
     339                                if (status[p.x * height + p.y] != 1)
     340                                        continue;
     341
     342                                if (opt_debug)
     343                                        cout << "Processing point " << cout_point(p.x,p.y) << endl;
     344
     345                                rgb = image.BlindGetPixelColor(p.x, p.y, false);
     346                                rgb_current = (rgb.rgbRed + rgb.rgbBlue + rgb.rgbGreen);
     347
     348                                p_right.x = p.x + opt_spread;
     349                                p_right.y = p.y;
     350
     351                                // Check if right one fits the bill
     352                                if (p_right.x < width)
     353                                {
     354                                        rgb = image.BlindGetPixelColor(p_right.x, p_right.y, false);
     355                                        rgb_right = (rgb.rgbRed + rgb.rgbBlue + rgb.rgbGreen);
     356
     357                                        if (abs(rgb_right - rgb_current) < opt_tolerance)
     358                                        {
     359                                                if (opt_debug)
     360                                                        cout << "Right point " << cout_point(p_right.x,p_right.y) << " gets included in block" << endl;
     361
     362                                                block_size++;
     363                                                queue.push(p_right);
     364                                        }
     365                                }
     366
     367                                // Check if up one fits the bill
     368                                p_up.x = p.x;
     369                                p_up.y = p.y + opt_spread;
     370                                if (p_up.y < height)
     371                                {
     372                                        rgb = image.BlindGetPixelColor(p_up.x, p_up.y, false);
     373                                        rgb_up = (rgb.rgbRed + rgb.rgbBlue + rgb.rgbGreen);
     374
     375                                        if (abs(rgb_up - rgb_current) < opt_tolerance)
     376                                        {
     377                                                if (opt_debug)
     378                                                        cout << "Upper point " << cout_point(p_up.x, p_up.y) << " gets included in block" << endl;
     379
     380                                                block_size++;
     381                                                queue.push(p_up);
     382                                        }
     383                                }
     384                                status[p.x * height + p.y] = 2;
     385                        }
     386                        if (opt_debug)
     387                                cout << cout_point(x,y) << " blocksize " << block_size << endl;
     388                        if (block_size > MAX_BLOCKSIZE) {
     389                                cout << "WARN: block_size larger than fixed limit of " << MAX_BLOCKSIZE << endl;
     390                                block_size = MAX_BLOCKSIZE;
     391                        }
     392
     393                        block[block_size]++;
     394                }
     395        }
     396
     397        delete status;
    265398        return true;
    266399}
     
    270403        // the histogram that we reuse for each image
    271404        float *histogram = new float[BIN_COUNT*BIN_COUNT*BIN_COUNT];
    272         float *block = new float[MAX_SIZE/SPREAD];
     405        float *block = new float[MAX_BLOCKSIZE];
    273406        // walk through all images
    274407        // Note: each of the three categories has 50 images
     
    304437                        if (fwrite(histogram, sizeof(float), BIN_COUNT*BIN_COUNT*BIN_COUNT, file) != BIN_COUNT*BIN_COUNT*BIN_COUNT)
    305438                                goto failure;
    306                         if (fwrite(block, sizeof(float), MAX_SIZE/SPREAD, file) != MAX_SIZE/SPREAD)
     439                        if (fwrite(block, sizeof(float), MAX_BLOCKSIZE, file) != MAX_BLOCKSIZE)
    307440                                goto failure;
    308441                        SAFE_CLOSEFILE(file);
     
    328461        // characteristics of that category
    329462        float *histogram = new float[BIN_COUNT*BIN_COUNT*BIN_COUNT];
    330         float *block = new float[MAX_SIZE/SPREAD];
    331         float *average_block = new float[MAX_SIZE/SPREAD];
     463        float *block = new float[MAX_BLOCKSIZE];
     464        float *average_block = new float[MAX_BLOCKSIZE];
    332465        float *average = new float[BIN_COUNT*BIN_COUNT*BIN_COUNT];
    333466        // walk through all descriptors
     
    362495                                goto failure;
    363496                        }
    364                         if (fread(block, sizeof(float), MAX_SIZE/SPREAD, file) != MAX_SIZE/SPREAD) {
     497                        if (fread(block, sizeof(float), MAX_BLOCKSIZE, file) != MAX_BLOCKSIZE) {
    365498                                p_err("Cannot read block");
    366499                                goto failure;
     
    372505                                average[b] += histogram[b];
    373506
    374                         for (int b = 0; b < MAX_SIZE/SPREAD; b++)
     507                        for (int b = 0; b < MAX_BLOCKSIZE; b++)
    375508                                average_block[b] += block[b];
    376509
     
    380513                for (int b = 0; b < BIN_COUNT*BIN_COUNT*BIN_COUNT; b++)
    381514                        average[b] /= c_size;
    382                
    383                 for (int b = 0; b < MAX_SIZE/SPREAD; b++)
     515
     516                for (int b = 0; b < MAX_BLOCKSIZE; b++)
    384517                        average_block[b] /= c_size;
    385518
     
    390523                if (fwrite(average, sizeof(float), BIN_COUNT*BIN_COUNT*BIN_COUNT, file) != BIN_COUNT*BIN_COUNT*BIN_COUNT)
    391524                        goto failure;
    392                 if (fwrite(average_block, sizeof(float), MAX_SIZE/SPREAD, file) != MAX_SIZE/SPREAD)
     525                if (fwrite(average_block, sizeof(float), MAX_BLOCKSIZE, file) != MAX_BLOCKSIZE)
    393526                        goto failure;
    394527
     
    428561                if (fread(average[c], sizeof(float), BIN_COUNT*BIN_COUNT*BIN_COUNT, file) != BIN_COUNT*BIN_COUNT*BIN_COUNT)
    429562                        return false;
    430                 if (fread(average_block[c], sizeof(float), MAX_SIZE/SPREAD, file) != MAX_SIZE/SPREAD)
     563                if (fread(average_block[c], sizeof(float), MAX_BLOCKSIZE, file) != MAX_BLOCKSIZE)
    431564                        return false;
    432565
     
    436569}
    437570
     571
     572bool ShowAverages(const char *basedir) {
     573
     574        if (opt_histogram) {
     575                cout << "Histogram averages" << endl;
     576                for (int c = 0; c < CATEGORY_SIZE; c++) {
     577                        cout << "Category [" << categories[c] << "] " << endl;
     578                        for (int i = 1; i <= BIN_COUNT*BIN_COUNT*BIN_COUNT; i++) {
     579                                cout << fixed << setprecision(2) << average[c][i-1] << " ";
     580                                if ((i % 10) == 0) cout << endl;
     581                        }
     582                        cout << endl;
     583                }
     584        }
     585        if (opt_block) {
     586                cout << "Block averages" << endl;
     587                for (int c = 0; c < CATEGORY_SIZE; c++) {
     588                        cout << "Category [" << categories[c] << "] " << endl;
     589                        for (int i = 1; i < MAX_BLOCKSIZE; i++) {
     590                                cout << fixed << setprecision(2) << average_block[c][i-1] << " ";
     591                                if ((i % 10) == 0) cout << endl;
     592                        }
     593                        cout << endl;
     594
     595                }
     596        }
     597        return true;
     598}
    438599int DetermineCategory(const char *path, const int guess=-1, const bool verbose=false) {
    439600        float *histogram = new float[BIN_COUNT*BIN_COUNT*BIN_COUNT];
    440         float *block = new float[MAX_SIZE/SPREAD];
     601        float *block = new float[MAX_BLOCKSIZE];
    441602        float cat2dist[CATEGORY_SIZE];
    442603        float cat2block[CATEGORY_SIZE];
     
    462623                        cat2dist[c] += fabs(histogram[b] - average[c][b]);
    463624
    464                 for (int b = 0; b < MAX_SIZE/SPREAD; b++)
     625                /* No including of the non-matching points currently */
     626                for (int b = 1; b < MAX_BLOCKSIZE; b++)
    465627                        cat2block[c] += fabs(block[b] - average_block[c][b]);
    466628        }
     
    498660                return cat_block;
    499661        } else {
    500             return -1;
     662                return -1;
    501663        }
    502664}
     
    560722                catname = categories[c];
    561723                sprintf(catdir, "%s\\%s\\", basedir, catname);
    562                
     724
    563725                /* process the images in the directory */
    564726                for (int i = 1; i <= 50; i++)
     
    581743                cout << "[" << catname << "] results " << c_succes[c] << "/" << c_total[c] << endl;
    582744        }
    583        
     745
    584746        /* Display grand total */
    585747        cout << "=== Totals ===" << endl;
     
    598760                all_succes += c_succes[c];
    599761        }
    600         printf ("[%-20s] %i/%i\n","total",all_succes,all_succes);
     762        printf ("[%-20s] %i/%i\n","total",all_succes,all_total);
    601763        cout << "Press any key to continue..."; cin.get();
    602764
Note: See TracChangeset for help on using the changeset viewer.