Commits

iorodeo committed 1a399e2

Worked on blobfinder.

Comments (0)

Files changed (8)

src/demo/blob_finder/CMakeLists.txt

 cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
 
 project(blob_finder)
-add_executable(blob_finder blob_finder_main.cpp blob_finder.cpp)
-target_link_libraries(blob_finder ${bias_ext_link_LIBS} bias_camera_facade)
 
+set(
+    blob_finder_HEADERS
+    blob_data.hpp
+    blob_finder_param.hpp
+    blob_finder.hpp
+    )
 
+set(
+    blob_finder_SOURCES
+    blob_data.cpp
+    blob_finder_main.cpp
+    blob_finder_param.cpp
+    blob_finder.cpp
+    )
 
+qt4_wrap_cpp(blob_finder_HEADERS_MOC ${blob_finder_HEADERS})
+
+include(${QT_USE_FILE})
+add_definitions(${QT_DEFINITIONS})
+
+add_executable(
+    blob_finder
+    ${blob_finder_HEADERS_MOC}
+    ${blob_finder_SOURCES} 
+    )
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+include_directories(.)
+target_link_libraries(
+    blob_finder 
+    ${QT_LIBRARIES} 
+    ${bias_ext_link_LIBS} 
+    bias_camera_facade
+    )
+
+
+

src/demo/blob_finder/blob_data.cpp

+#include "blob_data.hpp"
+#include <sstream>
+#include <iostream>
+
+// Centroid 
+// ----------------------------------------------------------------------------
+Centroid::Centroid()
+{
+    x = 0;
+    y = 0;
+}
+
+
+Centroid::Centroid(cv::Moments moments)
+{
+    setFromMoments(moments);
+}
+
+
+void Centroid::setFromMoments(cv::Moments moments)
+{
+    x = moments.m10/moments.m00;
+    y = moments.m01/moments.m00;
+}
+
+
+std::string Centroid::toStdString(unsigned int indent)
+{
+    std::stringstream ss;
+    std::string indentStr0 = getIndentString(indent);
+    std::string indentStr1 = getIndentString(indent+1);
+    ss << indentStr0 << "centroid:" << std::endl;
+    ss << indentStr1 << "x: " << x << std::endl;
+    ss << indentStr1 << "y: " << y << std::endl;
+    return ss.str();
+}
+
+
+void Centroid::print(unsigned int indent)
+{
+    std::cout << toStdString(indent);
+}
+
+
+// Ellipse
+// ----------------------------------------------------------------------------
+
+Ellipse::Ellipse()
+{
+    centerX = 0;
+    centerY = 0;
+    semiMajor = 0;
+    semiMinor = 0;
+    angle = 0;
+}
+
+
+Ellipse::Ellipse(std::vector<cv::Point> contour)
+{
+    setFromContour(contour);
+}
+
+
+void Ellipse::setFromContour(std::vector<cv::Point> contour)
+{
+    cv::Mat pointsf;
+    cv::Mat(contour).convertTo(pointsf,CV_32F);
+    cv::RotatedRect rotRect = cv::fitEllipse(pointsf);
+    centerX = rotRect.center.x;
+    centerY = rotRect.center.y;
+    if (rotRect.size.width > rotRect.size.height)
+    {
+        semiMajor = 0.5*rotRect.size.width;
+        semiMinor = 0.5*rotRect.size.height;
+        angle = rotRect.angle;
+    }
+    else
+    {
+        semiMajor = 0.5*rotRect.size.height;
+        semiMinor = 0.5*rotRect.size.width;
+        angle = rotRect.angle + 90.0;
+    }
+    if (angle > 180.0)
+    {
+        angle -= 180.0;
+    }
+}
+
+
+std::string Ellipse::toStdString(unsigned int indent)
+{
+    std::stringstream ss;
+    std::string indentStr0 = getIndentString(indent);
+    std::string indentStr1 = getIndentString(indent+1);
+    ss << indentStr0 << "ellipse:" << std::endl;
+    ss << indentStr1 << "centerX: " << centerX << std::endl;
+    ss << indentStr1 << "centerY: " << centerY << std::endl;
+    ss << indentStr1 << "semiMajor: " << semiMajor << std::endl;
+    ss << indentStr1 << "semiMinor: " << semiMinor << std::endl;
+    ss << indentStr1 << "angle: " << angle << std::endl;
+    return ss.str();
+}
+
+
+void Ellipse::print(unsigned int indent)
+{
+    std::cout << toStdString(indent);
+}
+
+
+void Ellipse::draw(cv::Mat &img)
+{ 
+    cv::Point lineStart; 
+    cv::Point lineStop;
+
+    // Plot major axis
+    lineStart.x = centerX - semiMajor*std::cos(M_PI*angle/180.0);
+    lineStart.y = centerY - semiMajor*std::sin(M_PI*angle/180.0);
+    lineStop.x = centerX + semiMajor*std::cos(M_PI*angle/180.0);
+    lineStop.y = centerY + semiMajor*std::sin(M_PI*angle/180.0);
+    cv::line(img,lineStart,lineStop,cv::Scalar(0,255,0),2,8);
+
+    // Plot limor axis
+    double anglePlus90 = angle + 90.0;
+    lineStart.x = centerX - semiMinor*std::cos(M_PI*anglePlus90/180.0);
+    lineStart.y = centerY - semiMinor*std::sin(M_PI*anglePlus90/180.0);
+    lineStop.x = centerX + semiMinor*std::cos(M_PI*anglePlus90/180.0);
+    lineStop.y = centerY + semiMinor*std::sin(M_PI*anglePlus90/180.0);
+    cv::line(img,lineStart,lineStop,cv::Scalar(0,255,0),2,8);
+
+    // Plot ellipse
+    cv::Point centerPt = cv::Point(centerX, centerY);
+    cv::Size size = cv::Size(semiMajor, semiMinor);
+    cv::ellipse(img,centerPt,size,angle,0,360,cv::Scalar(0,255,0),2,8);
+}
+
+
+// Blob Data
+// ----------------------------------------------------------------------------
+BlobData::BlobData()
+{
+    area = 0;
+}
+
+
+BlobData::BlobData(std::vector<cv::Point> contour)
+{
+    setFromContour(contour);
+}
+
+
+void BlobData::setFromContour(std::vector<cv::Point> contour)
+{
+    contourVector = contour;
+    cv::Moments moments = cv::moments(contour);
+    area = moments.m00;
+    centroid = Centroid(moments);
+    if (contour.size() >= 5)
+    {
+        ellipse = Ellipse(contour);
+    }
+}
+
+
+std::string BlobData::toStdString(unsigned int indent)
+{
+    std::stringstream ss;
+    std::string indentStr0 = getIndentString(indent);
+    std::string indentStr1 = getIndentString(indent+1);
+    ss << indentStr0 << "blobData:" << std::endl;
+    ss << indentStr1 << "area: " << area << std::endl;
+    ss << centroid.toStdString(indent+1);
+    ss << ellipse.toStdString(indent+1);
+    return ss.str();
+}
+
+
+void BlobData::print(unsigned int indent)
+{
+    std::cout << toStdString(indent);
+}
+
+
+void BlobData::draw(cv::Mat &img)
+{ 
+    std::vector<std::vector<cv::Point>> contourArray;
+    contourArray.push_back(contourVector);
+    cv::drawContours(img, contourArray, 0, cv::Scalar(0,0,255),2,8);
+    ellipse.draw(img);
+}
+
+
+// Utility functions
+// ----------------------------------------------------------------------------
+std::string getIndentString(unsigned int indent, unsigned indentStep)
+{
+    std::string indentString;
+    for (unsigned int i=0; i<indent; i++)
+    {
+        for (unsigned int j=0; j<indentStep; j++)
+        {
+            indentString.append(" ");
+        }
+    }
+    return indentString;
+}
+

src/demo/blob_finder/blob_data.hpp

+#ifndef BLOB_DATA_HPP
+#define BLOB_DATA_HPP
+
+#include <vector>
+#include <list>
+#include <opencv2/core/core.hpp>
+#include <opencv2/highgui/highgui.hpp>
+#include <opencv2/imgproc/imgproc.hpp>
+
+class Centroid
+{
+    public:
+        double x;
+        double y;
+
+        Centroid();
+        Centroid(cv::Moments moments);
+        void setFromMoments(cv::Moments moments);
+        std::string toStdString(unsigned int indent=0);
+        void print(unsigned int indent=0);
+};
+
+class Ellipse
+{
+    public:
+        double centerX;
+        double centerY;
+        double semiMajor;
+        double semiMinor;
+        double angle;
+
+        Ellipse();
+        Ellipse(std::vector<cv::Point> contour);
+        void setFromContour(std::vector<cv::Point> contour);
+        std::string toStdString(unsigned int indent=0);
+        void print(unsigned int indent=0);
+        void draw(cv::Mat &img);
+};
+
+class BlobData
+{
+    public:
+        double area;
+        Centroid centroid;
+        Ellipse ellipse;
+        std::vector<cv::Point> contourVector;
+
+        BlobData();
+        BlobData(std::vector<cv::Point> contour);
+        void setFromContour(std::vector<cv::Point> contour);
+        std::string toStdString(unsigned int indent=0);
+        void print(unsigned int indent=0);
+        void draw(cv::Mat &img);
+
+};
+
+
+typedef std::list<BlobData> BlobDataList;
+
+std::string getIndentString(unsigned int indent, unsigned int indentStep=2);
+
+
+#endif // #ifndef BLOB_DATA_HPP
+
+

src/demo/blob_finder/blob_finder.cpp

 #include "blob_finder.hpp"
 #include "camera_facade.hpp"
+#include "blob_data.hpp"
+#include <cmath>
 #include <iostream>
-#include <vector>
+#include <algorithm>
 #include <opencv2/core/core.hpp>
 #include <opencv2/highgui/highgui.hpp>
 #include <opencv2/imgproc/imgproc.hpp>
 
-const float BlobFinder::DEFAULT_FRAMERATE = 10.0;
-const float BlobFinder::DEFAULT_DISPLAY_SCALE = 0.5;
-const double BlobFinder::DEFAULT_THRESHOLD = 100.0;
-const double BlobFinder::DEFAULT_MINIMUM_AREA = 50.0;
-const double BlobFinder::DEFAULT_MAXIMUM_AREA = 640.0*480.0;
-const double BlobFinder::THRESHOLD_MAXVAL = 255.0;
+BlobFinder::BlobFinder() {}
 
 
-BlobFinder::BlobFinder()
+BlobFinder::BlobFinder(BlobFinderParam param)
 {
-    frameRate_ = DEFAULT_FRAMERATE;
-    displayScale_ = DEFAULT_DISPLAY_SCALE;
-    threshold_ = DEFAULT_THRESHOLD;
-    minimumArea_ = DEFAULT_MINIMUM_AREA;
-    maximumArea_ = DEFAULT_MAXIMUM_AREA; 
-}
-
-
-BlobFinder::BlobFinder(float frameRate) : BlobFinder()
-{
-    frameRate_ = frameRate;
+    param_ = param;
 }
 
 
     bool success = true;
 
     std::cout << std::endl;
-    std::cout << "* finding blobs - press 'x' to exit" << std::endl;
+    std::cout << "* finding blobs - press 'q' to exit" << std::endl;
 
     success = startCapture();
     if (!success)
     }
     std::cout << std::endl;
 
-    cv::namedWindow("Raw Image", CV_WINDOW_AUTOSIZE | CV_WINDOW_KEEPRATIO | CV_GUI_EXPANDED);
     cv::namedWindow("Threshold Image", CV_WINDOW_AUTOSIZE | CV_WINDOW_KEEPRATIO | CV_GUI_EXPANDED); 
-    cv::namedWindow("Contour Image", CV_WINDOW_AUTOSIZE | CV_WINDOW_KEEPRATIO | CV_GUI_EXPANDED); 
+    cv::namedWindow("Contour Image",   CV_WINDOW_AUTOSIZE | CV_WINDOW_KEEPRATIO | CV_GUI_EXPANDED); 
 
     unsigned long cnt = 0;
 
         cv::Mat image;
         cv::Mat imageTemp;
         cv::Mat imageThresh;
-        cv::Mat imageContour;
+        cv::Mat imageBlobs;
         std::vector<std::vector<cv::Point>> contours;
-        std::vector<std::vector<cv::Point>> contoursFiltered;
+        BlobDataList blobDataList;
 
         // Grab frame from camera
         std::cout << "  frame: " << cnt;
             std::cout << " - error " << runtimeError.what() << std::endl;
             continue;
         }
-        std::cout << std::endl; 
+        std::cout << std::endl << std::endl; 
 
         // Threshold image, invert and find external contours 
-        cv::threshold(image,imageThresh, threshold_, THRESHOLD_MAXVAL, CV_THRESH_BINARY);
-        imageThresh = THRESHOLD_MAXVAL - imageThresh;
+        cv::threshold(image,imageThresh, param_.threshold, param_.thresholdMaxVal, CV_THRESH_BINARY);
+        imageThresh = param_.thresholdMaxVal - imageThresh;
         imageTemp = imageThresh.clone();
         cv::findContours(imageTemp, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
 
-        // Filter contours by area
+        // Copy gray image to RGB and draw contours on image
+        imageBlobs = cv::Mat(image.size(), CV_8UC3, cv::Scalar(0,0,0));
+        cvtColor(image,imageBlobs,CV_GRAY2BGR);
+
+        // Filter contours by area and compute descriptive data
         for (size_t index=0; index < contours.size(); index++)
         {
             cv::Moments contourMoments = cv::moments(contours[index]);
-            if ((contourMoments.m00 >= minimumArea_) && (contourMoments.m00 <= maximumArea_))
+            BlobData blobData = BlobData(contours[index]);
+
+            if ((blobData.area >= param_.minimumArea) && (blobData.area <= param_.maximumArea))
             {
-                contoursFiltered.push_back(contours[index]);
+                blobCnt++;
+                blobDataList.push_back(blobData);
 
-                double centroidX = contourMoments.m10/contourMoments.m00;
-                double centroidY = contourMoments.m01/contourMoments.m00;
-                int numBlob = contoursFiltered.size() - 1;
-                std::cout << "    blob: " << numBlob; 
-                std::cout << ", (" << centroidX << ", " << centroidY << ") " << std::endl;
+                std::cout << "    blob #: " << blobDataList.size() << std::endl;
+                blobData.print(2);
+                std::cout << std::endl;
+                blobData.draw(imageBlobs);
             }
         }
         std::cout << std::endl;
 
-        // Draw contours on image
-        imageContour = cv::Mat(image.size(), CV_8UC3, cv::Scalar(0,0,0));
-        for (size_t index=0; index < contoursFiltered.size(); index++)
-        {
-            cv::drawContours(imageContour, contoursFiltered, index, cv::Scalar(0,0,255));
-        }
 
-        // Display images
-        cv::resize(image,imageTemp, cv::Size(0,0), displayScale_, displayScale_);
-        cv::imshow("Raw Image", imageTemp);
-
-        cv::resize(imageThresh,imageTemp, cv::Size(0,0), displayScale_, displayScale_);
+        cv::resize(imageThresh,imageTemp, cv::Size(0,0), param_.displayScale, param_.displayScale);
         cv::imshow("Threshold Image", imageTemp);
 
-        cv::resize(imageContour, imageTemp, cv::Size(0,0), displayScale_, displayScale_); 
+        cv::resize(imageBlobs, imageTemp, cv::Size(0,0), param_.displayScale, param_.displayScale); 
         cv::imshow("Contour Image", imageTemp);
 
-        // Look for 'x' key press as signal to quit
+        // Look for 'q' key press as signal to quit
         int key = cv::waitKey(1);
-        if (key == 120)
+        if ((key == 'q') || (key == 'Q'))
         {
             break;
         }
 {
     std::cout << std::endl;
     std::cout << "* setup camera" << std::endl << std::endl;
+    std::cout << "  searching for cameras ... ";
 
-    std::cout << "  searching for cameras ... ";
     CameraFinder cameraFinder;
     CameraPtrList cameraPtrList = cameraFinder.createCameraPtrList();
     if (cameraPtrList.empty())
     }
 
     std::cout << cameraPtrList.size() << " cameras" << std::endl;
+
     for (CameraPtrList::iterator it=cameraPtrList.begin(); it!=cameraPtrList.end(); it++)
     {
         CameraPtr cameraPtr_ = *it;
     }
 
     std::cout << "  connecting to first camera ... ";
+
     cameraPtr_ = cameraPtrList.front();
-
     if (cameraPtr_ -> isConnected()) 
     {
         std::cout << "error: camera already connected" << std::endl;
         std::cout << "error: " << runtimeError.what() << std::endl;
         return false;
     }
+
     std::cout << "done" << std::endl;
-
     std::cout << "  model:  " << cameraPtr_ -> getModelName() << std::endl;
     std::cout << "  vendor: " << cameraPtr_ -> getVendorName() << std::endl;
+    std::cout << "  setting videoMode=Format7, trigger=internal ... ";
 
-    std::cout << "  setting videoMode=Format7, trigger=internal ... ";
     try
     {
         cameraPtr_ -> setVideoMode(VIDEOMODE_FORMAT7);
         std::cout << "error: " << runtimeError.what() << std::endl;
         return false;
     }
+
     std::cout << "done" << std::endl;
+    std::cout << "  setting framerate to " << param_.frameRate << " fps ... ";
 
-    std::cout << "  setting framerate to " << frameRate_ << " fps ... ";
     try
     {
         PropertyInfo  frameRateInfo = cameraPtr_ -> getPropertyInfo(PROPERTY_TYPE_FRAME_RATE);
         Property frameRateProp = cameraPtr_ -> getProperty(PROPERTY_TYPE_FRAME_RATE);
         frameRateProp.absoluteControl = true;
-        frameRateProp.absoluteValue = frameRate_;
+        frameRateProp.absoluteValue = param_.frameRate;
         frameRateProp.autoActive = false;
         cameraPtr_ -> setProperty(frameRateProp);
         frameRateProp = cameraPtr_ -> getProperty(PROPERTY_TYPE_FRAME_RATE);
         std::cout << "error: " << runtimeError.what() << std::endl;
         return false;
     }
+
     std::cout << "done" << std::endl;
     std::cout << std::endl;
 
         std::cout << "error: " << runtimeError.what() << std::endl;
         return false;
     }
