Я все еще работаю над последняя программа и хотя я наконец узнал, как решить проблему (о том, как отфильтровать самый большой контур), у меня теперь есть новый вопрос, или, скорее, проблема.
Как вы видите, я использую алгоритм Канни для поиска краев в видео. Но объект, который я буду использовать для обнаружения, не имеет определенного цвета, поэтому, когда цвет объекта примерно такой же, как цвет окружения (например, если объект серебряный, а фон белый), край объекта исчезнет, и я не могу получить контур объекта.
Сейчас я протестирую каждый алгоритм фильтрации ребер, доступный в OpenCV, но чтобы сократить мою работу, мне нужна ваша помощь, чтобы рекомендовать лучший (или, по крайней мере, лучший) алгоритм, чем хитрый. Сейчас я проверил Собель, но результат не лучше, чем у Кэнни. Если возможно, пожалуйста, свяжите меня с хорошим примером для справки.
Код:
int main( int argc, char** argv )
{
CvCapture *cam;
CvMoments moments;
CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq* contours = NULL;
CvSeq* contours2 = NULL;
CvPoint2D32f center;
int i;
cam=cvCaptureFromCAM(0);
if(cam==NULL){
fprintf(stderr,"Cannot find any camera. \n");
return -1;
}
while(1){
IplImage *img=cvQueryFrame(cam);
if(img==NULL){return -1;}
IplImage *src_gray= cvCreateImage( cvSize(img->width,img->height), 8, 1);
cvCvtColor( img, src_gray, CV_BGR2GRAY );
cvSmooth( src_gray, src_gray, CV_GAUSSIAN, 5, 11);
cvCanny(src_gray, src_gray, 70, 200, 3);
cvFindContours( src_gray, storage, &contours, sizeof(CvContour), CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE, cvPoint(0,0));
if(contours==NULL){ contours=contours2;}
contours2=contours;
CvSeq* current_contour = contours;
double largestArea = 0;
CvSeq* largest_contour = NULL;
while (current_contour != NULL){
double area = fabs(cvContourArea(current_contour,CV_WHOLE_SEQ, false));
if(area > largestArea){
largestArea = area;
largest_contour = current_contour;
}
current_contour = current_contour->h_next;
}
cvMoments(largest_contour, &moments, 1);
double m_00 = cvGetSpatialMoment( &moments, 0, 0 );
double m_10 = cvGetSpatialMoment( &moments, 1, 0 );
double m_01 = cvGetSpatialMoment( &moments, 0, 1 );
float gravityX = (m_10 / m_00)-150;
float gravityY = (m_01 / m_00)-150;
if(gravityY>=0&&gravityX>=0&&m_00>=3000){
printf("center point=(%.f, %.f), Area = %.f \n",gravityX,gravityY,m_00); }if(m_00>=3000){
CvScalar color = CV_RGB(250,0,0);
cvDrawContours(img,largest_contour,color,color,-1,-1, 8, cvPoint(0,0));
}
cvShowImage( "Input", img );
cvShowImage( "Contours", src_gray );
cvClearMemStorage(storage);
if(cvWaitKey(33)>=0) break;
}
cvDestroyWindow("Contours");
cvDestroyWindow("Source");
cvReleaseCapture(&cam);
}
…и наконец, долгожданный пример картинки:
Во-первых, хороший (мой черный кошелек)
Во-вторых, провал (оранжевая коробка)
И, наконец, еще один сбой (белая коробка)
П.С., некоторые заметки:
Заранее спасибо. ура
Ваша проблема не в алгоритме обнаружения краев. Ваша проблема в том, что вы жестко программируете параметры алгоритма и ожидаете, что он волшебным образом сработает для всех изображений, которые вы на него бросаете. Также сглаживание изображения перед использованием cvCanny
не является необходимым, так как оператор Canny уже выполняет сглаживание для вас.
Так как сейчас немного яснее, чего вы хотите достичь, я могу предложить следующее: работать с видео, а не смотреть на каждый кадр отдельно. Если камера зафиксирована, и рука с объектом движется, то определение формы тривиально вычитание фона. Если камера не зафиксирована, вы все равно можете обнаружить руку (PDF ссылка) и работа оттуда. Кроме того, используйте любые другие знания, относящиеся к конкретному приложению, которыми вы можете обладать (например, предмет будет находиться в центре экрана, рука будет находиться под предметом).
Других решений пока нет …