Smorodov 579 Жалоба Опубликовано February 14, 2013 Без кода сказать ничего не могу. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Alexer 0 Жалоба Опубликовано February 18, 2013 Мне пришлось переписать данный код на C# ввиду требования руководителя. Вот именно на C# у меня вывело ContourArea = -4. if(Math.Abs(Cv.ContourArea(contours))>20) { Contour.DrawContours(contours, CvColor.White, CvColor.White, 2, Cv.FILLED, LineType.Link8); Console.WriteLine(cv.ContourArea(contours); } Но в данной ситуации рисуются все контуры абсолютно(включая маленькие). Может нужно как-то посчитать площадь каждого контура, чтобы потом отсеять? А на C код у меня выглядел вот так, но он рушится на условии if(abs(cvContourArea(storage))>20). #include "stdafx.h" #include <stdio.h> #include <stdlib.h> #include <cv.h> #include <highgui.h> int main(int argc, char* argv[]) { //Создаём 3 изображения IplImage* sign = cvLoadImage("D:\\1.jpg",3); IplImage* sign_hsv=cvCreateImage(cvGetSize(sign),IPL_DEPTH_8U,3); IplImage* sign_bin=cvCreateImage(cvGetSize(sign),IPL_DEPTH_8U,1); IplImage* canny = cvCreateImage(cvGetSize(sign),IPL_DEPTH_8U,1); IplImage* mask = cvCreateImage(cvGetSize(sign),IPL_DEPTH_8U,1); //Создание маски cvSet(mask,cvScalar(0,0,0)); //Преобразуем исходное изображение в градации серого cvCvtColor(sign,sign_hsv,CV_BGR2HSV); //Проводим бинаризацию полученного изображения(преобразуем в двоичное) cvInRangeS(sign_hsv, cvScalar(170,100,100), cvScalar(179,255,255), sign_bin); cvCanny(sign_bin,canny,50,255,5); cvSmooth(canny,canny,CV_BLUR,2,2); //Хранилище памяти для контуров CvMemStorage* storage = cvCreateMemStorage(0); CvSeq* contours=0; //Поиск контура cvFindContours(canny,storage,&contours,sizeof(CvContour),CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0)); if(abs(cvContourArea(storage))>20) { // рисуем найденный контур НА маске и заливаем его белым cvDrawContours(mask,contours, CV_RGB(255,255,255),CV_RGB(255,255,255), 2, CV_FILLED, CV_AA, cvPoint(0,0)); } cvNamedWindow("Original",CV_WINDOW_AUTOSIZE); cvNamedWindow("Gray",CV_WINDOW_AUTOSIZE); cvNamedWindow("Bin",CV_WINDOW_AUTOSIZE); cvNamedWindow("Canny",CV_WINDOW_AUTOSIZE); cvNamedWindow("Mask",CV_WINDOW_AUTOSIZE); cvShowImage("Original",sign); cvShowImage("Gray",sign_hsv); cvShowImage("Bin",sign_bin);; cvShowImage("Сanny",canny); cvShowImage("Mask",mask); cvWaitKey(0); cvReleaseImage(&sign); cvReleaseImage(&sign_hsv); cvReleaseImage(&sign_bin); cvReleaseImage(&canny); cvReleaseImage(&mask); cvReleaseMemStorage(&storage); cvDestroyAllWindows(); return 0; } Извиняюсь, что такая куча сложностей с переписыванием на разные языки. Чтобы разбираться и в случае чего опытные люди могли помочь, пишу на Cи, а в дальнейшем переписываю на C#, всвязи с требованием проекта... Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано February 18, 2013 Вот кусок моего кода. Надеюсь поймете где у Вас ошибка: vector<vector<Point> > contours; vector<Vec4i> hierarchy; findContours(img8U,contours, hierarchy, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, Point()); if(contours.size()>0) { for( int i = 0; i < contours.size(); i++ ) { if(contourArea(contours[i])>500) { Rect r=cv::boundingRect(contours[i]); Rects.push_back(r); } } }[/code] есть еще кусок с сишным интерфейсом отсюда: http://robocraft.ru/blog/computervision/640.html [code]// хранилище памяти для контуров CvMemStorage* storage = cvCreateMemStorage(0); CvSeq* contours=0; // находим контуры int contoursCont = cvFindContours( bin, storage,&contours,sizeof(CvContour),CV_RETR_LIST,CV_CHAIN_APPROX_SIMPLE,cvPoint(0,0)); assert(contours!=0); // обходим все контуры for( CvSeq* current = contours; current != NULL; current = current->h_next ){ // вычисляем площадь и периметр контура double area = fabs(cvContourArea(current)); double perim = cvContourPerimeter(current); // 1/4*CV_PI = 0,079577 if ( area / (perim * perim) > 0.07 && area / (perim * perim)< 0.087 ){ // в 10% интервале // нарисуем контур cvDrawContours(_image, current, cvScalar(0, 0, 255), cvScalar(0, 255, 0), -1, 1, 8); } } 1 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Alexer 0 Жалоба Опубликовано February 19, 2013 Спасибо огромнейшее, разобрался с этим вопросом. Я хотел бы спросить у Вас еще..вот после вычитания маски из исходного изображения, был получен знак. А вот как его лучше распознать? Я хотел сравнивать данный знак "40", со знаком "40" из ГОСТа и на основе какого-то процентного совпадения сделать вывод с определённой вероятностью, что это именно этот знак. Насколько такой метод эффективен и можно ли где нибудь почитать о реализации чего-то подобного в OpenCV? Есть ли у него какие нибудь "подводные камни"? Сможет ли программа узнать знак, если предположим, они по какой-либо причине разных размеров?(допустим изображение знака в программе меньше, чем знак на изображении шаблона). Извините, что так много вопросов и скорее всего большинство из них действительно глупые, но я нашёл довольно мало реcурсов в рунете, посвящённых OpenCV( Ваш форум и robocraft.ru) Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано February 19, 2013 Вначале вырезать кусок со знаком, или назначить область интереса (ROI), в матрицах это означает просто вынуть подматрицу, в IplImage для этого есть функции SetImageROI, ResetImageROI. По поводу размера, проблем не должно быть. Приводите к какому то стандартному, скажем 31х31 и сравнивайте с ним. Сравнивать можно или брутфорсом (начать можно с примера: descriptor_extractor_matcher.cpp), или подать изображение на вход нейронной сети, или другого классификатора. Можно и шаблоном. Почитать можно на сайте OpenCV: http://docs.opencv.org/doc/tutorials/imgproc/histograms/template_matching/template_matching.html Ну и тут посмотрите: http://www.ee.nthu.edu.tw/clhuang/paper/2001-2.pdf http://www.cvip.uofl.edu/wwwcvip/research/publications/Pub_Pdf/2004/ACIVS%202004%20paper023.pdf И еще на шарпе: http://www.emgu.com/wiki/index.php/Traffic_Sign_Detection_in_CSharp Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Argon 2 Жалоба Опубликовано March 20, 2013 Доброго времени суток! будьте так любезны и помогите разобраться в такой ситуации: после разности изображений получаю следующий результат: http://floomby.ru/s1/vaExRu код: void MouseDetected::StartVideoFile(){ frame = cvQueryFrame(capture); if (frame.empty() == true) { return; QMessageBox::information(this, "Сообщение программы", "Видео " + qVideofileName + "обработано успешно."); ui->IplOutputImage->setPixmap(QPixmap::fromImage(qimgNoFoto)); } dPosSlid = cvGetCaptureProperty(capture, CV_CAP_PROP_POS_FRAMES); int iFirstPosition = (int)dPosSlid; ui->lcdNumber->display(iFirstPosition); ui->horizontalSlider->setValue(iFirstPosition); //////////////////////////////////////////////Обработка кадра matOriginalGray = frame; matOriginal = frame; cv::cvtColor(matOriginalGray, matOriginalGray, CV_RGB2GRAY); cv::absdiff(matOriginalGray, matFon, matItog); cv::GaussianBlur(matItog, matItog, cv::Size(9,9), 1.5); cv::threshold(matItog, matItog, hSlider3, hSlider2, CV_THRESH_BINARY); cv::GaussianBlur(matItog, matItog, cv::Size(9,9), 1); matItog.convertTo(matProcessed, CV_8U); cv::Canny(matProcessed, matProcessed, 50, dcanny, 3); cv::findContours(matProcessed, vP, v4i,CV_RETR_TREE, CV_CHAIN_APPROX_NONE); //Обработка контролов cv::namedWindow("111", 0); cv::imshow("111", matOriginal); // QImage gimgOriginal((uchar*)matProcessed.data ,matProcessed.cols, matProcessed.rows, matProcessed.step, QImage::Format_Indexed8); ui->IplOutputImage->setPixmap(QPixmap::fromImage(gimgOriginal)); } подскажите как мне теперь выделить и обрисовать объект на основном кадре? желательно еще получать площадь объекта... Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано March 20, 2013 Как нарисовать и найти площадь есть в документации: http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Argon 2 Жалоба Опубликовано March 21, 2013 спасибо, как определять все контуры разобрался, а как выделить среди них только один, который должен находиться в определенных координатах на изображении??? вопрос больше по синтаксису чем по реализации.... на С делал так, 1) задавал интересующую меня область ROI int x = 172; int y = 42; int width = 379; int height = 365; int add = 1; 2) после преобразований над изображением делеа следующее, т.е. обрезал границы и выделяо объект: cvFindContours(itog, storage, &contours); for( ; contours!=0; contours->h_next) { CvRect* rect = cvBoundingRect(contours, 0); if (((rect.x >= x) && (rect.y <= y + height)) && ((rect.x >= rect.x + 5) || (rect.y <= rect.y + 5))) { if ((rect.x + 25 <= rect.x + rect.width )|| (rect.y + 25 <= rect.y + rect.height)) { cvRectangle(image, cvPoint(rect.x, rect.y), cvPoint(rect.x + rect.width, rect.y +rect.height), cvScalar(0,0,255,0), 1, 8, 0); } } } как мне на Qt проделать такое же выделение??? и еще, так и не понял как находить центр выделенного контура после cv::drawContours.... если не сложно, приведите простой пример.... Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано March 21, 2013 Конуры имеют рад характеристик, такие как координаты центра масс, площадь, моменты. Отфильтруйте по ним. см. по ссылке выше команды: boundingRect - отсюда можно взять центр moments - отсюда можно взять центр contourArea convexHull minAreaRect - отсюда можно взять центр minEnclosingCircle - отсюда можно взять центр По поводу выделения см. пост 328. Кусок изображения можно достать так: Rect r=cv::boundingRect(contours[i]); Mat roi=img(r);[/code] Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Argon 2 Жалоба Опубликовано March 22, 2013 используя поиск элементов получаю из кода: int idx = 0; for( ; idx >= 0; idx = v4i[idx][0] ) { cv::Scalar color( 0, 0, 255 ); for(int i = 0; i < vP.size(); i++) { cv::Rect rect = cv::boundingRect(vP[i]); if((rect.x >= x) && (rect.y <= y + height) && (cv::contourArea(vP[i]) > 100)) { cv::drawContours( matOriginal, vP, i, color, CV_FILLED, 8, v4i); } } } результат http://floomby.ru/s1/mavejr весь объект закрашен, а нужно только очертить контур... что не так делаю?? второй вопрос: как можно ускорить обработку из такого кода void MouseDetected::StartVideoFile(){ frame = cvQueryFrame(capture); if (frame.empty() == true) { return; QMessageBox::information(this, "Сообщение программы", "Видео " + qVideofileName + "обработано успешно."); ui->IplOutputImage->setPixmap(QPixmap::fromImage(qimgNoFoto)); } // для визуализации происходящего dPosSlid = cvGetCaptureProperty(capture, CV_CAP_PROP_POS_FRAMES); int iFirstPosition = (int)dPosSlid; ui->lcdNumber->display(iFirstPosition); ui->horizontalSlider->setValue(iFirstPosition); /////////---------Обработка кадра matOriginalGray = frame; matOriginal = frame; cv::cvtColor(matOriginalGray, matOriginalGray, CV_RGB2GRAY); cv::GaussianBlur(matOriginalGray, matOriginalGray, cv::Size(3,3), 1); cv::absdiff(matOriginalGray, matFon, matItog); cv::GaussianBlur(matItog, matItog, cv::Size(9,9), 1.5); cv::threshold(matItog, matItog, hSlider3, hSlider2, CV_THRESH_BINARY); cv::GaussianBlur(matItog, matItog, cv::Size(3,3), 1); cv::Canny(matItog, matItog, 50, dcanny, 3); cv::findContours(matItog, vP, v4i,CV_RETR_CCOMP , CV_CHAIN_APPROX_NONE); //Обработка контролов int idx = 0; for( ; idx >= 0; idx = v4i[idx][0] ) { cv::Scalar color( 0, 0, 255 ); for(int i = 0; i < vP.size(); i++) { cv::Rect rect = cv::boundingRect(vP[i]); if((rect.x >= x) && (rect.y <= y + height) && (cv::contourArea(vP[i]) > 100)) { cv::drawContours( matOriginal, vP, i, color, CV_FILLED, 8, v4i); } } } cv::cvtColor(matOriginal, matOriginal, CV_BGR2RGB); QImage gimgOriginal((uchar*)matOriginal.data ,matOriginal.cols, matOriginal.rows, matOriginal.step, QImage::Format_RGB888); ui->IplOutputImage->setPixmap(QPixmap::fromImage(gimgOriginal)); } Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано March 22, 2013 весь объект закрашен, а нужно только очертить контур... что не так делаю?? cv::drawContours( matOriginal, vP, i, color, CV_FILLED, 8, v4i); Ускорить можно не обновляя данные на ui каждый кадр, я имею ввиду слайдеры, кнопки и прочую подобную лабуду.. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Argon 2 Жалоба Опубликовано March 22, 2013 спасибо! помогло и заработало! Только как найти центр выделенного объекта вообще догнать немогу... ... сказывается тяжелая неделя.... Приведите небольшой пример установки средней точки в объекте после обработки изображения cv::drawContours Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано March 22, 2013 как то так: RotatedRect box; box=minAreaRect(Mat(contour)); // Рисуем габаритные прямоугольники Point2f center, vtx[4]; box.points(vtx); for(int k = 0; k < 4; k++ ) { line(Image, vtx[k], vtx[(k+1)%4], Scalar(255, 255, 0), 1, CV_AA); } // Рисуем центры масс circle(Image,box.center,1,Scalar(255,255,255),-1);[/code] 1 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Argon 2 Жалоба Опубликовано March 25, 2013 Спасибо! Все получилось! Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано April 11, 2013 Интересный способ манипуляции контуром, посредством контрольных точек (с исходником): описание: http://www.morethantechnical.com/2013/01/05/shape-manipulation-with-moving-least-squares-for-curves-w-code/ исходники: https://github.com/royshil/CurveDeformationMLS Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
_me_ 0 Жалоба Опубликовано April 14, 2013 Здравствуйте! Подскажите пожалуйста как получить приближенный эллипс зная контур CvContour. Затем необходимо закрасить все пиксели, которые находятся вне эллипса, на изображении IplImage в белый цвет. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано April 14, 2013 "Приближенные" эллипсы могут быть разные. Уточните что Вам нужно конкретно. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
_me_ 0 Жалоба Опубликовано April 14, 2013 Есть контур, как изображено на первой картинке, нужно получить картинку, где пиксели, которые вне эллипса (фото 2), закрашены в белый. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано April 14, 2013 Попробуйте это: http://se.cs.ait.ac.th/cvwiki/opencv:tutorial:fitting_ellipse_using_ransac_algorithm ну и в стандартных примерах: opencv/samples/cpp/fitellipse.cpp Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
_me_ 0 Жалоба Опубликовано April 14, 2013 Эллипс я рисую следующим образом CvContour contour; CvSeqBlock contour_block; cvMakeSeqHeaderForArray(CV_SEQ_POLYGON, sizeof(CvContour),sizeof(CvPoint),cvpoints2, Contour_Points*2, (CvSeq*)&contour, &contour_block); CvSeq* seq = (CvSeq*)&contour; CvMemStorage* storage =cvCreateMemStorage(0);; seq = cvApproxPoly( seq , sizeof(CvContour), storage,CV_POLY_APPROX_DP, 5, 1 ); cvDrawContours(TempImage4, seq, CV_RGB(255,216,0), CV_RGB(0,0,250), 0, 1,8); CvBox2D box=cvFitEllipse2(seq); cvEllipseBox(TempImage,box,CV_RGB(0,255,0)); Проблема именно в определении - находится ли точка внутри или вне этого эллипса. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано April 14, 2013 Ну, если скорость не особо критична, можно сделать по тупому : нарисовать эллипс на черном изображении и смотреть по нему. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
_me_ 0 Жалоба Опубликовано April 14, 2013 Не совсем поняла, как это можно сделать, если честно) Нашла функцию CVAPI(double) cvPointPolygonTest( const CvArr* contour,CvPoint2D32f pt, int measure_dist ), но в качестве первого параметра могу передать только контур seq. Нужно, по-видимому, каким-то образом получить объект эллипс и преобразовать к типу CvArr*, но с opencv я мало знакома. Существует ли такая возможность? Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано April 15, 2013 Рисуете заполненный белым эллипс на черном изображении (заново выделенном c типом CV_8UC1 ) получаете маску. cvEllipseBox(MaskImage,box,CV_RGB(255,255,255),-1); Чтобы проверить в эллипсе точка или нет, считываете значение пикселя маски, если он не равен нулю, то точка в эллипсе. Это если нужно проверять по одной точке. Если нужно залить все лишнее другим цветом, то используете эту маску при копировании. Вначале создаете изображение-приемник, заливаете его цветом фона (например белым), дальше копируете на него из изображения-источника по маске (см. параметры команды копирования). 1 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
_me_ 0 Жалоба Опубликовано April 15, 2013 Спасибо, но может все же есть более оптимальный вариант? Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано April 15, 2013 А Вы этот попробуйте, обычно так и делают. Проверять каждую точку изображения вычисляя полином наверное дольше будет, чем считать значение маски из памяти. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах