nagoHok 4 Жалоба Опубликовано July 13, 2011 оп, необновил страничку помоему Smorodov как раз на это ссылку дал. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
nagoHok 4 Жалоба Опубликовано July 13, 2011 Добавил сглаживание, не скажу что уж очень сгладилось но больших пиков уже нет 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; } Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано July 13, 2011 Не то. Надо найти сумму модулей разниц соседних точек и её сглаживать. А у Вас, по моему, просто разницы нарисованы. На 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] вот это надо сглаживать и брать производную. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
nagoHok 4 Жалоба Опубликовано July 13, 2011 вот это надо сглаживать и брать производную. Спасибо большое! Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
nagoHok 4 Жалоба Опубликовано July 13, 2011 Так если я правильно понял то float x - это позиция пикселя? тогда скажем для конечнего пикселя к примеру 640-го будет произведено 638 итераций? Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано July 13, 2011 Добавил сглаживание, не скажу что уж очень сгладилось но больших пиков уже нет так вроде так и должно быть должны сгладятся маленькие неровности, а большие пики должны остаться. хотя вот интересно какой результат производной будет без сглаживания. Так если я правильно понял то float x - это позиция пикселя? тогда скажем для конечнего пикселя к примеру 640-го будет произведено 638 итераций? т.к. там производится суммирование, то да для последней точки надо просчитать N-1 предыдущих for(int i=0;i<x-2;i++) не очень понял почему -2 мне кажется -1 должно быть. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано July 13, 2011 -2 не разбирался, как в документе было так и написал. Вычислительные затраты, естественно можно сильно сократить, прогнав f(x) только для конечного пикселя, и занося результат каждой итерации в выходной массив. Это я просто формулу из документа один в один привел. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
nagoHok 4 Жалоба Опубликовано July 13, 2011 так ну вроде получилось заставить работать функцию, спасибо Smorodov, сейчас осталось взять от неё производные, и работать с локализацией пластины. Можно еще поработать со сглаживанием, но изначальная оптимизация ЗЛО! Хотя и в данном варианте быстродействие меня вполне устраивает. 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; } Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
nagoHok 4 Жалоба Опубликовано July 13, 2011 ну производную, то в дискретном случае можно взять как (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); } } правда получается сплошная линия, толи я опять что то не так сделал, толи флрмула производной не та. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано July 14, 2011 Поясните пжл, что в данном случае y2 y1, x2 x1? ну вот вы получили функцию F(x). если брать шаг =1 то, y2=F(i+1) y1=F(i) и x2-x1=1 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
nagoHok 4 Жалоба Опубликовано July 14, 2011 ну вот вы получили функцию F(x). если брать шаг =1 то, y2=F(i+1) y1=F(i) и x2-x1=1 втом то и дело, что я реализовал, но график производной - прямая т.е. разница приращения y2-y1 всего 1 пиксель Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано July 14, 2011 значит ошибка где то в коде, т.к. график у вас получился правильный и там видно, что 2 участка где ф-ия почти не возрастает (по бокам), и "лесенка" (в середине). попробуйте еще шаг поменять, т.е. шаг =step то, y2=F(i+step) y1=F(i) и x2-x1=step, хотя не думаю, что это поможет. по большому счету вы уже сейчас можете определить границы таблички. взять какой то отступ(в % или константой), и пройтись от начала т.е. до точки 0+отступ (это будет начало таблички) и от конца до точки конец-отступ (это будет конец таблички). вообще метод кажется не особо надежным, обычно делают детектор движения(определяют движущийся объект-машину)+ Канни(или что то похожее) + поиск прямоугольника(таблички). Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
nagoHok 4 Жалоба Опубликовано July 14, 2011 значит ошибка где то в коде, т.к. график у вас получился правильный и там видно, что 2 участка где ф-ия почти не возрастает (по бокам), и "лесенка" (в середине). попробуйте еще шаг поменять, т.е. шаг =step то, y2=F(i+step) y1=F(i) и x2-x1=step, хотя не думаю, что это поможет. по большому счету вы уже сейчас можете определить границы таблички. взять какой то отступ(в % или константой), и пройтись от начала т.е. до точки 0+отступ (это будет начало таблички) и от конца до точки конец-отступ (это будет конец таблички). вообще метод кажется не особо надежным, обычно делают детектор движения(определяют движущийся объект-машину)+ Канни(или что то похожее) + поиск прямоугольника(таблички). да сейчас как раз эксперементирую, на счет надежности метода - это часть алгоритма локализации таблички, конечноже она будет будет работать совместно с детектором движения, хотя пока не стоит забегать в перед. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано July 14, 2011 Значения функции и её производной, в данном случае лучше считать в действительных числах (float), т.к. оно действительно получается небольшим. Производную лучше брать на участке хотя-бы 10 пикселей длинной тогда она получится точнее (до 0.1). Слишком большие длины приведут к потере точности локализации номера. Так что выбирайте оптимум. ЗЫ: Это все равно что сначала сгладить функцию, а потом искать производную. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
nagoHok 4 Жалоба Опубликовано July 14, 2011 Нашел ошибку в реализации 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); } } да сейчас придется поработать над сглаживанием Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано July 14, 2011 Только int-ы на float или double поменяйте, иначе ничего гладкого не получится. С целочисленной арифметикой надо очень аккуратно работать иначе очень долго можно потом ошибку искать. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
nagoHok 4 Жалоба Опубликовано July 14, 2011 Только int-ы на float или double поменяйте, иначе ничего гладкого не получится. С целочисленной арифметикой надо очень аккуратно работать иначе очень долго можно потом ошибку искать. Вот результат того же алгоритма но с вещественными значениями, имхо с интами было лучше) ЗЫ вывод надо менять алгоритм сглаживания. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано July 14, 2011 А CArray<int> m_arData; тоже на float поменяли? (int nSmooth, кстати тоже) Да, и фильтр можно считать попроще: AvgX=(I+AvgX)/(i+1); где AvgX - результат усреднения, I - усредняемая величина, i - количество точек по которым считается фильтр. Cumulative Average (CA) в материале wiki ЗЫ: 5 точек, маловато, я думаю надо примерно от четверти до половины номера в длину брать. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
nagoHok 4 Жалоба Опубликовано July 14, 2011 ЗЫ: 5 точек, маловато, я думаю надо примерно от четверти до половины номера в длину брать. так а как определить длинну номера тогда? К томуже если при движение размеры плитки будут меняться? Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано July 14, 2011 Вероятно нужно принять минимальные и максимальные возможные размеры номера и проводить несколько проверок с разными параметрами фильтра. А еще можно пирамиду сделать и по ней искать. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано July 14, 2011 так а как определить длинну номера тогда? на графике производной где первый сильный скачок там начало номера, где последний конец номера. К томуже если при движение размеры плитки будут меняться? более того такой же график(но скорее с менее ярковыраженными пиками будет выскакивать и на фарах автомобиля). Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано July 15, 2011 даже обычный пример из squares.c работает неплохо. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
nagoHok 4 Жалоба Опубликовано July 15, 2011 даже обычный пример из squares.c работает неплохо. работает то неплохо, но далек от реального времени. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
nagoHok 4 Жалоба Опубликовано July 19, 2011 так тут походу разбора полетов возник вопрос интенсивность яркости у нас от 0 до 255, значения IplImage::imageData у нас char т.е. от -127 до 128, правильно ли будет для получения функции приобразовывать char к unsigned char? или это надуманно? Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано July 19, 2011 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 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах