Fresh 0 Жалоба Опубликовано December 16, 2010 Здравствуйте. Подскажите с решением следующей задачи: Есть изображение шестерни с набитым номером. Необходимо перевести набитый номер из декартовой системы координат в логарифмически-полярную (т.е. из надписи написанной по окружности, необходимо сделать надпись написанную слева на право, т.е. в строку)+...остальное потом Поанирую двигаться в следующем направлении, но т.к. новичок в OpenCV - много не знаю, но хочу узнать . Итак шаги: 1.Определение положения шестерни на кадре 1.1 Медианный фильтр 1.2 Бинаризация изображения 1.3 ...выделение части окружности на которой надпись/поиск связных компонент/ 2. ...дальше пока не думал... Прошу помощи(желательно с примерами, названиями функций и т.п.) в решении. Для начала п.1 /или если у вас другое решение, прошу поделитесь/. Заранее спасибо Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Fresh 0 Жалоба Опубликовано December 16, 2010 Есть инструкция как реализовать, но описание в нем, к сожалению, представлено в виде картинок и текста. Функции не описаны. 2.ОПРЕДЕЛЕНИЕ ПОЛОЖЕНИЯ ШЕСТЕРНИ Целью данного этапа является определение размеров (радиусов) и положения (центров) большого и малого круга, которые ограничивают область нанесения маркировки. 2.1. Определение положения шестерни Рис.1. Исходное изображение Заметим, что шестеренка (поверхность с маркировкой) гораздо светлее, чем область за ее пределами. Поэтому для определения ее положения целесообразно использовать бинаризацию с глобальным порогом, значение которого выше среднего значения яркости по изображению. Для уменьшения шума перед бинаризацией применим к изображению медианный фильтр. Рис.2. Применение медианного фильтра Рис.3. Бинаризация изображения Для определения параметров большого и малого круга, ограничивающего шестеренку, выделим связные компоненты и выберем из них две: максимальную светлую компоненту, она задает большой круг и внутри нее максимальную темную компоненту – она задает внутренний круг. Рис.4.Поиск связных компонент Рис.5.Определение центра и радиуса окружностей Хотелось бы реализовать это для начала... Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано December 16, 2010 У меня пример по связным компонентам лежит здесь: c:\OpenCV-2.2.0\samples\cpp\connected_components.cpp и при пороге 132 выдает такой результат: По поводу фильтра, думаю тут лучше всего поэкспериментировать с open/close или erode/dilate Лежит здесь: c:\OpenCV-2.2.0\samples\c\morphology.c Дальше найдете окружности cvHoughCircle. Узнаете центры и радиусы. Затем cvRemap - ом развернете кольцо в полосу. 1 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Nuzhny 243 Жалоба Опубликовано December 16, 2010 Всё просто - пять минут и готово: 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] 2 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Fresh 0 Жалоба Опубликовано December 17, 2010 Огромное спасибо за помощь. Но при компиляции ругается на строку CvMemStorage *storage = cvCreateMemStorage(0); и др.строки после нее error C2275: CvMemStorage: недопустимое использование этого типа в качестве выражения error C2065: storage: необъявленный идентификатор Подскажите, как победить эту проблему. MSVS2008/OpenCV2.1 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Nuzhny 243 Жалоба Опубликовано December 17, 2010 Инклуды необходимые подключи. 1 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Fresh 0 Жалоба Опубликовано December 17, 2010 (изменено) Инклуды необходимые подключи. *** П.С. Все заработало. Оказалось, нужно было в настройках студии поставить галку, чтобы компилировалось как код C++ Изменено December 17, 2010 пользователем Fresh Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Fresh 0 Жалоба Опубликовано December 17, 2010 Все отлично работает. Получил вот такой результат: Как бы теперь определить где центр этого выделения и каким образом развернуть относительно этого центра? Заранее спасибо. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Nuzhny 243 Жалоба Опубликовано December 17, 2010 Гм. Ты меня удивляешь. А это что: CvPoint center = cvPointFrom32f(box.center); ? 1 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Fresh 0 Жалоба Опубликовано December 17, 2010 упс. точно. извиняюсь, за невнимательность/т.к. только учусь/. Дальше прошу помощи в следующем: 1.отсечь не нужную часть изображения. 2.резвернуть изображение относительно центра Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Nuzhny 243 Жалоба Опубликовано December 17, 2010 Отсечь легко: 1. создаёшь изображение необходимого размера; 2. делаешь SetImageROI к основному изображению; 3. копируешь основное в новое; 4. ResetImageROI к основному изображению. По разворачиванию Smorodov уже приводил функцию. 1 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Fresh 0 Жалоба Опубликовано December 17, 2010 Отсечь легко: 1. создаёшь изображение необходимого размера; 2. делаешь SetImageROI к основному изображению; 3. копируешь основное в новое; 4. ResetImageROI к основному изображению. Ширина и высота изображения только с шестеренкой, которое нужно для дальнейших преобразований, равно 2*R = d. //Тогда ширина и высота результирующего изображения для развернутого варианта будут равны 2*пи*R Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано December 17, 2010 Ширина и высота изображения только с шестеренкой, которое нужно для дальнейших преобразований, равно 2*R = d. //Тогда ширина и высота результирующего изображения для развернутого варианта будут равны 2*пи*R с cvRemap , скорее всего будет не так. Высота - ширина кольца, а длина зависит от шага преобразования (это угол 0-360 умноженный на кол-во шагов на градус (радиан)). ЗЫ: То, что я увидел у Вас на картинке, это результат преобразования прямоугольных координат в полярные, в opencv есть стандартный пример: C:\OpenCV2.1\samples\c\polar_transforms.c. 1 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Fresh 0 Жалоба Опубликовано January 11, 2011 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); } Подскажите, как после выполнения вышеприведенного кода залить все, что не попадает между двумя контурами, черным цветом. т.е. и снаружи и внутри кольца залить черным цветом /само кольцо не заливать/ Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Nuzhny 243 Жалоба Опубликовано January 11, 2011 1. Можно сделать изображение-маску: закрасить его чёрным цветом, нарисовать белый круг большего диаметра, нарисовать чёрный круг меньшего диаметра. И сделать логическое сложение твоего изображения и маски. 2. Можно попиксельно пройти по твоему изображению, проверяя попадание пикселей в кольцо. 1 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Fresh 0 Жалоба Опубликовано January 11, 2011 можно подробнее про первый способ. /хотя бы названия функций для логического сложения и др./ Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Nuzhny 243 Жалоба Опубликовано January 11, 2011 "Можно сделать изображение-маску" - mask = cvCreateImage "закрасить его чёрным цветом" - cvSet(img, cvScalar(0, 0, 0)) "нарисовать белый круг большего диаметра" - cvCircle + cvFloodFill "нарисовать чёрный круг меньшего диаметра" - cvCircle + cvFloodFill "сделать логическое сложение твоего изображения и маски" - cvAnd(img, mask, mask) mask - как раз должен быть искомым изображением. Писал на глаз, но работать должно. 1 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Fresh 0 Жалоба Опубликовано January 12, 2011 Nuzhny, спасибо большое. Все работает. Тут дальше очередной затык. Получил картинку: Черный квадрат с нужной мне полоской. Каким образом можно отсечь ненужное /выделить полоску с цифрами/? т.е. нужно выделить область интересов ROI и перенести в новый Img Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Nuzhny 243 Жалоба Опубликовано January 12, 2011 Надо экспериментировать: адаптивную бинаризацию, а после контуры. Или построить гистограмму по столбцам и посмотреть будут ли у неё провалы в области символов. Что-нибудь ещё. Ответа я не знаю. 1 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано January 12, 2011 Задача очень похожа на чтение CAPCHA, можно погуглить с этой стороны. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано January 12, 2011 Задача очень похожа на чтение CAPCHA, можно погуглить с этой стороны. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Fresh 0 Жалоба Опубликовано January 13, 2011 Сначала нужно просто вырезать полоску, а потом разбить по символам. Или построить гистограмму по столбцам и посмотреть будут ли у неё провалы в области символов Можно подробнее /с примером, желательно/. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Nuzhny 243 Жалоба Опубликовано January 13, 2011 Я думаю, что вырезать полоску не проблема. Гистограмма яркости по столбцам: 1. создаёшь массив целых чисел шириной, равной ширине изображения, каждый элемент массива - сумма яркостей в соответствующем столбце; 2. в цикле проходишь по строкам изображения и суммируешь значения. В результате получится некоторая плавная волнистая кривая с небольшими резкими проседаниями в области нахождения символов. Если такие проседания встречаются на небольшом расстоянии друг от друга, то это область с символами. Это всё мождет сработать, но пример привести не могу - времени совсем нет. 1 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Fresh 0 Жалоба Опубликовано January 13, 2011 Гистограмма яркости по столбцам: 1. создаёшь массив целых чисел шириной, равной ширине изображения, каждый элемент массива - сумма яркостей в соответствующем столбце; 2. в цикле проходишь по строкам изображения и суммируешь значения. В результате получится некоторая плавная волнистая кривая с небольшими резкими проседаниями в области нахождения символов. Если такие проседания встречаются на небольшом расстоянии друг от друга, то это область с символами. Это всё мождет сработать, но пример привести не могу - времени совсем нет. Большое спасибо, пригодится/уже разобрался, почти :)/. Изображение вырезал. Подскажите команду для попиксельного вычитания одно изображения из другого /нужно отделить изображение от фона/. кроме cvSub есть что-нибудь? ...и еще вопросик. Как можно избавится от небольших белых областей на ч/б изображении. cvErode? Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано January 13, 2011 По поводу вычитания, у Вас вроде бинарное изображение, так почему бы не применить логические функции, например "исключающее или"? Что касается фильтрации мелких фрагментов, тут можно либо cvErode+cvDilate, либо cvSmooth + cvThreshold, или просто найти контуры, и отфильтровать по площади. 1 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах