Предварительная обработка перед распознаванием цифр с помощью классификатора KNN

Прямо сейчас я пытаюсь создать систему распознавания цифр с использованием OpenCV. Есть много статей и примеров в сети (и даже на Переполнение стека). Я решил использовать КНН классификатор потому что это решение является самым популярным в сети. Я нашел база рукописных цифр с обучающим набором из 60 тыс. примеров и частотой ошибок менее 5%.

я использовал этот урок В качестве примера того, как работать с этой базой данных, используя OpenCV. Я использую точно такую ​​же технику и на тестовых данных (t10k-images.idx3-ubyte) У меня 4% ошибок. Но когда я пытаюсь классифицировать свои собственные цифры, я получаю гораздо большую ошибку. Например:

  • введите описание изображения здесь признается как 7
  • введите описание изображения здесь а также введите описание изображения здесь признаются как 5
  • введите описание изображения здесь а также введите описание изображения здесь признаются как 1
  • введите описание изображения здесь признается как 8

И так далее (я могу загрузить все изображения, если это необходимо).

Как видите, все цифры имеют хорошее качество и легко узнаваемы для человека.

Поэтому я решил сделать некоторую предварительную обработку перед классификацией. Со стола на База данных MNIST Я обнаружил, что люди используют Выравнивание, удаление шума, нечеткость а также сдвиг пикселей методы. К сожалению, почти все ссылки на статьи не работают. Поэтому я решил сделать такую ​​предварительную обработку самостоятельно, потому что я уже знаю, как это сделать.

Прямо сейчас мой алгоритм следующий:

  1. Разрушенное изображение (я думаю, что мои оригинальные цифры слишком
    грубый).
  2. Удалить небольшие контуры.
  3. Порог и размытие изображения.
  4. Центральная цифра (вместо сдвига).

Я думаю, что в моей ситуации нет необходимости в перекосе, потому что все цифры обычно вращаются. А также я не знаю, как найти правильный угол поворота.
Итак, после этого у меня есть эти изображения:

  • введите описание изображения здесь это также 1
  • введите описание изображения здесь является 3 (не 5 как раньше)
  • введите описание изображения здесь является 5 (не 8)
  • Элемент списка является 7 (Прибыль!)

Таким образом, такая предварительная обработка мне немного помогла, но мне нужны лучшие результаты, потому что, на мой взгляд, такие цифры должны распознаваться без проблем.

Кто-нибудь может дать мне какой-нибудь совет с предварительной обработкой? Спасибо за любую помощь.

Постскриптум Я могу загрузить свой исходный код (c ++).

11

Решение

Я понял свою ошибку — это не было связано с предварительной обработкой вообще (благодаря @DavidBrown а также @John). Я использовал рукописный набор данных цифр вместо печатных (с заглавной буквы). Я не нашел такой базы данных в сети, поэтому решил создать ее самостоятельно. Я загрузил свою базу данных в Гугл Диск.

А вот как вы можете его использовать (обучать и классифицировать):

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);
}
3

Другие решения

5 & 6, 1 & 7, 9 & 8 признаются одинаковыми, потому что центральные точки классов слишком похожи. Как насчет этого ?

  • Примените метод маркировки подключенного компонента к цифрам, чтобы получить реальные границы цифр и обрезать изображения через эти границы. Таким образом, вы будете работать над более правильной областью, а центральные точки нормализуются.
  • Затем разделите цифры на две части по горизонтали. (Например, у вас будет два круга после деления «8»)

В результате «9» и «8» более узнаваемы, а также «5» и «6». Верхние части будут такими же, а нижние — разными.

1

Я не могу дать вам лучший ответ, чем ваш собственный, но я бы хотел посоветовать. Вы можете улучшить свою систему распознавания цифр следующим образом:

  • Нанесите поверх белого и черного пятна процесс скелетонизации.

  • После этого подать заявку дистанционное преобразование.

Таким образом, вы можете улучшить результаты классификатора, когда цифры не точно отцентрированы или не совсем совпадают, морфологически говоря.

0
По вопросам рекламы [email protected]