Jump to content
Compvision.ru
K0rG

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

Recommended Posts

оп, необновил страничку помоему Smorodov как раз на это ссылку дал.

Share this post


Link to post
Share on other sites

Добавил сглаживание, не скажу что уж очень сгладилось но больших пиков уже нет

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

{

	cvNamedWindow("Org");

	cvNamedWindow("Gray");

	IplImage* frame = NULL;	


	frame = cvLoadImage("c:/test.jpg");


	IplImage* gray = NULL;


	gray = cvCreateImage(cvGetSize(frame), 8, 1);


	cvConvertImage(frame, gray, CV_BGR2GRAY);




	CvPoint ptLast = cvPoint(0, 0);


	DWORD dwStart = GetTickCount();

	int nLastYPos = 0;



	for (int nY = 0; nY < gray->height; nY+=10)

	{

		ptLast = cvPoint(0, nY);

		for (int nX = 2; nX < gray->widthStep - 2; nX++)

		{

			int nAv = 0;

			for (int nPos = -2; nPos < 3; nPos++)

			{

				nAv += gray->imageData[nY * gray->widthStep + nX + nPos];

			}	

			nAv = abs(nAv);

			nAv /= 50;

			//int nBr1 =  gray->imageData[nY * gray->widthStep + nX + 1] / 10;

			//nBr = abs(nBr1 - nBr);

			cvLine(frame, ptLast, cvPoint(nX, nY - nAv) , cvScalar(0), 1);

			ptLast = cvPoint(nX, nY - nAv);

		}

	}


	dwStart = GetTickCount() - dwStart;


	std::cout << dwStart;



	cvShowImage("Gray", gray);

	cvShowImage("Org", frame);


	cvReleaseImage(&gray);

	cvReleaseImage(&frame);


	gray = NULL;

	frame = NULL;


	char c = cvWaitKey(0);

	if (c == 27) 

	{ 

		return 0;

	}

	return 0;

}

post-1451-0-53395400-1310559346_thumb.jp

Share this post


Link to post
Share on other sites

Не то. Надо найти сумму модулей разниц соседних точек и её сглаживать. А у Вас, по моему, просто разницы нарисованы.

На 21 странице формула гласит:

float f(float x)
{
float _f=0;
for(int i=0;i<x-2;i++)
{
_f+=fabs(I[i+1]-I[i]);
}
return _f;
}[/code]

вот это надо сглаживать и брать производную.

Share this post


Link to post
Share on other sites

Так если я правильно понял то float x - это позиция пикселя?

тогда скажем для конечнего пикселя к примеру 640-го будет произведено 638 итераций?

Share this post


Link to post
Share on other sites
Добавил сглаживание, не скажу что уж очень сгладилось но больших пиков уже нет

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

хотя вот интересно какой результат производной будет без сглаживания.

Так если я правильно понял то float x - это позиция пикселя?

тогда скажем для конечнего пикселя к примеру 640-го будет произведено 638 итераций?

т.к. там производится суммирование, то да для последней точки надо просчитать N-1 предыдущих

for(int i=0;i<x-2;i++) не очень понял почему -2 мне кажется -1 должно быть.

Share this post


Link to post
Share on other sites

-2 не разбирался, как в документе было так и написал. Вычислительные затраты, естественно можно сильно сократить, прогнав f(x) только для конечного пикселя, и занося результат каждой итерации в выходной массив.

Это я просто формулу из документа один в один привел.

Share this post


Link to post
Share on other sites

так ну вроде получилось заставить работать функцию, спасибо Smorodov, сейчас осталось взять от неё производные, и работать с локализацией пластины.

Можно еще поработать со сглаживанием, но изначальная оптимизация ЗЛО! :D Хотя и в данном варианте быстродействие меня вполне устраивает.


class _Line

{

	int m_nSize;	

public:

	_Line()

		:m_nSize(0)

		,m_nYPosition(0)		

	{};

	virtual ~_Line(){};

	CArray<int>	m_arData;

	int GetSize() const {return m_nSize;};	

	void SetSize(int nSize)

	{

		if(nSize <= 0)

			return;

		m_nSize = nSize;

		m_arData.SetSize(m_nSize, 10);

	}

	_Line& operator = (const _Line& src)

	{

		SetSize(src.m_nSize);

		m_nYPosition = src.m_nYPosition;

		m_arData.Copy(src.m_arData);

		return *this;

	}


	int m_nYPosition;

};


void SmoothFunc(const CArray<_Line>& arSrc, CArray<_Line>& arDest)

{

	arDest.RemoveAll();	

	for (int nPosY = 0; nPosY < arSrc.GetCount(); nPosY++)

	{

		_Line line;

		line.SetSize(arSrc[nPosY].GetSize());

		line.m_nYPosition = arSrc[nPosY].m_nYPosition;		

		for (int nPosX = 0; nPosX < arSrc[nPosY].GetSize() - 2; nPosX++)

		{

			int nSmooth = 0;

			for (int nSmoothPos = -2; nSmoothPos < 3; nSmoothPos++)

			{

				if(nPosX < 2 && nSmoothPos < 0)

					continue;

				nSmooth += arSrc[nPosY].m_arData[nPosX + nSmoothPos];

			}

			nSmooth /= 5;

			line.m_arData[nPosX] = nSmooth;

		}

		arDest.Add(line);

	}

}


