Перейти к содержимому
Compvision.ru
K0rG

Распознавание номерного знака, расп. текста.

Recommended Posts

ну я имел ввиду что (abs(H1i-H2i))/(H1i+H2i)

Инварианты Ху имеют разную величину. Некоторые примерно равны единице, другие же ближе к 100 или к 100000. В связи с этим обычная Евклидова метрика, нечувствительна к "первым" моментам Ху, поскольку наибольший вклад в метрику дают более большие по модулю компоненты

расстояние Махаланобиса - это такая метрика, при которой компоненты вектора взвешиваются по-разному, обратно пропорционально матрице ковариации http://courses.graphicon.ru/main/vision2009 .

я все таки думаю что ху моменты довольно грубый метод сравнения.(если сравнивать чистые образы то норм наверно ,а если с шумом или как то деформированные то тут должно быть все хуже)

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Автор, ну так что у Вас получилось можете показать пример и исходник?

пока все в процессе

Сразу попутный вопрос, можно ли произвести фильтрацию изначального изображения КИХ фильтром?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

ну я имел ввиду что (abs(H1i-H2i))/(H1i+H2i)

Лол... У меня эта формула в первом посте)

Инварианты Ху имеют разную величину. Некоторые примерно равны единице, другие же ближе к 100 или к 100000. В связи с этим обычная Евклидова метрика, нечувствительна к "первым" моментам Ху, поскольку наибольший вклад в метрику дают более большие по модулю компоненты

расстояние Махаланобиса - это такая метрика, при которой компоненты вектора взвешиваются по-разному, обратно пропорционально матрице ковариации http://courses.graphicon.ru/main/vision2009 .

Вроде бы они все меньше единицы. Поэтому я вытащил метод сравнения из cvMatchShapes. Там сначала моменты п

реобразуются как (1/log(hu))

я все таки думаю что ху моменты довольно грубый метод сравнения.(если сравнивать чистые образы то норм наверно ,а если с шумом или как то деформированные то тут должно быть все хуже)

Да... Я наивный поверил чистой теории... И вот во что это вылилось... Если маленько изменить контур, то моменты поменяются координально =\ Сегодня начну писать через скалярное произведение контуров.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Лол... У меня эта формула в первом посте)

да чо то не осознал.

Вроде бы они все меньше единицы. Поэтому я вытащил метод сравнения из cvMatchShapes. Там сначала моменты п

реобразуются как (1/log(hu))

ну да наверно лучше пользоваться ихними готовыми.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

  • Like 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Автор, ну так что у Вас получилось можете показать пример и исходник?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Ага, так он и показал исходник :)

Сейчас двигаюсь в том же направлении, в сторону карты контрастностей. Задумка интересная, однако скорость работы такого метода уж очень маленькая, далеко до real-time. У меня python 2.7 + opencv 2.3

Думаю, язык программирования тут ни при чем, ведь на каждом языке там будет перебор width*height пикселей

Как это всё дело можно ускорить?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Сначала надо узнать, что тормозит.

Язык может быть причём, так как в С/С++ можно получать значения пикселей прямым проходом по памяти.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Сначала надо узнать, что тормозит.

Язык может быть причём, так как в С/С++ можно получать значения пикселей прямым проходом по памяти.

Что значит "прямым переходом по памяти"? Изображение уже загружено в память как матрица width*height и от перебора всех пикселей изображения никуда не уйти. Или я что-то упускаю из виду?

Я пока что придумал только ресайз изображения, но скорость все равно маленькая. Значит ли это, что этот метод не подходит для real-time?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

что такое карта контрастности? что просто поиск рамки не работает в риалтайме?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Что значит "прямым переходом по памяти"? Изображение уже загружено в память как матрица width*height и от перебора всех пикселей изображения никуда не уйти. Или я что-то упускаю из виду?

Чтобы последовательно пройти по всем пикселям изображения в С/С++ можно написать такой код:

