Quantcast
Channel: OpenCV Q&A Forum - Latest question feed
Viewing all articles
Browse latest Browse all 19555

Why is my knn network is so bad ?

$
0
0
Hello everyone ! I used a k-Nearest Neighbors algorithm (knn) and I trained it with the MNIST [database](http://yann.lecun.com/exdb/mnist/) Here is the code for the training: Ptr getKnn() { Ptr knn(ml::KNearest::create()); FILE *fp = fopen("/keep/Repo/USELESS/_sandbox/cpp/learning-cpp/sudoku/assets/train-images-idx3-ubyte", "rb"); FILE *fp2 = fopen("/keep/Repo/USELESS/_sandbox/cpp/learning-cpp/sudoku/assets/train-labels-idx1-ubyte", "rb"); if (!fp || !fp2) { cout << "can't open file" << endl; } int magicNumber = readFlippedInteger(fp); int numImages = readFlippedInteger(fp); int numRows = readFlippedInteger(fp); int numCols = readFlippedInteger(fp); fseek(fp2, 0x08, SEEK_SET); int size = numRows * numCols; cout << "size: " << size << endl; cout << "rows: " << numRows << endl; cout << "cols: " << numCols << endl; Mat_ trainFeatures(numImages, size); Mat_ trainLabels(1, numImages); BYTE *temp = new BYTE[size]; BYTE tempClass = 0; for (int i = 0; i < numImages; i++) { fread((void *)temp, size, 1, fp); fread((void *)(&tempClass), sizeof(BYTE), 1, fp2); trainLabels[0][i] = (int)tempClass; for (int k = 0; k < size; k++) { trainFeatures[i][k] = (float)temp[k]; } } knn->train(trainFeatures, ml::ROW_SAMPLE, trainLabels); return knn; } When I test the algorithm with the 10k images file MNIST provide I have: Accuracy: 96.910000 which is a good news :) The code to test the knn trained is here: void testKnn(Ptr knn, bool debug) { int totalCorrect = 0; FILE *fp = fopen("/keep/Repo/USELESS/_sandbox/cpp/learning-cpp/sudoku/assets/t10k-images-idx3-ubyte", "rb"); FILE *fp2 = fopen("/keep/Repo/USELESS/_sandbox/cpp/learning-cpp/sudoku/assets/t10k-labels-idx1-ubyte", "rb"); int magicNumber = readFlippedInteger(fp); int numImages = readFlippedInteger(fp); int numRows = readFlippedInteger(fp); int numCols = readFlippedInteger(fp); fseek(fp2, 0x08, SEEK_SET); int size = numRows * numCols; Mat_ testFeatures(numImages, size); Mat_ expectedLabels(1, numImages); BYTE *temp = new BYTE[size]; BYTE tempClass = 0; int K = 1; Mat response, dist, m; for (int i = 0; i < numImages; i++) { if (i % 1000 == 0 && i != 0) { cout << i << endl; } fread((void *)temp, size, 1, fp); fread((void *)(&tempClass), sizeof(BYTE), 1, fp2); expectedLabels[0][i] = (int)tempClass; for (int k = 0; k < size; k++) { testFeatures[i][k] = (float)temp[k]; } // test to verify if createMatFromMNIST and createMatToMNIST are well. m = testFeatures.row(i); knn->findNearest(m, K, noArray(), response, dist); if (debug) { cout << "response: " << response << endl; cout << "dist: " << dist << endl; Mat m2 = createMatFromMNIST(m); showImage(m2); // Mat m3 = createMatToMNIST(m2); // showImage(m3); } if (expectedLabels[0][i] == response.at(0)) { totalCorrect++; } } printf("Accuracy: %f ", (double)totalCorrect * 100 / (double)numImages); } By the way, you can test the knn I have implemented in my project here: (see the actions part) `https://bitbucket.org/BenNG/sudoku-recognizer` But when it comes to use my own data against the algo, it has a bad behavior. What is the data I give to the algo ? To answer that I will present a bit my project. My project is a sudoku grabber. So on a picture that holds a sudoku, I'm able to find the sudoku and extract it. Then I'm able to extract every cell in the puzzle. Each cell is preprocessed before I send it to the knn. By the way, you can also see the extraction of the puzzle and cells [here](https://bitbucket.org/BenNG/sudoku-recognizer) For the last part which is sending the extracted number to the knn I: - clean and extract only the number - resize the image to 20x20 - copy this 20x20 in a 28x28 black (adding border) - centerize 20x20 in 28x28 (still need to use the moment and not the middle of the picture as describe in the MNIST description) here is the code: Ptr knn = getKnn(); string fullName = p.string(); Mat raw = imread(fullName, CV_LOAD_IMAGE_GRAYSCALE); Mat sudoku = extractPuzzle(raw); for (int k = 0; k < 81; k++) { Mat cell = extractCell(sudoku, k); Mat roi = extractNumber(cell); if (!roi.empty()) { adaptiveThreshold(roi, fin, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV, 3, 1); fin2 = removeTinyVolume(fin, 90, Scalar(0, 0, 0)); vector v = findBiggestComponent(fin2); double left = v[0]; double top = v[1]; double width = v[2]; double height = v[3]; double x = v[4]; double y = v[5]; Rect rect(left, top, width, height); fin3 = fin2(rect); Mat normalized = normalizeSize(fin3), dest; int notZero = 0; int sumI = 0, sumY = 0; int size = 28; int mid = size / 2; Mat output = Mat::zeros(size, size, CV_32F); normalized.copyTo(output(Rect((mid - sumI / (double)notZero), (mid - sumY / (double)notZero), normalized.cols, normalized.rows))); Mat test = createMatToMNIST(output); knn->findNearest(test, K, noArray(), response, dist); cout << "response: " << response << endl; cout << "dist: " << dist << endl; } } I transform the 28x28 in a 1x784 Mat and give that to the knn and the answer is most of the time response: [5] dist: [-nan] but when I use a Mat from MNIST the result is accurate response: [7] dist: [457766] ![image description](https://c2.staticflickr.com/6/5504/30561061245_017877d4c8_o.png) left is mine right is mnist Do you have any ideas ? edit: 5 minutes after I publish the post I found something [this commit](https://bitbucket.org/BenNG/sudoku-recognizer/commits/8eee311a20c0b212d489846805c94035b0d31fb3) fixes the "no result" at all but still the network is not accurate enough

Viewing all articles
Browse latest Browse all 19555

Trending Articles