Recognizer.cpp

Training and recognizing main file - Abe S., 2011-03-28 07:18 pm

Download (6.4 kB)

 
1
/*
2
 * Recognizer.cpp
3
 *
4
 *  Created on: Mar 23, 2011
5
 *      Author: ams
6
 *
7
 *
8
 */
9
10
#include <cstdio>
11
#include <unistd.h>
12
#include <dirent.h>
13
#include <opencv/cv.h>
14
#include <opencv/highgui.h>
15
#include <opencv/ml.h>
16
17
#include "MoUT.hpp"
18
19
// Size of the sample images in pixels
20
#define SAMPLE_WIDTH 27
21
#define SAMPLE_HEIGHT 20
22
// Multiplied by 3 for the three color channels
23
#define SAMPLE_SIZE (SAMPLE_WIDTH * SAMPLE_HEIGHT * 3)
24
25
void trainNN()
26
{
27
        CvANN_MLP brains;
28
29
        int samples;
30
31
        FILE *fin;
32
        fin = fopen("./cup.dat", "r");
33
34
        //Get the number of samples.
35
        fscanf(fin, "%d", &samples);
36
        printf("Found training file with %d samples...\n", samples);
37
38
        /* Create a matrix to hold the training data
39
         * A sample is a 20x27 RGB image, so there are 1620 inputs in a sample.
40
         * There is also one output, so there are a total of 1621 values.
41
         * With 2304 samples, that means there are 3,734,784 values, and at
42
         * 4 bytes per value, over 14 megs of data. This should be trivial, but it
43
         * causes a segmentation fault. Using unit8_t appears to be ok...
44
         */
45
        uint8_t trainingData[samples][SAMPLE_SIZE + 1];
46
47
        /* OpenCV matrices for the sample data. One holds inputs, the other holds outputs
48
         * This has to be floating point, despite the fact that the input isn't */
49
        CvMat* trainInput = cvCreateMat(samples, SAMPLE_SIZE, CV_32FC1);
50
        CvMat* trainOutput = cvCreateMat(samples, 1, CV_32FC1);
51
52
        /* Weights of each sample, which should be all the same */
53
        CvMat* sampleWeights = cvCreateMat(samples, 1, CV_32FC1);
54
55
        /* Matrix representation of the network.
56
         * The first number is the count of layers.
57
         */
58
        CvMat* nnLayers = cvCreateMat(4, 1, CV_32SC1);
59
60
        CvMat trainInput1, trainOutput1, nnLayers1, sampleWeights1;
61
62
        cvGetRows(trainInput, &trainInput1, 0, samples);
63
        cvGetRows(trainOutput, &trainOutput1, 0, samples);
64
        cvGetRows(sampleWeights, &sampleWeights1, 0, samples);
65
        cvGetRows(nnLayers, &nnLayers1, 0, 4);
66
67
        /*Setting the number of neurons on each layer of the ANN
68
         * Layer 1: 1620 neurons (One for each channel of each input pixel)
69
         * Layer 2: Undecided, this parameter needs tweaking
70
         *  Layer 3: Undecided, this parameter also needs tweaking
71
         *  Layer 4: 1 neurons (1 output, for whether the input has a red cup in it)
72
         *
73
         *  Heuristic principles for the design of artificial neural networks, by
74
         *  Stephen Walczak and Narciso Cerpa, has some useful pointers.
75
         */
76
        cvSet1D(&nnLayers1, 0, cvScalar(SAMPLE_SIZE));
77
        cvSet1D(&nnLayers1, 1, cvScalar((int) (SAMPLE_SIZE * 0.75)));
78
        cvSet1D(&nnLayers1, 2, cvScalar((int) (SAMPLE_SIZE * 0.65)));
79
        cvSet1D(&nnLayers1, 3, cvScalar(1));
80
81
        /* Read the data from the training file. This might take
82
         * something like two forevers.
83
         */
84
        printf("Reading training data...");
85
        for (int sample = 0; sample < samples; sample++)
86
        {
87
                for (int value = 0; value < SAMPLE_SIZE + 1; value++)
88
                {
89
                        //%hhu is an integer promoted from a char that is unsigned
90
                        //This may be a problem, since trainingData is uint8_t (char)
91
                        fscanf(fin, "%hhu", &trainingData[sample][value]);
92
                }
93
        }
94
        //Done reading the file
95
        fclose(fin);
96
        printf("done.\n");
97
98
        //Assemble the ML training data.
99
        printf("Assembling training data...");
100
        for (int sample =0; sample < samples; sample++)
101
        {
102
                //Input values
103
                for (int value = 0; value < SAMPLE_SIZE; value++)
104
                {
105
                        //load each data value
106
                        cvSetReal2D(&trainInput1, sample, value, trainingData[sample][value]);
107
                }
108
109
           //Output values
110
           cvSet1D(&trainOutput1, sample, cvScalar(trainingData[sample][SAMPLE_SIZE + 1]));
111
112
           //Weight (setting everything to 1)
113
           cvSet1D(&sampleWeights1, sample, cvScalar(1));
114
        }
115
        printf("done.\n");
116
117
        //Create the ANN
118
        brains.create(&nnLayers1);
119
120
        //Train the ANN
121
        printf("Training ANN...");
122
        brains.train(
123
                        trainInput,
124
                        trainOutput,
125
                        sampleWeights,
126
                        0,                                                                                                                                                                                        //Take all samples into account
127
                        CvANN_MLP_TrainParams(
128
                                        cvTermCriteria(
129
                                                        CV_TERMCRIT_ITER + CV_TERMCRIT_EPS,                //Stop after either a number of iterations or a certain accuracy is achieved
130
                                                        10000,                                                                                                                                        //Maximum iterations
131
                                                        1.0),                                                                                                                                                //Accuracy TODO this needs finagling
132
                                        CvANN_MLP_TrainParams::BACKPROP,                                                //Use backpropagation
133
                                        0.01,                                                                                                                                                        // coefficeint to multiply weight gradient by. 0.1 is recommended by online sources
134
                                        0.05)                                                                                                                                                        // backpropagation "moment scale", couldn't find documentation
135
                        );
136
        printf("done.\n");
137
        //Save the results to a file
138
        CvFileStorage* annOutFile = cvOpenFileStorage("./annParams", 0, CV_STORAGE_WRITE_TEXT);
139
        brains.write(annOutFile, "annParams");
140
        printf("Wrote to file.\n");
141
}
142
143
/* Use the neural net to determine if the target occurs in an image
144
 */