for (uchar* pbuf = (uchar*)img->imageData, *pend = (uchar*)(img->imageData + img->imageSize); pbuf != pend; pbuf += img->nChannels)

{

	func(pbuf);

}
Всё будет работать быстро: 1. обращения к памяти последовательны, а не случайны; 2. переход к следующему пикселю производится всего за одну операцию сложения (pbuf += img->nChannels). Или можно делать обращения к каждому пикселю с помощью функции:
for (int y = 0; y < img->height; ++y)

{

	for (int x = 0; x < img->width; ++x, ++pl)

	{

		func(cvGet2D(img, y, x));

	}

}

В этому случае будет каждый раз:

1. вызываться проверка на попадание координат в пределы изображения;

2. высчитываться адрес пикселя в памяти с помощью 2 умножений и сложения (img->imgData + y * img->widthStep + x * img->nChannels);

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

Если ты в Питоне проходишь по изображению, то вызовется питон-аналог именно второго варианта, который будет намного медленней рукописного первого.

Если ты из Питона вызываешь какую-нибудь функцию из OpenCV, то внутри себя она будет работать быстро, по первому варианту.

Я пока что придумал только ресайз изображения, но скорость все равно маленькая. Значит ли это, что этот метод не подходит для real-time?

Нет, не значит. Надо сперва провести профилирование.

  • Like 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

что такое карта контрастности? что просто поиск рамки не работает в риалтайме?

Насколько я понял, это тот метод, которым воспользовался nagoHok для локализации номера.

Суть такова, что номерной знак автомобиля имеет резкие переходы от черного к белому и наоборот. Строим вертикальные и горизонтальные гистрограммы и выбираем зоны наибольших скачков. Вроде так. Если что, поправьте меня.

А как предлагаете искать рамку? Я уже пробовал искать параллелограммы в контурах изображения с помощью Canny и findContours, однако точность такого метода оставляет желать лучшего, по крайней мере, в моем исполнении.

Чтобы последовательно пройти по всем пикселям изображения в С/С++ можно написать такой код:

Здорово! Спасибо за информацию. Узнаю у гуру питона, есть ли у них что-нибудь подобное и в случае чего всё-таки откажусь от питон обертки

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

из примера squares.c через поиск линий.

для гистограмм есть cv::calcHist

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Язык, как раз очень при чём. Дело в том, что на циклах как раз и проявляется тормознуть языка. Интерпритируемые языках тормазили бы жутко, если бы не замена циклов на функции из библиотек, в которых эти функции оптимизированны. В результате тормоза языка а вернее компилятора/интерпретатора будут не всегда заметны.

Не очень понял о коком алгоритме идёт речь. Но для поиска контрастных пикселей требуется 4 прохода по изображению. Все проходы простые. Ориентировочно скорость 50 мс.

Исходное изображение в градациях серого. Находим 2 вспомогательных изображения первое сглаженное. Второе возводим в квадрат и сглаженное. И четвёртый проход нужен чтобы посчитать дисперсию и сравнить с некоторым порогом. Дисперсия получается путём вычитания из второго первое. Там где дисперсия большая там контрастность большая

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

из примера squares.c через поиск линий.

для гистограмм есть cv::calcHist

Поиск контуров не всегда работает хорошо

Про гистограммы я Вас ввел в заблуждение. В этом методе строятся не просто гистограммы, а гистограммы изменений градаций ЧБ изображения. Грубо говоря, насколько X пиксель темнее/светлее X+1 пикселя. Вот та зона, где количество и "сила" таких скачков велика, там теоретически находится наш номерной знак

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Не очень понял о коком алгоритме идёт речь. Но для поиска контрастных пикселей требуется 4 прохода по изображению. Все проходы простые. Ориентировочно скорость 50 мс.

Исходное изображение в градациях серого. Находим 2 вспомогательных изображения первое сглаженное. Второе возводим в квадрат и сглаженное. И четвёртый проход нужен чтобы посчитать дисперсию и сравнить с некоторым порогом. Дисперсия получается путём вычитания из второго первое. Там где дисперсия большая там контрастность большая