void Func(IplImage* pImg, int nPosY, _Line& line)

{

	unsigned int _f = 0;

	int nLinePos = nPosY * pImg->widthStep;

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

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

	{

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

		line.m_arData[nPos] = _f;

	}

}



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

{

	cvNamedWindow("Org");

	cvNamedWindow("Gray");

	IplImage* frame = NULL;

	frame = cvLoadImage("c:/test.jpg");


	IplImage* gray = NULL;


	gray = cvCreateImage(cvGetSize(frame), 8, 1);


	cvConvertImage(frame, gray, CV_BGR2GRAY);




	CvPoint ptLast = cvPoint(0, 0);


	DWORD dwStart = GetTickCount();

	int nLastYPos = 0;


	CArray<_Line>	arLines;

	CArray<_Line> arLinesSmoth;


	for (int nY = 0; nY < gray->height; nY += 10)

	{

		//ptLast = cvPoint(0, nY);

		_Line line;

		line.m_nYPosition = nY;

		Func(gray, nY, line);

		arLines.Add(line);		

	}

	SmoothFunc(arLines, arLinesSmoth);


	CArray<_Line> arDraw;

	arDraw.Copy(arLinesSmoth);


	for (int nPosY = 0; nPosY < arDraw.GetCount(); nPosY++)

	{

		if(nPosY != 46)     //Убрать!!!!

			continue;   //Убрать!!!!

		ptLast = cvPoint(0, arDraw[nPosY].m_nYPosition);

		for (int nPosX = 0; nPosX < arDraw[nPosY].GetSize(); nPosX++)

		{

			int f = arDraw[nPosY].m_arData[nPosX] / 50;

			cvLine(frame, ptLast, cvPoint(nPosX, arDraw[nPosY].m_nYPosition - f) , cvScalar(0), 1);

			ptLast = cvPoint(nPosX, arDraw[nPosY].m_nYPosition - f);

		}		

	}



	dwStart = GetTickCount() - dwStart;


	std::cout << dwStart;



	cvShowImage("Gray", gray);

	cvShowImage("Org", frame);



	cvReleaseImage(&gray);

	cvReleaseImage(&frame);


	gray = NULL;

	frame = NULL;


	char c = cvWaitKey(0);

	if (c == 27) 

	{ 

		return 0;

	}

	return 0;

}

post-1451-0-65047100-1310594207_thumb.jp

Share this post


Link to post
Share on other sites

ну производную, то в дискретном случае можно взять как (y2-y1)/(x2-x1).

как сглаживать и зачем не знаю.

Поясните пжл, что в данном случае y2 y1, x2 x1?

Спасибо за рание!

Утро вечера мудренее :)


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

{

	arDest.RemoveAll();     

	for (int nPosY = 0; nPosY < arSrc.GetCount(); nPosY++)

	{

		_Line line;

		line.SetSize(arSrc[nPosY].GetSize());

		line.m_nYPosition = arSrc[nPosY].m_nYPosition;          

		for (int nPosX = 0; nPosX < arSrc[nPosY].GetSize() - 2; nPosX++)

		{

			int nDiff = 0;

			int nY = arSrc[nPosY].m_nYPosition;

			if(nPosX + 1 > arSrc[nPosY].GetSize())

				return;

			int ndY = (nY - arSrc[nPosY].m_arData[nPosX + 1]) - (nY - arSrc[nPosY].m_arData[nPosX]);

			int ndX = arSrc[nPosY].m_arData[nPosX + 1] - arSrc[nPosY].m_arData[nPosX];

			if(ndX)

				nDiff = ndY / ndX;


			line.m_arData[nPosX] = nDiff;

		}

		arDest.Add(line);

	}

}

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

Share this post


Link to post
Share on other sites
Поясните пжл, что в данном случае y2 y1, x2 x1?

ну вот вы получили функцию F(x).

если брать шаг =1 то, y2=F(i+1) y1=F(i) и x2-x1=1

Share this post


Link to post
Share on other sites

ну вот вы получили функцию F(x).

если брать шаг =1 то, y2=F(i+1) y1=F(i) и x2-x1=1

втом то и дело, что я реализовал, но график производной - прямая

т.е. разница приращения y2-y1 всего 1 пиксель

Share this post


Link to post
Share on other sites

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

попробуйте еще шаг поменять, т.е. шаг =step то, y2=F(i+step) y1=F(i) и x2-x1=step, хотя не думаю, что это поможет.

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

взять какой то отступ(в % или константой), и пройтись от начала т.е. до точки 0+отступ (это будет начало таблички) и от конца до точки конец-отступ (это будет конец таблички).

