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 |
|
20 | #define SAMPLE_WIDTH 27
|
21 | #define SAMPLE_HEIGHT 20
|
22 |
|
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 |
|
35 | fscanf(fin, "%d", &samples);
|
36 | printf("Found training file with %d samples...\n", samples);
|
37 |
|
38 | |
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 | |
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 |
|
53 | CvMat* sampleWeights = cvCreateMat(samples, 1, CV_32FC1);
|
54 |
|
55 | |
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 | |
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 | |
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 |
|
90 |
|
91 | fscanf(fin, "%hhu", &trainingData[sample][value]);
|
92 | }
|
93 | }
|
94 |
|
95 | fclose(fin);
|
96 | printf("done.\n");
|
97 |
|
98 |
|
99 | printf("Assembling training data...");
|
100 | for (int sample =0; sample < samples; sample++)
|
101 | {
|
102 |
|
103 | for (int value = 0; value < SAMPLE_SIZE; value++)
|
104 | {
|
105 |
|
106 | cvSetReal2D(&trainInput1, sample, value, trainingData[sample][value]);
|
107 | }
|
108 |
|
109 |
|
110 | cvSet1D(&trainOutput1, sample, cvScalar(trainingData[sample][SAMPLE_SIZE + 1]));
|
111 |
|
112 |
|
113 | cvSet1D(&sampleWeights1, sample, cvScalar(1));
|
114 | }
|
115 | printf("done.\n");
|
116 |
|
117 |
|
118 | brains.create(&nnLayers1);
|
119 |
|
120 |
|
121 | printf("Training ANN...");
|
122 | brains.train(
|
123 | trainInput,
|
124 | trainOutput,
|
125 | sampleWeights,
|
126 | 0,
|
127 | CvANN_MLP_TrainParams(
|
128 | cvTermCriteria(
|
129 | CV_TERMCRIT_ITER + CV_TERMCRIT_EPS,
|
130 | 10000,
|
131 | 1.0),
|
132 | CvANN_MLP_TrainParams::BACKPROP,
|
133 | 0.01,
|
134 | 0.05)
|
135 | );
|
136 | printf("done.\n");
|
137 |
|
138 | CvFileStorage* annOutFile = cvOpenFileStorage("./annParams", 0, CV_STORAGE_WRITE_TEXT);
|
139 | brains.write(annOutFile, "annParams");
|
140 | printf("Wrote to file.\n");
|
141 | }
|
142 |
|
143 | |
144 | */
|
145 |
|
146 | bool recognize(string dirName)
|
147 | {
|
148 |
|
149 | CvFileStorage* annInFile = cvOpenFileStorage("./annParams", 0, CV_STORAGE_READ);
|
150 | CvFileNode* annInNode;
|
151 | CvANN_MLP ann;
|
152 | ann.read(annInFile, annInNode);
|
153 |
|
154 |
|
155 | DIR *dpdf;
|
156 | struct dirent *epdf;
|
157 | dpdf = opendir(dirName.c_str());
|
158 | if (dpdf != NULL)
|
159 | {
|
160 |
|
161 | while (epdf = readdir(dpdf))
|
162 | {
|
163 |
|
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 |
|
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 |
|
196 | float output[1];
|
197 | CvMat nnOutput = cvMat(1, 1, CV_32FC1, output);
|
198 |
|
199 |
|
200 | ann.predict(&sample, &nnOutput);
|
201 |
|
202 |
|
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 |
|
228 | break;
|
229 | default:
|
230 | usage();
|
231 | return EXIT_FAILURE;
|
232 | }
|
233 | }
|
234 |
|
235 | return EXIT_SUCCESS;
|
236 | }
|