а есть где почитать/посмотреть про данный метод? Или, примеры кода? Не очень ясно, о чем речь

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Поиск контуров не всегда работает хорошо

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

Грубо говоря, насколько X пиксель темнее/светлее X+1 пикселя. Вот та зона, где количество и "сила" таких скачков велика, там теоретически находится наш номерной знак

ну это можно оператор собеля (cvSobel) применить и найти "максимальные скачки".

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

Посмотрю этот пример, думал там то же, что и в squares.py. На питоне там поиск контуров, апроксимация их до прямоугольников

ну это можно оператор собеля (cvSobel) применить и найти "максимальные скачки".

а в чем смысл тогда лишнюю операцию делать?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Продолжу тему. В OpenCV реализованы моменты Ху. Насколько я выяснил:

"Продолжением было опробование других множеств полиномов в качестве базисных функций. Ч. Х. Тех и

Р. Т. Чин предложили в качестве базисных функций использовать ортогональные полиномы псевдо-

Зернике и полиномы Лежандра [Teh & Chin, 1988], Ю. Шенг и Л. Шен ввели ортогональные моменты

Фурье-Меллина [sheng & Shen, 1994], Р. Мукундан и др. предложили моменты на основе полиномов

Чебышева [Munkundan et. al., 2001], П.Т. Яп и др. предложили использовать моменты на основе

полиномов Кравчука [Yap et. al, 2003], Х.К. Жу и др. ввели в обращение моменты Рака [Zhu et. al., 2007]."

Источник Ссылка

Вот человек пытается реализовать моменты Зернике в OpenCV:

Ссылка

Насколько это правильно, реализовывать для своей задачи методы моментов, приведенные выше?

Моя подзадача стоит именно в новизне (хоть какой-то) моментных методов, применительно к нахождению инвариантного ансамбля векторов движения.

Грубо говоря, машинка на видеопоследовательности повернула на какой-то угол, а тут я кадр проанализировал моментами, и отследил ее.

Вопрос, стоит ли реализовывать существующие новые методы моментов в OpenCV, если да, то какие?

  • Like 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Оч сырой код, но более 50% локализует, предлагаю довести его до ума)

#include "stdafx.h"

#include "ContrastMap.h"



#pragma warning (disable:4996)

#include <cv.h>

#include <opencv2\highgui\highgui_c.h>

#include <math.h>



#pragma comment(lib,"opencv_core220d.lib")

#pragma comment(lib,"opencv_highgui220d.lib")

#pragma comment(lib,"opencv_imgproc220d.lib")

#pragma comment(lib,"opencv_video220d.lib")

#pragma comment(lib,"opencv_legacy220d.lib")


#ifdef _DEBUG

#define new DEBUG_NEW

#endif



// The one and only application object


CWinApp theApp;


using namespace std;



class CBlock

{	

public:

	int m_nStartPoin;

	int m_nEndPoint;

	int m_nBlockLen;

	CBlock(void)

	{

		m_nStartPoin = 0;

		m_nEndPoint = 0;

		m_nBlockLen = 0;

	}

	virtual ~CBlock(void)

	{


	}

	void Empty()

	{

		m_nStartPoin = 0;

		m_nEndPoint = 0;

		m_nBlockLen = 0;

	}

	bool IsNull(){return m_nBlockLen ? false : true;}

};


void SummRow(const IplImage* pSrc, CArray<double>& arRow)

{

	arRow.RemoveAll();

	arRow.SetSize(pSrc->height);	

	for (int nPosY = 0; nPosY < pSrc->height; nPosY++)

	{

		int nOffset = pSrc->widthStep * nPosY;

		for (int nPosX = 0; nPosX < pSrc->widthStep; nPosX++)

		{

			arRow[nPosY] += (uchar)pSrc->imageData[nOffset + nPosX];

		}	

	}

}

void DrawGraf(IplImage* pSrc, const CArray<double>& arRow)

