L@MER 6 Жалоба Опубликовано January 7, 2012 Добрый день. Дано: установка, предназначенная для намотки проволоки на каркас Задача: при помощи системы компьютерного зрения необходимо контролировать ширину межвиткового зазора. Для этого необходимо сравнение с заданной шириной, а для этого, в свою очередь необходимо измерить ширину текущую. Зазор темный, витки светлые. Так что с точки срения выделения самого зазора наверное проблем не будет. Вопросов два: как при помощи OpenCV выделить зазор и как измерить его ширину? Буду благодарен за направление в нужную сторону мысли, а также любые подсказки и примеры! Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано January 7, 2012 Неплохо бы изображение увидеть, а пока можно посоветовать измерять площадь темного участка фиксированной длины (бинаризировать по порогу я затем cvCountNonZero) так будет точнее чем измерять ширину. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано January 7, 2012 Я имел ввиду, что камера меряет площадь. А затем программа делит площадь на известную длину, тем самым усредняя ширину прямоугольника. Для пользователя это должно быть прозрачно, то есть он работает только с шириной зазора. Кстати, нехилая для камеры точность . Сколько писелей/мм получается? Или микроскоп используете? И еще, мне пришла мысль, нужно считать отношение белых пикселей к черным, зная толщину проволоки, можно очень точно посчитать зазор. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
L@MER 6 Жалоба Опубликовано January 7, 2012 Я имел ввиду, что камера меряет площадь. А затем программа делит площадь на известную длину, тем самым усредняя ширину прямоугольника. Для пользователя это должно быть прозрачно, то есть он работает только с шириной зазора. Кстати, нехилая для камеры точность . Сколько писелей/мм получается? Или микроскоп используете? И еще, мне пришла мысль, нужно считать отношение белых пикселей к черным, зная толщину проволоки, можно очень точно посчитать зазор. Кстати, а какие функции OpenCV могут выделить светлый\темный участки и посчитать количество пикселей? 1 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано January 7, 2012 Не надо точной камеры. Бинаризируем получаем черные 0 и белые 255 точки. дальше cvCountNonZero считаем кол-во белых. всего точек на изображении H*W. длины проволок в кадре и длины зазоров равны. следовательно отношение площадей проволоки и зазора = отношению ширины проволоки к ширине зазора сплошная статистика. Точность камеры, я подозреваю, сильно точности измерениям не добавит, но интересно узнать все таки результат эксперимента. 1 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
L@MER 6 Жалоба Опубликовано January 7, 2012 Не надо точной камеры. Бинаризируем получаем черные 0 и белые 255 точки. дальше cvCountNonZero считаем кол-во белых. всего точек на изображении H*W. длины проволок в кадре и длины зазоров равны. следовательно отношение площадей проволоки и зазора = отношению ширины проволоки к ширине зазора сплошная статистика. Точность камеры, я подозреваю, сильно точности измерениям не добавит, но интересно узнать все таки результат эксперимента. Хороший алгоритм! Сначала реализую на макетке (веб-камера и штатив). Потом, если все будет ОК, обязательно отпишусь о результатах. А может еще какие вопросы возникнут Большое спасибо за наводку!!!! Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Pavia00 32 Жалоба Опубликовано January 7, 2012 Я бы вместо камеры взял бы фотоаппорат, за N тысяч руб. с нормальной оптикой. И функцией съемки с компьютера. Есть камеры с функцией фотосъёмки(бывают потделки, которые просто программно интерполируют картинку). Камера работает в потоковом режиме это значит что оно постоянно делает много снимков. Пока в вашей постановки это не требуется. А вот канал передачи данных камера-компьютер имеет ограничения поэтому 1МПиксель на 10 кадров имеем 100 Мбит/с, а то и все 300 МБит/с. В виду этого ограничения камер с разрешением более FullHD (1920х1080)не встретить. А ещё разработчики видео камер любят сжимается видео прямо на камере и уже потом передавать потребителю. Сжатие может привести к потере разрешающей способности до 8 раз по горизонтали и 8 по вертикали. Фотоаапорат не требует большого числа кадров, поэму его разрешающая способность раз в 10 больше. В кадре должно помещаться от 10-30 щелей. Объект должен занимать 30-90% ширины кадра. Щель должна занимать не менее 20 пикселей. Такая обработка требует около 1000 пикселей по ширене. Точность измерений определяется количеством пикселей и не чем иным. Усреднение конечно улучшает результат измерения. Но сильно полагаться на него не стоит. Ошибка 0.05мм/5мм=0.01 другими словами щель должна быть 1/0.01=100 пикселей 1 пиксель на фото должен соответствовать 0.05 мм. С такими размерами над оптикой надо подумать либо отказаться вовсе от неё. Кстати, а какие функции OpenCV могут выделить светлый\темный участки и посчитать количество пикселей? Пожалуй это самое трудное. Выделить можно по порогу, либо воспользоваться адаптивной бинаризацией. Еще можно будет поиграться с гистограммами. Поиск хорошего участка для обработки можно сделать так. Выбираешь случайные линии и оцениваешь наличие периодической структуры. Подсчёт пикселей можно сделать ручками. http://locv.ru/wiki/3.6_Доступ_к_данным_изображения http://locv.ru/wiki/9.1.3_Пиксельные_сегменты 1 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Pavia00 32 Жалоба Опубликовано January 7, 2012 Сначала реализую на макетке (веб-камера и штатив). С вашими размерами не плохо превратить камеру в микроскоп. Если веб-камера с ручным фокусом то линза аккуратно свинчивается разворачивается тыльной стороной и крепится скотчем. 1 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
L@MER 6 Жалоба Опубликовано January 7, 2012 Спасибо всем откликнувшимся за дельные советы. Теперь буду реализовывать! 1 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
L@MER 6 Жалоба Опубликовано January 7, 2012 Еще можно будет поиграться с гистограммами. Поиск хорошего участка для обработки можно сделать так. Кстати да, у меня уже есть готовая программа на OpenCV, которая сравнивает гистограммы эталонного и текущего изображений, выдавая результат в процентах. Может получится сюда прикрутить. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
L@MER 6 Жалоба Опубликовано January 7, 2012 Провел эксперимент - нарисовал на листе "зебру", имитируя светлые участки и щели (в кадре оказалось 12 щелей). Щели нарисовал 0,2 мм. Расстояние между ними около 2 мм. После того как получил стоп-кадр с веб-камеры, обработал фильтром median (убрал шумы по краям) и преобразовал в .bmp. Открыл в Paint и посмотрел ширину такой нарисованной щели в пикселя. Оказалось, при разрешении 640х480 - 0,2 мм это 5 пикселей. Т.е. минимальная ширина щели, фиксируемая данной камерой составит 0,2/5=0,04 мм. Это как раз тот минимальный размер, который мне необходимо фиксировать. Так что и 640х480 для такой задачи (работа с макетом в домашних условиях) уже достаточно, а для завода можно использовать камеру 1 - 2 Мpx, это позволит получить еще большую точность!!! Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
L@MER 6 Жалоба Опубликовано January 7, 2012 Не надо точной камеры. Бинаризируем получаем черные 0 и белые 255 точки. дальше cvCountNonZero считаем кол-во белых. всего точек на изображении H*W. длины проволок в кадре и длины зазоров равны. следовательно отношение площадей проволоки и зазора = отношению ширины проволоки к ширине зазора сплошная статистика. Точность камеры, я подозреваю, сильно точности измерениям не добавит, но интересно узнать все таки результат эксперимента. Посидел, подумал, посчитал и пришел к выводу что нормальной точности при таком подходе не добъешься, т.к. при этом получается, что (Sb/Sw)*bc = a1+a2+...an, где Sb - площадь черных пикселей, Sw - площадь белых пикселей, b - длина участков с белыми и черными пикселями, с - ширина зон с белыми пикселями. Таким образом мы можем точно найти только сумму ширин всех черных участков в исследуемой области и даже минимально уменьшив исследуемую область, а так-же приняв ширины близлежащих черных областей почти одинаковыми (что даст нам среднюю ширину, если в верхнем выражении примем a1=a2=...=an и поделим его на n, да кстати n тоже еще нужно найти) программа не застрахована от того, что в исследуемую область попадет например одна целая черная область и одна не целая. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано January 7, 2012 я люблю статистику такой код на мысли не наводит? ... CvMat MV,MH; double *VertSumS; double *HorSumS; VertSumS=new double[r->height]; HorSumS=new double[r->width]; cvInitMatHeader( &MV,r->height,1, CV_64FC1, VertSumS ); cvInitMatHeader( &MH,1,r->width,CV_64FC1, HorSumS ); cvReduce(gray, &MV,1,CV_REDUCE_AVG); // Среднее по строкам cvReduce(gray, &MH,0,CV_REDUCE_AVG); // Среднее по столбцам ... [/code] И вот тут картинки: http://www.dmi.unict.it/farinella/PUBLICATIONS/FurtherInformationMicroIPLAB/ Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
L@MER 6 Жалоба Опубликовано January 7, 2012 я люблю статистику такой код на мысли не наводит? ... CvMat MV,MH; double *VertSumS; double *HorSumS; VertSumS=new double[r->height]; HorSumS=new double[r->width]; cvInitMatHeader( &MV,r->height,1, CV_64FC1, VertSumS ); cvInitMatHeader( &MH,1,r->width,CV_64FC1, HorSumS ); cvReduce(gray, &MV,1,CV_REDUCE_AVG); // Среднее по строкам cvReduce(gray, &MH,0,CV_REDUCE_AVG); // Среднее по столбцам ... И вот тут картинки: http://www.dmi.unict.it/farinella/PUBLICATIONS/FurtherInformationMicroIPLAB/ Это понятно - задаем матрицу, находим среднее. Только как результат - опять усредненное значение. Никак не соображу как это применимо в данном конкретном случае, когда хочется получить точное, а не усредненное значение ширины щели? Единственное, что придумалось, это 9 пунктов постом выше. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано January 8, 2012 Просто я исхожу из соображения, что в течение трех витков, например, параметры системы, если и будут меняться, то линейно. Если скорость вращения барабана известна, то зная среднее, и его приращение за один виток, можно, я думаю вычислить на сколько изменилась текущая ширина зазора. Считать лень, но на уровне интуиции думаю что это можно сделать как-то не сложно. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
L@MER 6 Жалоба Опубликовано January 8, 2012 Просто я исхожу из соображения, что в течение трех витков, например, параметры системы, если и будут меняться, то линейно. Если скорость вращения барабана известна, то зная среднее, и его приращение за один виток, можно, я думаю вычислить на сколько изменилась текущая ширина зазора. Считать лень, но на уровне интуиции думаю что это можно сделать как-то не сложно. Буду думать. О результатах отпишусь! Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
L@MER 6 Жалоба Опубликовано January 8, 2012 Решил применить ROI чтобы сузить исследуемую область фильтра. Написал следующий код: void __fastcall TForm_MainDemo::Button7Click(TObject *Sender) { cvNamedWindow("ROI", CV_WINDOW_AUTOSIZE); IplImage *roi = cvLoadImage("raspozn.bmp", 1); cvSetImageROI(roi, cvRect(100, 150, 100, 100)); cvShowImage("ROI", roi); cvResetImageROI(roi); } Все замечательно - из картинки вырезает участок с заданными параметрами и показывает в отдельном окне. Но мне нужно чтобы показывало в окне программы, в этом случае меняю код на следующий: void __fastcall TForm_MainDemo::Button7Click(TObject *Sender) { IplImage *roi = cvLoadImage("raspozn.bmp", 1); cvSetImageROI(roi, cvRect(100, 150, 100, 100)); APIDrawIpl(0,0,roi,Panel3->Handle); } В результате выполнения программы выдает ошибку (см.прикрепленный файл) Самое интересное, что если пишу следующий код с той же функцией вывода картинки на панель, то все прекрасно работает и просто картинка (а не её область) на Panel3 прекрасно отображается. Код следующий: void __fastcall TForm_MainDemo::Button7Click(TObject *Sender) { IplImage *roi = cvLoadImage("raspozn.bmp", 1); APIDrawIpl(0,0,roi,Panel3->Handle); } Почему ROI не хочет отображаться на панели? И как это поправить? Заранее благодарен! Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано January 8, 2012 Скопировать ROI в отдельное изображение и нарисовать. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
L@MER 6 Жалоба Опубликовано January 8, 2012 Скопировать ROI в отдельное изображение и нарисовать. Пишу следующий код: void __fastcall TForm_MainDemo::Button7Click(TObject *Sender) { cvNamedWindow("ROI", CV_WINDOW_AUTOSIZE); IplImage *roi = cvLoadImage("raspozn.bmp", 1); cvSetImageROI(roi, cvRect(100, 150, 100, 100)); IplImage *sub_roi = cvCreateImage(cvGetSize(roi),roi->depth,roi->nChannels); cvCopy(roi, sub_roi, NULL); cvShowImage("ROI", sub_roi); cvResetImageROI(roi); } В результате перестало выводиться даже в отдельном окне. Пишет ошибку: External exeption E06D7363 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано January 8, 2012 cvGetSize(roi) - помнится в билдере не работало, задайте ширину и высоту изображения по отдельности. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
L@MER 6 Жалоба Опубликовано January 8, 2012 cvGetSize(roi) - помнится в билдере не работало, задайте ширину и высоту изображения по отдельности. Сделал так: void __fastcall TForm_MainDemo::Button7Click(TObject *Sender) { cvNamedWindow("ROI", CV_WINDOW_AUTOSIZE); IplImage *roi = cvLoadImage("raspozn.bmp", 1); cvSetImageROI(roi, cvRect(100, 150, 100, 100)); IplImage *sub_roi = cvCreateImage(cvSize(640,480), 8, 1); cvCopy(roi, sub_roi, NULL); cvShowImage("ROI", sub_roi); cvResetImageROI(roi); Результат тот-же Хотя в других местах программы cvCreateImage(cvSize(640,480), 8, 1) прекрасно работает Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано January 8, 2012 ну так считывается трехканальное , а копируете в одноканальное... IplImage* cvLoadImage(const char* filename, int iscolor=CV_LOAD_IMAGE_COLOR) [/code] Parameters: filename – Name of file to be loaded. iscolor – Specific color type of the loaded image: CV_LOAD_IMAGE_COLOR the loaded image is forced to be a 3-channel color image CV_LOAD_IMAGE_GRAYSCALE the loaded image is forced to be grayscale CV_LOAD_IMAGE_UNCHANGED the loaded image will be loaded as is. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
L@MER 6 Жалоба Опубликовано January 8, 2012 ну так считывается трехканальное , а копируете в одноканальное... IplImage* cvLoadImage(const char* filename, int iscolor=CV_LOAD_IMAGE_COLOR) void __fastcall TForm_MainDemo::Button7Click(TObject *Sender) { cvNamedWindow("ROI", CV_WINDOW_AUTOSIZE); IplImage *roi = cvLoadImage("raspozn.bmp",CV_LOAD_IMAGE_COLOR); cvSetImageROI(roi, cvRect(100, 150, 100, 100)); IplImage *sub_roi = cvCreateImage(cvSize(640,480), IPL_DEPTH_8U, 3); cvCopy(roi, sub_roi,NULL); cvShowImage("ROI", sub_roi); cvResetImageROI(roi); Результат тот-же Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Nuzhny 243 Жалоба Опубликовано January 9, 2012 Падает на строке cvShowImage? Не у верен, что оно вообще будет работать с vcl'ной модификацией очереди сообщений. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
L@MER 6 Жалоба Опубликовано January 9, 2012 Падает на строке cvShowImage? Не у верен, что оно вообще будет работать с vcl'ной модификацией очереди сообщений. Прекрасно работает если я не копирую картинку, а работаю с исходной, а вот после того как создаю новую и копирую в неё, то вот новая не выводится... Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах