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

Чтение маркировки шестерни

Recommended Posts

Здравствуйте. Подскажите с решением следующей задачи:

Есть изображение шестерни с набитым номером. 5d986c08ef3et.jpg

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

Поанирую двигаться в следующем направлении, но т.к. новичок в OpenCV - много не знаю, но хочу узнать :).

Итак шаги:

1.Определение положения шестерни на кадре

1.1 Медианный фильтр

1.2 Бинаризация изображения

1.3 ...выделение части окружности на которой надпись/поиск связных компонент/

2. ...дальше пока не думал...

Прошу помощи(желательно с примерами, названиями функций и т.п.) в решении. Для начала п.1 /или если у вас другое решение, прошу поделитесь/.

Заранее спасибо

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


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

Есть инструкция как реализовать, но описание в нем, к сожалению, представлено в виде картинок и текста. Функции не описаны.

2.ОПРЕДЕЛЕНИЕ ПОЛОЖЕНИЯ ШЕСТЕРНИ

Целью данного этапа является определение размеров (радиусов) и положения (центров) большого и малого круга, которые ограничивают область нанесения маркировки.

2.1.

Определение положения шестерни

7f2f3760e3b4t.jpg

Рис.1. Исходное изображение

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

Для уменьшения шума перед бинаризацией применим к изображению медианный фильтр.

72343752f797t.jpg

Рис.2. Применение медианного фильтра

c1732a8753a1t.jpg

Рис.3. Бинаризация изображения

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

ac76ff3e8a29t.jpg

Рис.4.Поиск связных компонент

347ab9104b60t.jpg

Рис.5.Определение центра и радиуса окружностей

Хотелось бы реализовать это для начала...

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


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

У меня пример по связным компонентам лежит здесь:

c:\OpenCV-2.2.0\samples\cpp\connected_components.cpp

и при пороге 132 выдает такой результат:

post-1-0-78431900-1292527180_thumb.jpg

По поводу фильтра, думаю тут лучше всего поэкспериментировать с open/close или erode/dilate

post-1-0-15754000-1292527613_thumb.jpg

post-1-0-14594800-1292527621_thumb.jpg

Лежит здесь:

c:\OpenCV-2.2.0\samples\c\morphology.c

Дальше найдете окружности cvHoughCircle. Узнаете центры и радиусы.

Затем cvRemap - ом развернете кольцо в полосу.

  • Like 1

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


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

Всё просто - пять минут и готово:

int main()

{

	IplImage *img = cvLoadImage("d:\\5d986c08ef3e.jpg");


	IplImage *bin_img = cvCreateImage(cvGetSize(img), 8, 1);

	cvCvtColor(img, bin_img, CV_RGB2GRAY);


	cvThreshold(bin_img, bin_img, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);


	cvErode(bin_img, bin_img, NULL, 1);

	cvDilate(bin_img, bin_img, NULL, 5);

	cvErode(bin_img, bin_img, NULL, 4);


	CvMemStorage *storage = cvCreateMemStorage(0);

	CvContourScanner traverse = cvStartFindContours(bin_img, storage, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_NONE);


	CvSeq *mContour = 0;

	for (CvSeq *contour = cvFindNextContour(traverse); contour; contour = cvFindNextContour(traverse))

	{

		CvBox2D box = cvFitEllipse2(contour);

		CvPoint center = cvPointFrom32f(box.center);

		CvSize size = cvSize(cvRound(box.size.width*0.5), cvRound(box.size.height*0.5));

		cvEllipse(img, center, size, -box.angle, 0, 360, CV_RGB(0,0,255), 1, CV_AA, 0);

	}


	cvEndFindContours(&traverse);

	cvReleaseMemStorage(&storage);


	cvShowImage("1", img);

	cvShowImage("2", bin_img);


	for (;

	{

		if (cvWaitKey(10) > 0)

			break;

	}


	cvReleaseImage(&bin_img);

	cvReleaseImage(&img);


	return 0;

}[/code]

  • Like 2

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


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

Огромное спасибо за помощь. Но при компиляции ругается на строку

CvMemStorage *storage = cvCreateMemStorage(0);

и др.строки после нее

error C2275: CvMemStorage: недопустимое использование этого типа в качестве выражения

error C2065: storage: необъявленный идентификатор

Подскажите, как победить эту проблему.

MSVS2008/OpenCV2.1

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


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

Инклуды необходимые подключи.

  • Like 1

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


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

Инклуды необходимые подключи.

***

П.С. Все заработало. Оказалось, нужно было в настройках студии поставить галку, чтобы компилировалось как код C++

Изменено пользователем Fresh

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


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

Все отлично работает. Получил вот такой результат:

90a768fe0600t.jpg

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

Заранее спасибо.

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


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

Гм. Ты меня удивляешь. А это что: CvPoint center = cvPointFrom32f(box.center);

?

  • Like 1

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


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

упс. точно. извиняюсь, за невнимательность/т.к. только учусь/.

Дальше прошу помощи в следующем:

1.отсечь не нужную часть изображения.

bdefb7bf1a32t.jpg

2.резвернуть изображение относительно центра

5342bf337ee8t.jpg

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


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

Отсечь легко:

1. создаёшь изображение необходимого размера;

2. делаешь SetImageROI к основному изображению;

3. копируешь основное в новое;

4. ResetImageROI к основному изображению.

По разворачиванию Smorodov уже приводил функцию.

  • Like 1

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


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

Отсечь легко:

1. создаёшь изображение необходимого размера;

2. делаешь SetImageROI к основному изображению;

3. копируешь основное в новое;

4. ResetImageROI к основному изображению.

Ширина и высота изображения только с шестеренкой, которое нужно для дальнейших преобразований, равно 2*R = d.

//Тогда ширина и высота результирующего изображения для развернутого варианта будут равны 2*пи*R

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


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

Ширина и высота изображения только с шестеренкой, которое нужно для дальнейших преобразований, равно 2*R = d.

//Тогда ширина и высота результирующего изображения для развернутого варианта будут равны 2*пи*R

с cvRemap , скорее всего будет не так. Высота - ширина кольца, а длина зависит от шага преобразования (это угол 0-360 умноженный на кол-во шагов на градус (радиан)).

ЗЫ:

То, что я увидел у Вас на картинке, это результат преобразования прямоугольных координат в полярные, в opencv есть стандартный пример: C:\OpenCV2.1\samples\c\polar_transforms.c.

  • Like 1

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


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

        CvSeq *mContour = 0;

        for (CvSeq *contour = cvFindNextContour(traverse); contour; contour = cvFindNextContour(traverse))

        {

                CvBox2D box = cvFitEllipse2(contour);

                CvPoint center = cvPointFrom32f(box.center);

                CvSize size = cvSize(cvRound(box.size.width*0.5), cvRound(box.size.height*0.5));

                cvEllipse(img, center, size, -box.angle, 0, 360, CV_RGB(0,0,255), 1, CV_AA, 0);

        }

Подскажите, как после выполнения вышеприведенного кода залить все, что не попадает между двумя контурами, черным цветом.

т.е. и снаружи и внутри кольца залить черным цветом /само кольцо не заливать/

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


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

1. Можно сделать изображение-маску: закрасить его чёрным цветом, нарисовать белый круг большего диаметра, нарисовать чёрный круг меньшего диаметра. И сделать логическое сложение твоего изображения и маски.

2. Можно попиксельно пройти по твоему изображению, проверяя попадание пикселей в кольцо.

  • Like 1

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


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

можно подробнее про первый способ.

/хотя бы названия функций для логического сложения и др./

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


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

"Можно сделать изображение-маску" - mask = cvCreateImage

"закрасить его чёрным цветом" - cvSet(img, cvScalar(0, 0, 0))

"нарисовать белый круг большего диаметра" - cvCircle + cvFloodFill

"нарисовать чёрный круг меньшего диаметра" - cvCircle + cvFloodFill

"сделать логическое сложение твоего изображения и маски" - cvAnd(img, mask, mask)

mask - как раз должен быть искомым изображением. Писал на глаз, но работать должно.

  • Like 1

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


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

Nuzhny, спасибо большое. Все работает.

Тут дальше очередной затык.

Получил картинку:

01e4c2dfaeaft.jpg

Черный квадрат с нужной мне полоской.

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

т.е. нужно выделить область интересов ROI и перенести в новый Img

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


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

Надо экспериментировать: адаптивную бинаризацию, а после контуры. Или построить гистограмму по столбцам и посмотреть будут ли у неё провалы в области символов. Что-нибудь ещё.

Ответа я не знаю.

  • Like 1

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


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

Задача очень похожа на чтение CAPCHA, можно погуглить с этой стороны.

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


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

Задача очень похожа на чтение CAPCHA, можно погуглить с этой стороны.

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


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

Сначала нужно просто вырезать полоску, а потом разбить по символам.

Или построить гистограмму по столбцам и посмотреть будут ли у неё провалы в области символов

Можно подробнее /с примером, желательно/.

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


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

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

Гистограмма яркости по столбцам:

1. создаёшь массив целых чисел шириной, равной ширине изображения, каждый элемент массива - сумма яркостей в соответствующем столбце;

2. в цикле проходишь по строкам изображения и суммируешь значения.

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

Это всё мождет сработать, но пример привести не могу - времени совсем нет.

  • Like 1

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


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

Гистограмма яркости по столбцам:

1. создаёшь массив целых чисел шириной, равной ширине изображения, каждый элемент массива - сумма яркостей в соответствующем столбце;

2. в цикле проходишь по строкам изображения и суммируешь значения.


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

Это всё мождет сработать, но пример привести не могу - времени совсем нет. 

Большое спасибо, пригодится/уже разобрался, почти :)/.

Изображение вырезал.

Подскажите команду для попиксельного вычитания одно изображения из другого /нужно отделить изображение от фона/.

кроме cvSub есть что-нибудь?

...и еще вопросик. Как можно избавится от небольших белых областей на ч/б изображении. cvErode? 64fad8a3d9c7t.jpg

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


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

По поводу вычитания, у Вас вроде бинарное изображение, так почему бы не применить логические функции, например "исключающее или"?

Что касается фильтрации мелких фрагментов, тут можно либо cvErode+cvDilate, либо cvSmooth + cvThreshold, или просто найти контуры, и отфильтровать по площади.

  • Like 1

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


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

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

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

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

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

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

Войти

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

Войти сейчас


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

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

×