struct CvBlobTrackerAutoParam1 { int FGTrainFrames; CvFGDetector* pFG; // segmentator tła CvBlobDetector* pBD; // detektor blobów CvBlobTracker* pBT; // tracker blobów CvBlobTrackGen* pBTGen; CvBlobTrackPostProc* pBTPP; int UsePPData; CvBlobTrackAnalysis* pBTA; };
Komentarz dodałem obok najważniejszych modułów (reszta jest opcjonalna). Tracker tworzymy za pomocą funkcji CvBlobTrackerAuto* cvCreateBlobTrackerAuto1(CvBlobTrackerAutoParam1* param = NULL);, gdzie, jak widać, przekazujemy nasze parametry. Dla standardowo dostępnych modułów mamy funkcje budujące odpowiednie obiekty. I tak np. dla detektora blobów mamy funkcję cvCreateBlobDetectorXXX gdzie XXX to Simple lub CC. Moduły są klasami wirtualnymi, nic nie stoi na przeszkodzie pisania własnych. Tak też uczynimy, żeby móc śledzić skórę. Użyłem prostego algorytmu segmentacji z poprzedniego wpisu. Klasa CvFGDetector wygląda następująco:
class CV_EXPORTS CvFGDetector: public CvVSModule { public: CvFGDetector(){SetTypeName("FGDetector");}; virtual IplImage* GetMask() = 0; /* Process current image: */ virtual void Process(IplImage* pImg) = 0; /* Release foreground detector: */ virtual void Release() = 0; };
Trzy metody do przedefiniowania :) Uzyskujemy nową klasę SimpleSkinDetector :
class SimpleSkinDetector : public CvFGDetector { IplImage * maska; public: SimpleSkinDetector() { maska = 0; SetTypeName("SSD"); }; virtual IplImage* GetMask() { return maska; } /* Process current image: */ virtual void Process(IplImage* img) { if (!maska) maska = cvCreateImage(cvGetSize(img), 8, 1); for (int y = 0; y < img->height; y++) { uchar* ptr = (uchar*) (img->imageData + y * img->widthStep); uchar* ptrRet = (uchar*) (maska->imageData + y * maska->widthStep); for (int x = 0; x < img->width; x++) { double b, g, r; b = ptr[3 * x]; g = ptr[3 * x + 1]; r = ptr[3 * x + 2]; double min = b; double max = b; if (min > g) min = g; if (min > r) min = r; if (max < g) max = g; if (max < r) max = r; if (r <= 95 || g <= 40 || b <= 20 || max - min <= 15 || fabs(r - g) <= 15 || r <= g || r <= b) { ptrRet[x] = 0; } else { ptrRet[x] = 255; } } } cvErode(maska, maska, NULL, 1); cvDilate(maska, maska, NULL, 1); }; /* Release foreground detector: */ virtual void Release() { if (maska) cvReleaseImage(&maska); } };
Wynik działania trackera wygląda następująco
Poniżej kod programu
#include < vector > #include < cv.h > #include < cvaux.h > #include < highgui.h > #include < iostream > #include < list > using namespace std; void rysujPunkty(IplImage * obr, int x, int y, CvScalar col) { int x1 = x - 5; int x2 = x + 5; int y1 = y - 5; int y2 = y + 5; if (x1 < 0) x1 = 0; if (x2 > obr->width - 1) x2 = obr->width - 1; if (y1 < 0) y1 = 0; if (y2 > obr->height - 1) y2 = obr->height - 1; cvLine(obr, cvPoint(x1, y), cvPoint(x2, y), col); cvLine(obr, cvPoint(x, y1), cvPoint(x, y2), col); } class SimpleSkinDetector : public CvFGDetector { IplImage * maska; public: SimpleSkinDetector() { maska = 0; SetTypeName("SSD"); }; virtual IplImage* GetMask() { return maska; } /* Process current image: */ virtual void Process(IplImage* img) { if (!maska) maska = cvCreateImage(cvGetSize(img), 8, 1); for (int y = 0; y < img->height; y++) { uchar* ptr = (uchar*) (img->imageData + y * img->widthStep); uchar* ptrRet = (uchar*) (maska->imageData + y * maska->widthStep); for (int x = 0; x < img->width; x++) { double b, g, r; b = ptr[3 * x]; g = ptr[3 * x + 1]; r = ptr[3 * x + 2]; double min = b; double max = b; if (min > g) min = g; if (min > r) min = r; if (max < g) max = g; if (max < r) max = r; if (r <= 95 || g <= 40 || b <= 20 || max - min <= 15 || fabs(r - g) <= 15 || r <= g || r <= b) { ptrRet[x] = 0; } else { ptrRet[x] = 255; } } } cvErode(maska, maska, NULL, 1); cvDilate(maska, maska, NULL, 1); }; /* Release foreground detector: */ virtual void Release() { if (maska) cvReleaseImage(&maska); } }; CvScalar kolorki[] = { CV_RGB(255, 255, 255), CV_RGB(255, 0, 255), CV_RGB(0, 255, 255), CV_RGB(255, 255, 0), CV_RGB(0, 0, 255), CV_RGB(255, 0, 0), CV_RGB(0, 255, 0) }; void rysujObszar(IplImage*dst, CvBlob* blob, CvScalar kol) { CvRect rect = CV_BLOB_RECT(blob); cvSetImageROI(dst, rect); cvAddS(dst, kol, dst); cvResetImageROI(dst); } int main(int argc, char** argv) { CvCapture* cam = NULL; if (argc > 1) cam = cvCreateCameraCapture(atoi(argv[1])); else cam = cvCreateCameraCapture(0); cvNamedWindow("Oryginał", CV_WINDOW_AUTOSIZE); cvNamedWindow("Skóra", CV_WINDOW_AUTOSIZE); cvNamedWindow("Bloby", CV_WINDOW_AUTOSIZE); //+++++++++++++++++++++++++++++++++++++++ CvBlobTrackerAutoParam1 params; CvBlobTrackerAuto* tracker; SimpleSkinDetector skd; params.pFG = &skd; params.FGTrainFrames = 0; params.pBD = cvCreateBlobDetectorSimple(); params.pBT = cvCreateBlobTrackerMS(); params.pBTA = cvCreateModuleBlobTrackAnalysisHistPVS(); params.pBTGen = cvCreateModuleBlobTrackGen1(); params.pBTPP = cvCreateModuleBlobTrackPostProcKalman(); tracker = cvCreateBlobTrackerAuto1(¶ms); //+++++++++++++++++++++++++++++++++++++++ IplImage * _img = cvQueryFrame(cam); while (true) { _img = cvQueryFrame(cam); // optymalizacja przez zmniejszenie analizowanego obszaru CvSize polowa = cvSize(_img->width / 2.0, _img->height / 2.0); IplImage* _img2 = cvCreateImage(polowa, 8, 3); IplImage * _skinImg = cvCreateImage(polowa, 8, 1); IplImage* _skinImgTemp = skd.GetMask() cvResize(_skinImgTemp, _skinImg); cvResize(_img, _img2); IplImage * _cross = cvCreateImage(polowa, 8, 3); cvZero(_cross); tracker->Process(_img2, NULL); if (tracker->GetBlobNum() > 0) { for (int i = tracker->GetBlobNum(); i > 0; i--) { CvScalar kolor = kolorki[i % 7]; // ustalamy kolor CvBlob* pB = tracker->GetBlob(i - 1); // pobieramy bloba CvPoint p = cvPointFrom32f(CV_BLOB_CENTER(pB)); // makra CV_BLOB_XXX pozwalaja uzyskac dane o blobach // rysujemy wyniki rysujPunkty(_cross, p.x, p.y, kolor); CvSize s = cvSize(MAX(1, cvRound(CV_BLOB_RX(pB))), MAX(1, cvRound(CV_BLOB_RY(pB)))); rysujObszar(_img2, pB, cvScalar(255, 0, 0)); cvRectangle(_cross, cvPoint(p.x - s.width, p.y - s.height), cvPoint(p.x + s.width, p.y + s.height), kolor, 2, CV_AA); } } cvShowImage("Oryginał", _img2); cvShowImage("Skóra", _skinImg); cvShowImage("Bloby", _cross); cvReleaseImage(&_skinImg); cvReleaseImage(&_skinImgTemp); cvReleaseImage(&_cross); cvReleaseImage(&_img2); int key = cvWaitKey(3); if (key == ' ') break; } cvDestroyAllWindows(); // sprzatamy if (cam)cvReleaseCapture(&cam); if (params.pBT)cvReleaseBlobTracker(¶ms.pBT); if (params.pBD)cvReleaseBlobDetector(¶ms.pBD); if (params.pBTGen)cvReleaseBlobTrackGen(¶ms.pBTGen); if (params.pBTA)cvReleaseBlobTrackAnalysis(¶ms.pBTA); if (params.pFG)cvReleaseFGDetector(¶ms.pFG); if (tracker)cvReleaseBlobTrackerAuto(&tracker); return 0; }
1 komentarz:
Ten program wywala błąd przy pierwszej próbie skalowania obrazu :) Zmienna maska nie ma rozmiaru więc nie można jej użyć jako wzorca do skalowania.
Prześlij komentarz