{

	CvPoint ptLastPoint = cvPoint(0, 0);

	for (int nPos = 0; nPos < arRow.GetCount(); nPos++)

	{

		cvDrawLine(pSrc, ptLastPoint, cvPoint((int)arRow[nPos] / 200, nPos) , cvScalar(0), 1);

		ptLastPoint = cvPoint((int)arRow[nPos] / 200, nPos);

	}

}


void AplyFilter(const IplImage* pSrc, IplImage* pDest)

{

	double arMask[9] = {0,0,0,0,0.5,0,0,0,0};

	//double arSharp[9] = {0.1111, -0.8889, 0.1111, -0.8889, 4.1111, -0.8889, 0.1111, -0.8889, 0.1111};

	CvMat matMask = cvMat(3, 3, CV_64FC1, arMask);				

	cvFilter2D(pSrc, pDest, &matMask, cvPoint(-1,-1));

}


void AplySobel(const IplImage* pScr, IplImage* pDest)

{

	IplImage* pDst = cvCreateImage( cvSize(pScr->width, pScr->height), IPL_DEPTH_16S, pScr->nChannels);

	// применяем оператор Собеля

	cvSobel(pScr, pDst, 1, 0, 3);

	// преобразуем изображение к 8-битному

	cvConvertScale(pDst, pDest);

	cvReleaseImage(&pDst);

}



inline double GSmooth(double nDist, double nParam, double nParam2)

{	

	return exp((-(nDist * nDist)/nParam)) / nParam2;	

}


void GauseSmooth(const CArray<double>& arSrc, CArray<double>& arDest)

{

	arDest.RemoveAll();


	double nParam = 3.;

	int nAperture = 5;

	double nParam1 = 2* (nParam * nParam);

	double nParam2 = sqrt(2 * CV_PI) * nParam;


	arDest.SetSize(arSrc.GetCount());


	for (int nPos = 0; nPos < arSrc.GetCount() - 1; nPos++)

	{

		double s = 0.;

		for (int nK = max(nPos - nAperture, 0); nK < min(arSrc.GetCount() - 1, nPos + nAperture); nK++)

		{

			s += arSrc[nK] * GSmooth(abs(nPos - nK), nParam1, nParam2);

		}		

		arDest.SetAt(nPos, s);

	}

}


void Func(IplImage* pImg, int nPosY, CArray<double>& arFunc)

{

	arFunc.RemoveAll();

	double _f = 0.;	

	int nLinePos = nPosY * pImg->widthStep;

	arFunc.SetSize( pImg->widthStep - 1);     

	for(int nPos = 0; nPos < pImg->widthStep - 1; nPos++)

	{			

		_f += abs(pImg->imageData[nLinePos + nPos + 1] - pImg->imageData[nLinePos + nPos]);			

		arFunc.SetAt(nPos, _f);

	}	

}


void GetFirstDiff(const CArray<double>& arSrc, CArray<double>& arDest)

{	

	CArray<double> arTmp;

	arTmp.SetSize(arSrc.GetCount());

	for (int nPos = 1; nPos < arSrc.GetCount(); nPos++)

	{		

		if(nPos + 1 > arSrc.GetCount() - 1)

			continue;

		double ndY = arSrc[nPos + 1] - arSrc[nPos];			

		arTmp.SetAt(nPos, ndY);

	}

	arDest.RemoveAll();  

	arDest.Copy(arTmp);

	arTmp.RemoveAll();

}


int GetMaxPosition(CArray<double>& arGraf)

{

	int nMax = 0;

	for (int nPos = 0; nPos < arGraf.GetCount(); nPos++)

	{

		if(arGraf[nPos] > arGraf[nMax])

			nMax = nPos;

	}

	return nMax;

}


void GetLocalMinMax(const CArray<double>& arData, CArray<int>& arPositionsMin, CArray<int>& arPositionsMax)

