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

Измерение ширины зазора

Recommended Posts

Добрый день.

Дано: установка, предназначенная для намотки проволоки на каркас

Задача: при помощи системы компьютерного зрения необходимо контролировать ширину межвиткового зазора.

Для этого необходимо сравнение с заданной шириной, а для этого, в свою очередь необходимо измерить ширину текущую.

Зазор темный, витки светлые. Так что с точки срения выделения самого зазора наверное проблем не будет.

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

Буду благодарен за направление в нужную сторону мысли, а также любые подсказки и примеры!

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


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

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

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


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

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

Кстати, нехилая для камеры точность :). Сколько писелей/мм получается? Или микроскоп используете?

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

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


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

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

Кстати, нехилая для камеры точность :). Сколько писелей/мм получается? Или микроскоп используете?

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

:thumbsu:

Кстати, а какие функции OpenCV могут выделить светлый\темный участки и посчитать количество пикселей?

  • Like 1

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


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

Не надо точной камеры.

Бинаризируем получаем черные 0 и белые 255 точки.

дальше cvCountNonZero считаем кол-во белых.

всего точек на изображении H*W.

длины проволок в кадре и длины зазоров равны.

следовательно отношение площадей проволоки и зазора = отношению ширины проволоки к ширине зазора

сплошная статистика.

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

  • Like 1

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


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

Не надо точной камеры.

Бинаризируем получаем черные 0 и белые 255 точки.

дальше cvCountNonZero считаем кол-во белых.

всего точек на изображении H*W.

длины проволок в кадре и длины зазоров равны.

следовательно отношение площадей проволоки и зазора = отношению ширины проволоки к ширине зазора

сплошная статистика.

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

Хороший алгоритм! Сначала реализую на макетке (веб-камера и штатив). Потом, если все будет ОК, обязательно отпишусь о результатах. А может еще какие вопросы возникнут:) Большое спасибо за наводку!!!! ;)

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


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

Я бы вместо камеры взял бы фотоаппорат, за 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_Пиксельные_сегменты

  • Like 1

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


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

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

  • Like 1

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


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

Спасибо всем откликнувшимся за дельные советы. Теперь буду реализовывать! :thumbsu:

  • Like 1

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


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

Еще можно будет поиграться с гистограммами.

Поиск хорошего участка для обработки можно сделать так.

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

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


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

Провел эксперимент - нарисовал на листе "зебру", имитируя светлые участки и щели (в кадре оказалось 12 щелей). Щели нарисовал 0,2 мм. Расстояние между ними около 2 мм. После того как получил стоп-кадр с веб-камеры, обработал фильтром median (убрал шумы по краям) и преобразовал в .bmp. Открыл в Paint и посмотрел ширину такой нарисованной щели в пикселя. Оказалось, при разрешении 640х480 - 0,2 мм это 5 пикселей. Т.е. минимальная ширина щели, фиксируемая данной камерой составит 0,2/5=0,04 мм. Это как раз тот минимальный размер, который мне необходимо фиксировать. Так что и 640х480 для такой задачи (работа с макетом в домашних условиях) уже достаточно, а для завода можно использовать камеру 1 - 2 Мpx, это позволит получить еще большую точность!!!

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


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

Не надо точной камеры.

Бинаризируем получаем черные 0 и белые 255 точки.

дальше cvCountNonZero считаем кол-во белых.

всего точек на изображении H*W.

длины проволок в кадре и длины зазоров равны.

следовательно отношение площадей проволоки и зазора = отношению ширины проволоки к ширине зазора

сплошная статистика.

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

Посидел, подумал, посчитал и пришел к выводу что нормальной точности при таком подходе не добъешься, т.к. при этом получается, что (Sb/Sw)*bc = a1+a2+...an, где Sb - площадь черных пикселей, Sw - площадь белых пикселей, b - длина участков с белыми и черными пикселями, с - ширина зон с белыми пикселями. Таким образом мы можем точно найти только сумму ширин всех черных участков в исследуемой области и даже минимально уменьшив исследуемую область, а так-же приняв ширины близлежащих черных областей почти одинаковыми (что даст нам среднюю ширину, если в верхнем выражении примем a1=a2=...=an и поделим его на n, да кстати n тоже еще нужно найти) программа не застрахована от того, что в исследуемую область попадет например одна целая черная область и одна не целая.

:rolleyes:

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


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

я люблю статистику :)

такой код на мысли не наводит?


...
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/

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


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

я люблю статистику :)

такой код на мысли не наводит?


...

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 пунктов постом выше:).

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


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

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

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


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

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

Буду думать.:) О результатах отпишусь!

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


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

Решил применить 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 не хочет отображаться на панели? И как это поправить? Заранее благодарен!

post-1271-0-02412400-1326044196_thumb.jp

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


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

Скопировать ROI в отдельное изображение и нарисовать.

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


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

Скопировать 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

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


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

cvGetSize(roi) - помнится в билдере не работало, задайте ширину и высоту изображения по отдельности.

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


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

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) прекрасно работает

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


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

ну так считывается трехканальное , а копируете в одноканальное...


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.

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


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

ну так считывается трехканальное , а копируете в одноканальное...


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);


Результат тот-же:(

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


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

Падает на строке cvShowImage? Не у верен, что оно вообще будет работать с vcl'ной модификацией очереди сообщений.

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


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

Падает на строке cvShowImage? Не у верен, что оно вообще будет работать с vcl'ной модификацией очереди сообщений.

Прекрасно работает если я не копирую картинку, а работаю с исходной, а вот после того как создаю новую и копирую в неё, то вот новая не выводится...

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


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

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

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

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

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

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

Войти

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

Войти сейчас


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

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

×