Перейти к содержимому
Compvision.ru
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]

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


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

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



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++ чувство что ошибаюсь в элементарном из за не знания =(((

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


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

int unsigned i=0; -> unsigned int

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

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

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


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

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

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

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

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


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

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

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

R=G=B > Threshold

!!!

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


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

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

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

a61575497021.png

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

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

Изменено пользователем Виктор

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


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

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

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


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

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

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

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

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

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

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


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

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

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


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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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


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

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

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

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

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

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

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


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

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

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

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

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

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

Войти

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

Войти сейчас


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

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

×