вообще метод кажется не особо надежным, обычно делают детектор движения(определяют движущийся объект-машину)+ Канни(или что то похожее) + поиск прямоугольника(таблички).

Share this post


Link to post
Share on other sites

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

попробуйте еще шаг поменять, т.е. шаг =step то, y2=F(i+step) y1=F(i) и x2-x1=step, хотя не думаю, что это поможет.

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

взять какой то отступ(в % или константой), и пройтись от начала т.е. до точки 0+отступ (это будет начало таблички) и от конца до точки конец-отступ (это будет конец таблички).

вообще метод кажется не особо надежным, обычно делают детектор движения(определяют движущийся объект-машину)+ Канни(или что то похожее) + поиск прямоугольника(таблички).

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

Share this post


Link to post
Share on other sites

Значения функции и её производной, в данном случае лучше считать в действительных числах (float), т.к. оно действительно получается небольшим. Производную лучше брать на участке хотя-бы 10 пикселей длинной тогда она получится точнее (до 0.1). Слишком большие длины приведут к потере точности локализации номера. Так что выбирайте оптимум.

ЗЫ: Это все равно что сначала сгладить функцию, а потом искать производную.

Share this post


Link to post
Share on other sites

Нашел ошибку в реализации


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

{

        arDest.RemoveAll();     

        for (int nPosY = 0; nPosY < arSrc.GetCount(); nPosY++)

        {

                _Line line;

                line.SetSize(arSrc[nPosY].GetSize());

                line.m_nYPosition = arSrc[nPosY].m_nYPosition;          

                for (int nPosX = 0; nPosX < arSrc[nPosY].GetSize() - 2; nPosX++)

                {

                        int nDiff = 0;

                        int nY = arSrc[nPosY].m_nYPosition;

                        if(nPosX + 1 > arSrc[nPosY].GetSize())

                                return;

                        int ndY = (nY - arSrc[nPosY].m_arData[nPosX + 1]) - (nY - arSrc[nPosY].m_arData[nPosX]);

                        int ndX = nPosX + 1 - nPosX;  //Можно и не делить

                        if(ndX)                       //Так как шаг всегда 1

                                nDiff = ndY / ndX;


                        line.m_arData[nPosX] = nDiff;

                }

                arDest.Add(line);

        }

}

да сейчас придется поработать над сглаживанием

post-1451-0-08639000-1310626694_thumb.jp

Share this post


Link to post
Share on other sites

Только int-ы на float или double поменяйте, иначе ничего гладкого не получится.

С целочисленной арифметикой надо очень аккуратно работать иначе очень долго можно потом ошибку искать.

Share this post


Link to post
Share on other sites

Только int-ы на float или double поменяйте, иначе ничего гладкого не получится.

С целочисленной арифметикой надо очень аккуратно работать иначе очень долго можно потом ошибку искать.

Вот результат того же алгоритма но с вещественными значениями, имхо с интами было лучше)

ЗЫ вывод надо менять алгоритм сглаживания.

post-1451-0-59973400-1310628310_thumb.jp

Share this post


Link to post
Share on other sites

А CArray<int> m_arData; тоже на float поменяли? (int nSmooth, кстати тоже)

Да, и фильтр можно считать попроще:

AvgX=(I+AvgX)/(i+1);

где AvgX - результат усреднения, I - усредняемая величина, i - количество точек по которым считается фильтр.

Cumulative Average (CA) в материале wiki

ЗЫ: 5 точек, маловато, я думаю надо примерно от четверти до половины номера в длину брать.

Share this post


Link to post
Share on other sites

ЗЫ: 5 точек, маловато, я думаю надо примерно от четверти до половины номера в длину брать.

так а как определить длинну номера тогда?

К томуже если при движение размеры плитки будут меняться?

Share this post


Link to post
Share on other sites

Вероятно нужно принять минимальные и максимальные возможные размеры номера и проводить несколько проверок с разными параметрами фильтра.

А еще можно пирамиду сделать и по ней искать.

Share this post


Link to post
Share on other sites
так а как определить длинну номера тогда?

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

К томуже если при движение размеры плитки будут меняться?

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

Share this post


Link to post
Share on other sites

даже обычный пример из squares.c работает неплохо.

thumb.png

работает то неплохо, но далек от реального времени.

Share this post


Link to post
Share on other sites

так тут походу разбора полетов возник вопрос

интенсивность яркости у нас от 0 до 255, значения IplImage::imageData у нас char т.е. от -127 до 128, правильно ли будет для получения функции приобразовывать char к unsigned char? или это надуманно?

Share this post


Link to post
Share on other sites
For a multi-channel byte image:

IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);

((uchar *)(img->imageData + i*img->widthStep))[j*img->nChannels + 0]=111; // B

((uchar *)(img->imageData + i*img->widthStep))[j*img->nChannels + 1]=112; // G

((uchar *)(img->imageData + i*img->widthStep))[j*img->nChannels + 2]=113; // R

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


  • Recently Browsing   0 members

    No registered users viewing this page.

×