/************************************************************************ Blob.h FUNCTIONALITY: Definition of the Blob class and some helper classes to perform some calculations on it AUTHOR: Inspecta S.L. MODIFICATIONS (Modification, Author, Date): **************************************************************************/ //! Disable warnings referred to 255 character truncation for the std:map //#pragma warning(disable : 4786) #ifndef CBLOB_INSPECTA_INCLUDED #define CBLOB_INSPECTA_INCLUDED class Blob; #include "opencv2/core/core_c.h" #include "opencv2/opencv.hpp" #include "BlobLibraryConfiguration.h" #include "BlobContour.h" #include #include #ifdef BLOB_OBJECT_FACTORY //! Object factory pattern implementation #include "..\inspecta\DesignPatterns\ObjectFactory.h" #endif //! Type of labelled images typedef unsigned int LabelID; typedef std::list BlobList; typedef std::list BlobContourList; enum AreaMode {GREEN, PIXELWISE}; //! Blob class class Blob { friend class CompLabeler; public: Blob(); Blob(LabelID id, const cv::Point& startPoint, const cv::Size& originalImageSize); ~Blob(); //! Copy constructor Blob(const Blob& src); Blob(const Blob* src); //! Assigment operator Blob& operator=(const Blob& src); //! Adds a new internal contour to the blob void addInternalContour(const BlobContour& newContour); //! Retrieves contour in Freeman's chain code BlobContour* getExternalContour() { return &m_externalContour; } BlobContourList& getInternalContours() { return m_internalContours; } //! Bool to permit deletion with filter function double m_toBeDeleted; //! Get label ID LabelID getID() { return m_id; } void setID(LabelID newID) { m_id = newID; } //! > 0 for external blobs, 0 if not int exterior(IplImage* mask, bool xBorder = true, bool yBorder = true); //! opencv2 Interface int exterior(const cv::Mat& mask, bool xBorder = true, bool yBorder = true); //! Computes the area of the blob. //! areaCompMode defines which way to compute the areas: //! - Using green's formula (not exact result, probably faster) //! - Counting the pixels (probably slower) double area(AreaMode areaCompMode = GREEN); //! Compute blob's perimeter double perimeter(); //! Compute blob's moment (p,q up to MAX_CALCULATED_MOMENTS) //! if intContours = false, internal contours do not count for moment computation (i.e. the blob is considered without holes). double moment(int p, int q, bool intContours = true); //! Compute external perimeter double externalPerimeter(IplImage* mask, bool xBorder = true, bool yBorder = true); //! opencv2 interface double externalPerimeter(const cv::Mat& mask, bool xBorder = true, bool yBorder = true); //! Get mean grey color //(Warning: use meanStdDev for simultaneous computation of mean and std. dev, and for RGB images). double mean(IplImage *image); //! opencv2 interface //(Warning: use meanStdDev for simultaneous computation of mean and std. dev, and for RGB images). double mean(const cv::Mat& image); //! Get standard deviation grey color //(Warning: use meanStdDev for simultaneous computation of mean and std. dev, and for RGB images). double stdDev(IplImage *image); //! opencv2 interface //(Warning: use meanStdDev for simultaneous computation of mean and std. dev, and for RGB images). double stdDev(const cv::Mat& image); //! Computes mean and standard deviation of image, which can be in any opencv format //! Since mean and standard deviation are computed with the same function call, this results quicker than //! calling separately mean and standard deviation. void meanStdDev(const cv::Mat& image, cv::Scalar& mean, cv::Scalar& stddev); //void meanStdDev(Mat image, double *mean, double *stddev); //! Shows if the blob has associated information bool isEmpty(); //! Calculates the convex hull of the blob void getConvexHull(Contours& hull); //! Paints the blob in an image //! intContours - determines wheter to draw the holes of the blob (true) or not (false) //! srcImage - image from where to copy the holes contents. If unassigned and intContours is true, the internal pixels will be set to black. void fillBlob(IplImage *image, cv::Scalar color, int offsetX = 0, int offsetY = 0, bool intContours = false, const IplImage* srcImage = NULL); void fillBlob(const cv::Mat& image, cv::Scalar color, int offsetX = 0, int offsetY = 0, bool intContours = false, const cv::Mat& srcImage = cv::Mat()); //! Joins a blob to current one //! NOTE: All the data is copied, a new blob is created and joined to the caller one. void joinBlob(Blob* blob); //! Get bounding box cv::Rect getBoundingBox(); //! Get bounding ellipse cv::RotatedRect getEllipse(); //! Minimun X double minX() { return getBoundingBox().x; } //! Minimun Y double minY() { return getBoundingBox().y; } //! Maximun X double maxX() { return getBoundingBox().x + getBoundingBox().width; } //! Maximun Y double maxY() { return getBoundingBox().y + getBoundingBox().height; } /** Computes extremes for the contour (i.e. 4 points, respectively with max X, max Y, min X, minY) In case of perfect rectangular shapes, the code will return the vertexes in counterclockwise order. TODO: Extend function to joined blobs */ void getExtremes(cv::Point& xmax, cv::Point& xmin, cv::Point& ymax, cv::Point& ymin); //! Shifts the blob by (x,y) void shiftBlob(int x, int y); //! Returns the number of overlapping pixels between the caller blob and blob. //! A preliminary check is performed with respect to the bounding boxes in order to avoid unnecessary computations int overlappingPixels(Blob* blob); //! Computes the density of the blob, i.e. the ratio (blob Area) / (ConvexHullArea) //! areaCalculationMode defines which way to compute the areas: //! - Using green's formula (not exact result, probably faster) //! - Counting the pixels double density(AreaMode areaCalculationMode); //! Returns blob center in pixels (integers). cv::Point getCenter(); //! Return blob centroid cv::Point2f getCentroid(bool useInternalContours); /* * Border: 0 = top, 1 = right, 2 = bottom, 3 = left */ /*Contours getPointsTouchingBorder(int border);*/ //! For joined blobs, return the number of sub-blobs. int getNumJoinedBlobs(); cv::Size originalImageSize() const { return m_originalImageSize; } void originalImageSize(int width, int height) { m_originalImageSize.width = width; m_originalImageSize.height = height; } private: void requestDeletion(Blob* blob); //! Deallocates all contours void clearContours(); private: //! Just for multithread joining routine; bool m_startPassed; bool m_isJoined; BlobList m_joinedBlobs; Blob* m_deleteRequestOwnerBlob; ////////////////////////////////////////////////////////////////////////// // Blob contours ////////////////////////////////////////////////////////////////////////// //! External contour of the blob (crack codes) BlobContour m_externalContour; //! Internal contours (crack codes) BlobContourList m_internalContours; ////////////////////////////////////////////////////////////////////////// // Blob features ////////////////////////////////////////////////////////////////////////// //! Label number LabelID m_id; //! Area double m_area; //! Perimeter double m_perimeter; //! external perimeter from blob double m_externalPerimeter; //! mean gray color double m_meanGray; //! Standard deviation from gray color blob distribution double m_stdDevGray; //! Bounding box cv::Rect m_boundingBox; //! Bounding ellipse cv::RotatedRect m_ellipse; //! Sizes from image where blob is extracted cv::Size m_originalImageSize; friend class BlobGroup; }; #endif //CBLOB_INSPECTA_INCLUDED