+
     std::cout << "done" << std::endl;
     std::cout << std::endl;
+
     return true;
 }
 
 
-
 bool BlobFinder::startCapture()
 {
     std::cout << std::endl;
     std::cout << "* start capture ... ";
+
     try
     {
         cameraPtr_ -> startCapture();
         std::cout << "error: " << runtimeError.what() << std::endl;
         return false;
     }
+
     std::cout << "done" << std::endl;
+
     return true;
 }
 
 {
     std::cout << std::endl;
     std::cout << "* stop capture ... ";
+
     try
     {
         cameraPtr_ -> stopCapture();
         std::cout << "error: " << runtimeError.what() << std::endl << std::endl;
         return false;
     }
+
     std::cout << "done" << std::endl;
+
     return true;
 }
+

src/demo/blob_finder/blob_finder.hpp

 #ifndef BLOB_FINDER_HPP
 #define BLOB_FINDER_HPP
 #include "camera_facade_fwd.hpp"
+#include "blob_finder_param.hpp"
 
 using namespace bias;
 
 {
     public:
 
-        static const float DEFAULT_FRAMERATE;
-        static const float DEFAULT_DISPLAY_SCALE;
-        static const double DEFAULT_THRESHOLD;
-        static const double DEFAULT_MINIMUM_AREA;
-        static const double DEFAULT_MAXIMUM_AREA;
-        static const double THRESHOLD_MAXVAL;
-
         BlobFinder();
-        BlobFinder(float frameRate);
+        BlobFinder(BlobFinderParam param);
 
         bool setupCamera();
         bool cleanUp();
 
     private:
 
-        float frameRate_;
-        float displayScale_;
-        double threshold_;
-        double minimumArea_; 
-        double maximumArea_;
+        BlobFinderParam param_;
         CameraPtr cameraPtr_;
 
         bool startCapture();
         bool stopCapture();
-
+        bool sendData();
 };
 
 #endif // #ifndef BLOB_FINDER_HPP

