现在我正在尝试使用 OpenCV 创建数字识别系统。 WEB 上有很多文章和示例(甚至在 StackOverflow 上)。我决定使用 KNN classifier因为这个解决方案是WEB中最流行的。我找到了 database of handwritten digits具有 60k 个示例的训练集,错误率低于 5%。
我使用了 this tutorial作为如何使用 OpenCV 使用此数据库的示例。我使用完全相同的技术,并且在测试数据 (t10k-images.idx3-ubyte
) 上,我的错误率为 4%。但是当我尝试对自己的数字进行分类时,我遇到了更大的错误。例如:
- 被识别为 7
- 和 被识别为 5
- 和 被识别为1
- 被识别为 8
等等(如果需要,我可以上传所有图片)。
如您所见,所有数字都具有良好的质量,并且很容易被人类识别。
所以我决定在分类之前做一些预处理。来自 MNIST database site 上的表格我发现人们正在使用 deskewing、noise removal、blurring 和 pixel shift 技术。不幸的是,几乎所有文章的链接都被破坏了。所以我决定自己做这样的预处理,因为我已经知道该怎么做了。
现在,我的算法如下:
- 腐 eclipse 图片(我觉得我原来的数字也太
粗糙)。 - 去除小轮廓。
- 阈值和模糊图像。
- 中心数字(而不是移位)。
我认为在我的情况下不需要纠偏,因为所有数字通常都会旋转。而且我也不知道如何找到合适的旋转角度。 所以在这之后我得到了这些图片:
- 也是1
- 是 3(不像以前那样 5)
- 是 5(不是 8)
- 是 7(利润!)
所以,这样的预处理对我有点帮助,但我需要更好的结果,因为在我看来,这样的数字应该可以毫无问题地识别出来。
谁能给我关于预处理的任何建议?感谢您的帮助。
附:我可以上传我的源代码 (c++)。
最佳答案
我意识到我的错误 - 它根本与预处理无关(感谢 @DavidBrown 和 @John)。我使用手写的数字数据集而不是打印的(大写)。我在网上没有找到这样的数据库,所以我决定自己创建它。我已将我的数据库上传到 Google Drive .
下面是你如何使用它(训练和分类):
int digitSize = 16;
//returns list of files in specific directory
static vector<string> getListFiles(const string& dirPath)
{
vector<string> result;
DIR *dir;
struct dirent *ent;
if ((dir = opendir(dirPath.c_str())) != NULL)
{
while ((ent = readdir (dir)) != NULL)
{
if (strcmp(ent->d_name, ".") != 0 && strcmp(ent->d_name, "..") != 0 )
{
result.push_back(ent->d_name);
}
}
closedir(dir);
}
return result;
}
void DigitClassifier::train(const string& imagesPath)
{
int num = 510;
int size = digitSize * digitSize;
Mat trainData = Mat(Size(size, num), CV_32FC1);
Mat responces = Mat(Size(1, num), CV_32FC1);
int counter = 0;
for (int i=1; i<=9; i++)
{
char digit[2];
sprintf(digit, "%d/", i);
string digitPath(digit);
digitPath = imagesPath + digitPath;
vector<string> images = getListFiles(digitPath);
for (int j=0; j<images.size(); j++)
{
Mat mat = imread(digitPath+images[j], 0);
resize(mat, mat, Size(digitSize, digitSize));
mat.convertTo(mat, CV_32FC1);
mat = mat.reshape(1,1);
for (int k=0; k<size; k++)
{
trainData.at<float>(counter*size+k) = mat.at<float>(k);
}
responces.at<float>(counter) = i;
counter++;
}
}
knn.train(trainData, responces);
}
int DigitClassifier::classify(const Mat& img) const
{
Mat tmp = img.clone();
resize(tmp, tmp, Size(digitSize, digitSize));
tmp.convertTo(tmp, CV_32FC1);
return knn.find_nearest(tmp.reshape(1, 1), 5);
}
关于c++ - 使用 KNN 分类器进行数字识别前的预处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16401974/