{

	int nCount = 0;

	double nMin = 0, nMax = 0;	

	bool bIsMaxF = false;

	bool bIsMinF = false;


	for(int nPos = 1; nPos < arData.GetCount() - 1; nPos++)

	{

		//Отслеживаем уменьшение.

		if ((nPos == 1) || (arData[nPos - 1] < arData[nPos]))

		{

			nMax = arData[nPos];

			bIsMaxF = true;

		}

		if ((nPos == 1) || (arData[nPos - 1] > arData[nPos]))

		{

			nMin = arData[nPos];

			bIsMinF = true;

		}

		//Если ранее было обнаружено уменьшение.

		if(bIsMaxF)

		{

			//Отслеживаем увеличение.

			if ((nPos == arData.GetCount() - 1) || (arData[nPos - 1] > arData[nPos]))

			{

				//Очередной локальный max найден.

				arPositionsMax.Add(nPos);

				nCount++;

				if(nCount == 1)

					nMin = nMax;

				else if(nMax < nMin)

					nMin = nMax;

				bIsMaxF = false;

			}

		}

		if(bIsMinF)

		{

			//Отслеживаем увеличение.

			if ((nPos == arData.GetCount() - 1) || (arData[nPos - 1] < arData[nPos]))

			{

				//Очередной локальный минимум найден.

				arPositionsMin.Add(nPos);

				nCount++;

				if(nCount == 1)

					nMax = nMin;

				else if(nMin > nMax)

					nMax = nMin;

				bIsMinF = false;

			}

		}

	}

}


void CalcBlocks(int nMinBlockLen, CArray<CBlock>& m_arWidthBlock, double nAvVal, const CArray<double>& arData)

{

	m_arWidthBlock.RemoveAll();

	CBlock block;

	int nSpaces = 0;

	for (int nPos = 0; nPos < arData.GetCount(); nPos++)

	{

		if(arData[nPos] >= nAvVal)

		{

			if(block.m_nStartPoin)

			{

				block.m_nBlockLen++;

				nSpaces = 0;

			}

			else

			{

				block.m_nStartPoin = nPos;

				block.m_nBlockLen++;

				nSpaces = 0;

			}

		}

		else

		{

			if(block.m_nStartPoin)

			{

				if(nSpaces >= nMinBlockLen)

				{

					block.m_nEndPoint = nPos - nSpaces;

					block.m_nBlockLen -= nSpaces;

					nSpaces = 0;

					m_arWidthBlock.Add(block);

					block.Empty();

					continue;

				}

				nSpaces++;				

			}


		}

	}

	if(block.m_nStartPoin)

	{ 

		block.m_nEndPoint = arData.GetCount() - nSpaces;

		m_arWidthBlock.Add(block);

	}

}


int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])