src/demo/blob_finder/blob_finder_main.cpp

     std::cout << "--------------------------------------- " << std::endl;
 
     bool success = true;
-    const float frameRate = 50.0;
-    BlobFinder blobFinder(frameRate); 
+
+    BlobFinder blobFinder; 
 
     success = blobFinder.setupCamera();
     if (!success)

src/demo/blob_finder/blob_finder_param.cpp

+#include "blob_finder_param.hpp"
+#include <sstream>
+#include <iostream>
+
+const float  BlobFinderParam::DEFAULT_FRAMERATE        = 30.0;
+const float  BlobFinderParam::DEFAULT_DISPLAY_SCALE    = 0.5;
+const double BlobFinderParam::DEFAULT_THRESHOLD        = 100.0;
+const double BlobFinderParam::DEFAULT_THRESHOLD_MAXVAL = 255.0;
+const double BlobFinderParam::DEFAULT_MINIMUM_AREA     = 100.0;
+const double BlobFinderParam::DEFAULT_MAXIMUM_AREA     = 640.0*480.0;
+
+
+BlobFinderParam::BlobFinderParam()
+{
+    frameRate = DEFAULT_FRAMERATE;
+    displayScale = DEFAULT_DISPLAY_SCALE;
+    threshold = DEFAULT_THRESHOLD;
+    thresholdMaxVal = DEFAULT_THRESHOLD_MAXVAL;
+    minimumArea = DEFAULT_MINIMUM_AREA;
+    maximumArea = DEFAULT_MAXIMUM_AREA;
+}
+
+
+std::string BlobFinderParam::toStdString()
+{
+    std::stringstream ss;
+    ss << "frameRate:       " << frameRate        << std::endl;
+    ss << "displayScale:    " << displayScale     << std::endl;
+    ss << "threshold:       " << threshold        << std::endl;
+    ss << "thresholdMaxVal: " << thresholdMaxVal  << std::endl;
+    ss << "minimumArea:     " << minimumArea      << std::endl;
+    ss << "maximumArea:     " << maximumArea      << std:: endl;
+    return ss.str();
+}
+
+
+void BlobFinderParam::print()
+{
+    std::cout << toStdString();
+}
+
+

src/demo/blob_finder/blob_finder_param.hpp

+#ifndef BLOB_FINDER_PARAM_HPP
+#define BLOB_FINDER_PARAM_HPP
+
+#include <string>
+
+class BlobFinderParam
+{
+    public:
+
+        static const float  DEFAULT_FRAMERATE;
+        static const float  DEFAULT_DISPLAY_SCALE;
+        static const double DEFAULT_THRESHOLD;
+        static const double DEFAULT_MINIMUM_AREA;
+        static const double DEFAULT_MAXIMUM_AREA;
+        static const double DEFAULT_THRESHOLD_MAXVAL;
+
+        float frameRate;
+        float displayScale;
+        double minimumArea;
+        double maximumArea;
+        double threshold;
+        double thresholdMaxVal;
+
+        BlobFinderParam();
+
+        std::string toStdString();
+        void print();
+};
+
+#endif // #ifndef BLOB_FINDER_PARAMS_HPP