nagoHok 4 Report post Posted July 13, 2011 оп, необновил страничку помоему Smorodov как раз на это ссылку дал. Share this post Link to post Share on other sites
nagoHok 4 Report post Posted 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; } Share this post Link to post Share on other sites
Smorodov 578 Report post Posted 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] вот это надо сглаживать и брать производную. Share this post Link to post Share on other sites
nagoHok 4 Report post Posted July 13, 2011 вот это надо сглаживать и брать производную. Спасибо большое! Share this post Link to post Share on other sites
nagoHok 4 Report post Posted July 13, 2011 Так если я правильно понял то float x - это позиция пикселя? тогда скажем для конечнего пикселя к примеру 640-го будет произведено 638 итераций? Share this post Link to post Share on other sites
mrgloom 242 Report post Posted July 13, 2011 Добавил сглаживание, не скажу что уж очень сгладилось но больших пиков уже нет так вроде так и должно быть должны сгладятся маленькие неровности, а большие пики должны остаться. хотя вот интересно какой результат производной будет без сглаживания. Так если я правильно понял то 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
Smorodov 578 Report post Posted July 13, 2011 -2 не разбирался, как в документе было так и написал. Вычислительные затраты, естественно можно сильно сократить, прогнав f(x) только для конечного пикселя, и занося результат каждой итерации в выходной массив. Это я просто формулу из документа один в один привел. Share this post Link to post Share on other sites
nagoHok 4 Report post Posted 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; } Share this post Link to post Share on other sites
nagoHok 4 Report post Posted 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); } } правда получается сплошная линия, толи я опять что то не так сделал, толи флрмула производной не та. Share this post Link to post Share on other sites
mrgloom 242 Report post Posted July 14, 2011 Поясните пжл, что в данном случае 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
nagoHok 4 Report post Posted July 14, 2011 ну вот вы получили функцию 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
mrgloom 242 Report post Posted July 14, 2011 значит ошибка где то в коде, т.к. график у вас получился правильный и там видно, что 2 участка где ф-ия почти не возрастает (по бокам), и "лесенка" (в середине). попробуйте еще шаг поменять, т.е. шаг =step то, y2=F(i+step) y1=F(i) и x2-x1=step, хотя не думаю, что это поможет. по большому счету вы уже сейчас можете определить границы таблички. взять какой то отступ(в % или константой), и пройтись от начала т.е. до точки 0+отступ (это будет начало таблички) и от конца до точки конец-отступ (это будет конец таблички). вообще метод кажется не особо надежным, обычно делают детектор движения(определяют движущийся объект-машину)+ Канни(или что то похожее) + поиск прямоугольника(таблички). Share this post Link to post Share on other sites
nagoHok 4 Report post Posted July 14, 2011 значит ошибка где то в коде, т.к. график у вас получился правильный и там видно, что 2 участка где ф-ия почти не возрастает (по бокам), и "лесенка" (в середине). попробуйте еще шаг поменять, т.е. шаг =step то, y2=F(i+step) y1=F(i) и x2-x1=step, хотя не думаю, что это поможет. по большому счету вы уже сейчас можете определить границы таблички. взять какой то отступ(в % или константой), и пройтись от начала т.е. до точки 0+отступ (это будет начало таблички) и от конца до точки конец-отступ (это будет конец таблички). вообще метод кажется не особо надежным, обычно делают детектор движения(определяют движущийся объект-машину)+ Канни(или что то похожее) + поиск прямоугольника(таблички). да сейчас как раз эксперементирую, на счет надежности метода - это часть алгоритма локализации таблички, конечноже она будет будет работать совместно с детектором движения, хотя пока не стоит забегать в перед. Share this post Link to post Share on other sites
Smorodov 578 Report post Posted July 14, 2011 Значения функции и её производной, в данном случае лучше считать в действительных числах (float), т.к. оно действительно получается небольшим. Производную лучше брать на участке хотя-бы 10 пикселей длинной тогда она получится точнее (до 0.1). Слишком большие длины приведут к потере точности локализации номера. Так что выбирайте оптимум. ЗЫ: Это все равно что сначала сгладить функцию, а потом искать производную. Share this post Link to post Share on other sites
nagoHok 4 Report post Posted 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); } } да сейчас придется поработать над сглаживанием Share this post Link to post Share on other sites
Smorodov 578 Report post Posted July 14, 2011 Только int-ы на float или double поменяйте, иначе ничего гладкого не получится. С целочисленной арифметикой надо очень аккуратно работать иначе очень долго можно потом ошибку искать. Share this post Link to post Share on other sites
nagoHok 4 Report post Posted July 14, 2011 Только int-ы на float или double поменяйте, иначе ничего гладкого не получится. С целочисленной арифметикой надо очень аккуратно работать иначе очень долго можно потом ошибку искать. Вот результат того же алгоритма но с вещественными значениями, имхо с интами было лучше) ЗЫ вывод надо менять алгоритм сглаживания. Share this post Link to post Share on other sites
Smorodov 578 Report post Posted July 14, 2011 А 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
nagoHok 4 Report post Posted July 14, 2011 ЗЫ: 5 точек, маловато, я думаю надо примерно от четверти до половины номера в длину брать. так а как определить длинну номера тогда? К томуже если при движение размеры плитки будут меняться? Share this post Link to post Share on other sites
Smorodov 578 Report post Posted July 14, 2011 Вероятно нужно принять минимальные и максимальные возможные размеры номера и проводить несколько проверок с разными параметрами фильтра. А еще можно пирамиду сделать и по ней искать. Share this post Link to post Share on other sites
mrgloom 242 Report post Posted July 14, 2011 так а как определить длинну номера тогда? на графике производной где первый сильный скачок там начало номера, где последний конец номера. К томуже если при движение размеры плитки будут меняться? более того такой же график(но скорее с менее ярковыраженными пиками будет выскакивать и на фарах автомобиля). Share this post Link to post Share on other sites
mrgloom 242 Report post Posted July 15, 2011 даже обычный пример из squares.c работает неплохо. Share this post Link to post Share on other sites
nagoHok 4 Report post Posted July 15, 2011 даже обычный пример из squares.c работает неплохо. работает то неплохо, но далек от реального времени. Share this post Link to post Share on other sites
nagoHok 4 Report post Posted July 19, 2011 так тут походу разбора полетов возник вопрос интенсивность яркости у нас от 0 до 255, значения IplImage::imageData у нас char т.е. от -127 до 128, правильно ли будет для получения функции приобразовывать char к unsigned char? или это надуманно? Share this post Link to post Share on other sites
mrgloom 242 Report post Posted 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 Share this post Link to post Share on other sites