145
146
bool recognize(string dirName)
147
{
148
        // Load the NN from the file
149
        CvFileStorage* annInFile = cvOpenFileStorage("./annParams", 0, CV_STORAGE_READ);
150
        CvFileNode* annInNode;
151
        CvANN_MLP ann;
152
        ann.read(annInFile, annInNode);
153
154
        //get all the images in the directory
155
        DIR *dpdf;
156
        struct dirent *epdf;
157
        dpdf = opendir(dirName.c_str());
158
        if (dpdf != NULL)
159
        {
160
                //Loop over all the files in the directory
161
                while (epdf = readdir(dpdf))
162
                {
163
                        //skip the dot files
164
                        if(strcmp(epdf->d_name, ".") == 0 || strcmp(epdf->d_name, "..") == 0)
165
                        {
166
                                continue;
167
                        }
168
                        string fullName = (dirName + "/" + epdf->d_name).c_str();
169
170
                        //Downsample and convert to an input vector
171
                        string nnVector = img2NNVect(fullName);
172
                        float strSample[SAMPLE_SIZE];
173
174
                        vector<string> tokens;
175
                        Tokenize(nnVector, tokens);
176
177
                        vector<string>::iterator tokIt;
178
                        int index = 0;
179
                        float newVal = 0.0;
180
                        for(tokIt = tokens.begin(); tokIt != tokens.end(); tokIt++)
181
                        {
182
                                if(fromString<float>(newVal, (*tokIt), std::dec))
183
                                {
184
                                        strSample[index] = newVal;
185
                                }
186
                                else
187
                                {
188
                                        strSample[index] = -1.0;
189
                                        printf("Error converting %s to a float\n", (*tokIt).c_str());
190
                                }
191
                                index++;
192
                        }
193
                        CvMat sample = cvMat(1, SAMPLE_SIZE, CV_32FC1, strSample);
194
195
                        //Matrix to store the output in
196
                        float output[1];
197
                        CvMat nnOutput = cvMat(1, 1, CV_32FC1, output);
198
199
                        // Feed to the NN
200
                        ann.predict(&sample, &nnOutput);
201
202
                        // Display the results
203
                        printf("File: %s\t\tOutput: %f", fullName.c_str(), nnOutput.data.fl[0]);
204
205
                }
206
        }
207
        return false;
208
}
209
210
void usage()
211
{
212
        printf("Please specify training (-t) or recognizing (-r)\n");
213
}
214
215
int main(int argc, char **argv)
216
{
217
        int c;
218
        while ((c = getopt(argc, argv, "tr")) != -1)
219
        {
220
                switch (c)
221
                {
222
                case 't':
223
                        trainNN();
224
                        break;
225
                case 'r':
226
                        recognize("/data/cup_untrained");
227
                        //recognize("/data/cup_untrained");
228
                        break;
229
                default:
230
                        usage();
231
                        return EXIT_FAILURE;
232
                }
233
        }
234
235
        return EXIT_SUCCESS;
236
}