{

	IplImage* pFrame = NULL;		//Захваченый фрейм

	IplImage* pGray = NULL;			//Фрейм приведенный к серому цвету	

	IplImage* pGrath = NULL;		//Тут рисуем графики


	CFileFind finder;

	//BOOL bWorking = finder.FindFile(_T("c:/Utils/Работа/Мое/Распознание/Саша/Day/*.*"));	

	BOOL bWorking = finder.FindFile(_T("C:/Users/Я/Desktop/Avto-Control Demo/Images/Day/*.*"));	

	while (bWorking)

	{

		bWorking = finder.FindNextFile();

		if(!bWorking)

			break;

		CStringA strFileName(finder.GetFilePath());

		if(finder.IsDots())

			continue;

		TRACE(strFileName.GetString());

		TRACE(_T("\n"));

		pFrame = cvLoadImage(strFileName);

		if(!pFrame)

			continue;



		DWORD dwStart = GetTickCount();

		cvSmooth(pFrame, pFrame, CV_GAUSSIAN, 3, 3);



		//Создаем серое изображение

		pGray = cvCreateImage(cvGetSize(pFrame), 8, 1);

		cvConvertImage(pFrame, pGray, CV_BGR2GRAY);	


		//Выравниваем яркость изображения		

		cvEqualizeHist(pGray, pGray);


		CArray<double> arGraf;


		AplySobel(pGray, pGray);

		SummRow(pGray, arGraf);

		int nMaxPos = GetMaxPosition(arGraf);


		CArray<double> arFunc;

		Func(pGray, nMaxPos, arFunc);

		CArray<double> arSmooth;

		//GauseSmooth(arFunc, arSmooth);

		CArray<double> arDif;

		GetFirstDiff(arFunc, arDif);



		CArray<int> arMins;

		CArray<int> arMaxs;

		GetLocalMinMax(arDif, arMins, arMaxs);

		int nMaxFromMax = GetMaxPosition(arDif);

		double nAvValMax = arDif[nMaxFromMax] * 0.2;



		CArray<CBlock> arBlocks;

		CalcBlocks(20, arBlocks, nAvValMax, arDif);



	/*	for (int nPos = 0; nPos < arMaxs.GetCount(); nPos++)

		{

			nAvValMax += arDif[arMaxs[nPos]];

		}*/


		//nAvValMax = nAvValMax / arMaxs.GetCount();

		//nAvValMax = nAvValMax + nAvValMax * 0.2;


		pGrath = cvCreateImage(cvGetSize(pFrame), 8, 1);



		DrawGraf(pFrame, arGraf);


		CvPoint ptLast = cvPoint(0, nMaxPos);

		int nCount = 0;

//		for (int nPos = 0; nPos < arDif.GetCount(); nPos++)

//		{

//			//if(arDif[nPos] < nAvValMax)

//			//{

//			//	//cvDrawLine(pGrath, cvPoint(nPos, nMaxPos), cvPoint(nPos, nMaxPos - (int)(arDif[nPos])), cvScalar(0), 1);

//			//	continue;

//			//}

//

//			nCount++;

//			cvDrawLine(pFrame, cvPoint(nPos, nMaxPos), cvPoint(nPos, nMaxPos + (int)(arDif[nPos] / 5)), cvScalar(0), 1);

//

///*

//			int nPosY = (nMaxPos + (int)arDif[nPos] / 5);

//			cvDrawLine(pGrath, ptLast, cvPoint(nPos, nPosY), cvScalar(0), 1);

//			ptLast = cvPoint(nPos, nPosY);

//*/

//		}


		for (int nPos = 0; nPos < arBlocks.GetCount(); nPos++)

		{

			CBlock &block = arBlocks[nPos];

			int nHigh = (int)(block.m_nEndPoint - block.m_nStartPoin) / 9.2;

			if(arBlocks[nPos].m_nBlockLen < 10 || arBlocks[nPos].m_nBlockLen > 100)

				continue;

			cvDrawRect(pFrame, cvPoint(arBlocks[nPos].m_nStartPoin - 10, nMaxPos - nHigh), cvPoint(arBlocks[nPos].m_nEndPoint + 10, nMaxPos + nHigh), cvScalar(255), 2);

		}


		std::cout << nCount << " " << GetTickCount() - dwStart << std::endl ;

		cvNamedWindow("Graf");

		cvShowImage("Graf", pFrame);



		cvReleaseImage(&pGray);

		cvReleaseImage(&pFrame);	

		cvReleaseImage(&pGrath);	



		char c = cvWaitKey(0);

		if (c == 27) 

		{ 

			break;

		}

	}


	return 0;

}

post-1451-0-77747800-1331761781_thumb.pn

  • Like 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Друзья, а у Вас есть какая-либо выборка состоящая из изображений авто с номерными знаками? хотяб пару сотен обучающих изображений?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

нет, но собрать не сложно:

в Google поиск картинок набираем "номерной знак автомобиля" и получаем много автомобильных номеров. Правда без ручного труда тут не получится обойтись.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте учётную запись или войдите для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать учётную запись

Зарегистрируйтесь для создания учётной записи. Это просто!

Зарегистрировать учётную запись

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас


  • Сейчас на странице   0 пользователей

    Нет пользователей, просматривающих эту страницу

×