Jump to content
Compvision.ru
Sign in to follow this  
milk3d

Поиск зелёных объектов на изображении

Recommended Posts

У меня такой код без проблем работает:

// test.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "vector"
class ob{
public:
char id; //Цвет
int M00,M10,M01;
int Xc,Yc;
ob()
{
M00=M10=M01=0;
}
void addPoint(int x, int y)
{
M00++;
M10+=x;
M01+=y;
}

};

int _tmain(int argc, _TCHAR* argv[])
{

std::vector<ob*> bufOb;
for(int i=0;i<10;i++)
{
bufOb.push_back(new ob);
}

for(unsigned int i=0;i<bufOb.size();i++)
{
delete bufOb[i];
}
bufOb.clear();
getchar();
return 0;
}
[/code]

Share this post


Link to post
Share on other sites

Не понял... от центровка по объекту, а затем удаление массива?



for(unsigned int i=0;i<bufOb.size();i++)

{

delete bufOb[i]; 

}


В такой версии bufOb в 2-х случаях начинает выдавать ошибку


// opencv1.cpp: определяет точку входа для консольного приложения.

//


#include "stdafx.h"

#include <cv.h>

#include <highgui.h>

#include <ctype.h>

#include <stdio.h>

#include <stdlib.h>


#include <iostream>

#include <vector>


using namespace std;

// Размер картинки

        int width;

        int height;

//Класс объекта

class ob{

public:

        char id; //Цвет

        int M00,M10,M01;

        int Xc,Yc;

        ob(){

                M00=M10=M01=0;

        }

        void addPoint(int x, int y){

                M00++;

                M10+=x;

                M01+=y;

        }

        CvPoint getCenter(){

                Xc=int(M10/M00);

                Yc=int(M01/M00);

                return cvPoint(Xc,Yc);

        }

};

//---Три функции алгоритма заливки

void NearPix(uchar** ptr,int x, int y, int *numStack, CvPoint *Stack, ob &Obj){

        if(ptr[y][3*x]==255){

                ptr[y][3*x] = 0;

                ptr[y][3*x+1] = 255;

                ptr[y][3*x+2] = 0;

                Stack[*numStack].x=x;

                Stack[*numStack].y=y;

                (*numStack)++;

                Obj.addPoint(x,y);

        }

}


void OneStep(uchar** ptr, int *numSrc, int *numDest, CvPoint *Src, CvPoint *Dest, ob &Obj){

        int x,y,i;

        *numDest=0;

        for(i=0; i<*numSrc;i++){

                x=Src[i].x;

                y=Src[i].y;

                NearPix(ptr,x+1,y,numDest,Dest,Obj);

                NearPix(ptr,x-1,y,numDest,Dest,Obj);

                NearPix(ptr,x,y+1,numDest,Dest,Obj);

                NearPix(ptr,x,y-1,numDest,Dest,Obj);

        }

}


void WaveFill(uchar** ptr,int xst, int yst, ob &Obj){


        Obj.addPoint(xst,yst);

        ptr[yst][3*xst] = 0;

        ptr[yst][3*xst+1] = Obj.id;

        ptr[yst][3*xst+2] = 0;


        int numA, numB;

        CvPoint *stackA, *stackB;


        stackA=new CvPoint[10000];

        stackB=new CvPoint[10000];

        numA=1;

        stackA[0].x=xst;

        stackA[0].y=yst;

        numB=0;

        while(1){

                if(numA>0)OneStep(ptr,&numA,&numB,stackA,stackB,Obj);

                else break;

                if(numB>0)OneStep(ptr,&numB,&numA,stackB,stackA,Obj);

                else break;

        }

        delete [] stackB;

        delete [] stackA;

}


IplImage* image = 0;


//---Начало программы

int main(int argc, char* argv[])

{


        // имя картинки задаётся первым параметром

        char* filename = argc == 2 ? argv[1] : "E:\\1.jpg";




		vector<ob*> bufOb;       //Буфер объектов


		cvNamedWindow( "Example2", CV_WINDOW_AUTOSIZE );

        image = cvLoadImage(filename,1);

        IplImage* frame;

        width = image->width;

        height = image->height;

        IplImage* buf = cvCreateImage( cvSize(width,height), 8, 3 );


        uchar** ptra=new uchar*[height];



                frame = cvLoadImage("E:\\1.jpg");


				cvCopy(frame,buf);


                cvSmooth( frame, frame, CV_GAUSSIAN, 5, 5 );

                uchar* ptr;

                //Первый прход по всем пикселям

                for( int y=0; y<height; y++ ){

                        ptr = (uchar*)(frame->imageData + y * frame->widthStep);

                        for( int x=0; x<width; x++ ){

                                //Гасим всё кроме зелёного

                                bool bGreen = ptr[3*x]+15<ptr[3*x+1]&&ptr[3*x+2]+15<ptr[3*x+1];

                                ptr[3*x] = ptr[3*x+1] = ptr[3*x+2] = bGreen*255;

                        }

                        ptra[y]=ptr;

                }

                //Рисуем рамку чёрного цвета по границе изображения

                //для ограничения заливки

                cvRectangle(frame,

                        cvPoint(0,0),

                        cvPoint(width-1,height-1),

                        cvScalar(0,0,0)

                );

                //Второй проход по всем пикселям в котором применяется заливка

                //для разделения объектов, причём шаг цикла это ограничение

                //на размер объекта

                for( int y=0; y<height; y+=1 ){

                        for( int x=0; x<width; x+=1 ){

                                if(ptra[y][3*x]==255){


					ob* newOb;

					newOb = new ob; 

                                        bufOb.push_back(newOb);

                                        WaveFill(ptra,x,y,bufOb[bufOb.size()-1]); // тут

                                }

                        }

                }


               for(int unsigned i=0; i<bufOb.size(); i++){

                        cvCircle (frame,bufOb[i].getCenter(),5,cvScalar(0,0,255),3,2); // тут

                }

                //Очистка буфера объектов

                bufOb.clear();

                cvShowImage( "Example2", frame );

                char c = cvWaitKey(33);




 cvDestroyWindow( "Example2" );

 cvReleaseImage(& image);

return 0;

 }


без финальной обработки запускается, правда виснет насмерть ))) .... осталось только самый конец....

помогите закончить ))) и я отправлюсь учить c++ чувство что ошибаюсь в элементарном из за не знания =(((

Share this post


Link to post
Share on other sites

int unsigned i=0; -> unsigned int

сейчас туго соображаю, завтра посмотрю подробнее

Еще лучше запуститесь под отладкой (Debug), наставьте бряков (F9) и шагайте построчно (F10), заодно и поймете как программа работает :)

Share this post


Link to post
Share on other sites

С наступившим новом годом!

Собственно во всём разобрался, фильтр доделать осталась для определения нужного текста, а так всё работает, спасибо!

Такой вопрос возник, а как найти белые цвет? Он вроде все 255, но по факту, когда так делаю, находятся все цвета которые есть на изображение (буквально сразу все), кроме белого...

Share this post


Link to post
Share on other sites

Переходите в пространство HSV :)

ЗЫ: белый = серый - это когда

R=G=B > Threshold

!!!

Share this post


Link to post
Share on other sites

Спасибо, очень пригодилось для понимания.

А допустим мне надо выделять не одноцветный объект, а объект залитый двумя или более цветами. Примерно такой:

a61575497021.png

Как лучше организовать эту операцию?

Вообще как я понимаю операция выделения объекта по цвету сводиться к "убиванию" всех других цветов отличных от искомого. Допустим если выделять искомые цвета белым, то получится так, что у меня будет белый объект. Но как достоверится что белый объект является искомым объектом?

Edited by Виктор

Share this post


Link to post
Share on other sites

Наложить белый объект (маску) на изображение и сравнить с искомым. Можно даже по количеству попавших под маску пикселей разных цветов (по гистограмме).

Share this post


Link to post
Share on other sites

Наложить белый объект (маску) на изображение и сравнить с искомым.

Это интересный вариант.

В этом случае можно вычислить процент совпадения?

Можно даже по количеству попавших под маску пикселей разных цветов (по гистограмме).

Но этот интереснее, так как он позволит получать больше информации.

Share this post


Link to post
Share on other sites

По первому варианту. Вырезаем, приводим к фиксированному масштабу (масштабу шаблона), по маске обрезаем все лишнее, и cvMatchTemplate (или что нибудь аналогичное) по каналам (RGB или HSV). Степень совпадения выдается в численном виде. В принципе, можно нормировать яркость, вычесть одно из другого, и найти сумму элементов результата.

Share this post


Link to post
Share on other sites

Доброго времени суток.

Передо мной поставили практически аналогичную задачу по выделению объектов.

Но есть несколько нюансов:

  • Выделение не определенного цвета, а цветового интерва. Хотя на первое время будут использоваться изображения в оттенках серого;
  • Существуют ограничения по площади закрашивания объектов.

На первый взгляд перебор всех пикселей для поиска нужных нам объектов достаточно медленно будет производится. Вот и вопрос есть ли более оптимальный вариант именно с учетом ограничений по площади.

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

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

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

P.S. Извините за ломаный язык...

Share this post


Link to post
Share on other sites

Хотя бы для эксперимента, попробуйте засечь время прохода по всем пикселям изображения, думаю результат Вас удивит :)

Если хотите работать с цветом, то и начинайте с цветного изображения. Только переведите его перед бинаризацией в пространство HSV.

Поиск контуров вполне нормальный вариант.

Еще гуглите по фразе: Connected Components Labeling.

Тут апплет иллюстрирующий алгоритм: http://www.cise.ufl.edu/~sahni/dsaaj/JavaVersions/applications/ImageComponentLabeling/ImageComponentLabeling.htm

Share this post


Link to post
Share on other sites

Сделал через прогон всех пикселей. Скорость приятно удивила, спасибо. В былые времена, когда начинал все с delphi, это все было в разы медленнее.

На счет цвета, маловероятно что кто-то будет потом на цвет переходить.

На счет преимущества HSV над RGB, пока не особо его осознаю. Может кто образумит)

На счет Connected Components Labeling. Уже решал подобного рода задачи когда еще не использовал библиотеку. Меня порадовала как раз функция cvFloodFill(), которая все делает что надо, да еще как раз площадь возвращает, да и периметр, который тоже потом понадобится.

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

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

×