SimpleBlobDetector 类移植

来源:互联网 发布:软件开发人员等级评定 编辑:程序博客网 时间:2024/06/06 03:18
opencv中集成了斑点检测的类:SimpleBlobDetector ,但是需要2.2版本以后才支持。
angstrom系统中自带的opencv版本是2.2.0的,恰好不支持斑点检测。之前编译了cvblob插件,没成功。

看了新版本里的SimpleBlobDetector 类后,发现其实现并不难,基于FeatureDetector类,而FeatureDetector是一个特征检测的基础类,其成员函数并没有什么实质的东西。而SimpleBlobDetector 类的实现函数用到的函数、变量类型等都是opencv2.2版本中有的,所以可以直接把SimpleBlobDetector 类拿出来,放到自己的应用程序中。并且可以在带opencv2.2的系统中编译通过。

/**头文件:定义类*/#ifndef BLOB_H#define BLOB_H#include <opencv2/core/core.hpp>#include <opencv2/core/types_c.h>#include <opencv2/flann/miniflann.hpp>#include <opencv2/features2d/features2d.hpp>#include <opencv2/imgproc/imgproc.hpp>#include <opencv2/imgproc/imgproc_c.h>#include <opencv2/core/internal.hpp>#include <iterator>#include <opencv2/highgui/highgui.hpp>#include <iostream>using namespace cv;using namespace std;class CV_EXPORTS BlobDetector //: public cv::FeatureDetector{public:    struct CV_EXPORTS Params    {        Params();        float thresholdStep;        float minThreshold;        float maxThreshold;        size_t minRepeatability;        float minDistBetweenBlobs;        bool filterByColor;        uchar blobColor;        bool filterByArea;        float minArea, maxArea;        bool filterByCircularity;        float minCircularity, maxCircularity;        bool filterByInertia;        float minInertiaRatio, maxInertiaRatio;        bool filterByConvexity;        float minConvexity, maxConvexity;        void read( const FileNode& fn );        void write( FileStorage& fs ) const;    };    BlobDetector(const BlobDetector::Params ¶meters = BlobDetector::Params());    void read( const FileNode& fn );    void write( FileStorage& fs ) const;/**detect keypoints in an image.*image the image.*keypoints the detected keypoints*mask mask specifying where to look for keypoints(optional).must be a char* matrix with non-zero values in the region of intestest.*/    void detect(const Mat& image,vector<KeyPoint>& keypoints,const Mat& mask=Mat()) const;/**detect keypoints in an image set*images image collection*keypoints collection of keypoints detected in an input image.* keypoints[i] is a set of keypoints detected in an images[i]*masks masks for image set. masks[i] is a mask for images[i].*/    void detect(const vector<Mat>& images,vector< vector<KeyPoint> >& keypoints,const vector<Mat>& masks=vector<Mat>()) const;    static Ptr<BlobDetector> create(const string& detectorName);    void blobTest();protected:    struct CV_EXPORTS Center    {        Point2d location;        double radius;        double confidence;    };    void detectImpl( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask=Mat() ) const;    void findBlobs(const cv::Mat &image, const cv::Mat &binaryImage, std::vector<Center> ¢ers) const;    Params params;};#endif // BLOB_H

/**源文件:类的实现*/#include "blob.h"/** BlobDetector*/BlobDetector::Params::Params(){    thresholdStep = 10;    minThreshold = 50;    maxThreshold = 220;    minRepeatability = 2;    minDistBetweenBlobs = 10;    filterByColor = true;    blobColor = 0;    filterByArea = true;    minArea = 25;    maxArea = 5000;    filterByCircularity = false;    minCircularity = 0.8f;    maxCircularity = std::numeric_limits<float>::max();    filterByInertia = true;    //minInertiaRatio = 0.6;    minInertiaRatio = 0.1f;    maxInertiaRatio = std::numeric_limits<float>::max();    filterByConvexity = true;    //minConvexity = 0.8;    minConvexity = 0.95f;    maxConvexity = std::numeric_limits<float>::max();}void BlobDetector::Params::read(const cv::FileNode& fn ){    thresholdStep = fn["thresholdStep"]; //getFileNodeByName,从文件中读取参数    minThreshold = fn["minThreshold"];    maxThreshold = fn["maxThreshold"];    minRepeatability = (size_t)(int)fn["minRepeatability"];    minDistBetweenBlobs = fn["minDistBetweenBlobs"];    filterByColor = (int)fn["filterByColor"] != 0 ? true : false;    blobColor = (uchar)(int)fn["blobColor"];    filterByArea = (int)fn["filterByArea"] != 0 ? true : false;    minArea = fn["minArea"];    maxArea = fn["maxArea"];    filterByCircularity = (int)fn["filterByCircularity"] != 0 ? true : false;    minCircularity = fn["minCircularity"];    maxCircularity = fn["maxCircularity"];    filterByInertia = (int)fn["filterByInertia"] != 0 ? true : false;    minInertiaRatio = fn["minInertiaRatio"];    maxInertiaRatio = fn["maxInertiaRatio"];    filterByConvexity = (int)fn["filterByConvexity"] != 0 ? true : false;    minConvexity = fn["minConvexity"];    maxConvexity = fn["maxConvexity"];}void BlobDetector::Params::write(cv::FileStorage& fs) const //储存参数{    fs << "thresholdStep" << thresholdStep;    fs << "minThreshold" << minThreshold;    fs << "maxThreshold" << maxThreshold;    fs << "minRepeatability" << (int)minRepeatability;    fs << "minDistBetweenBlobs" << minDistBetweenBlobs;    fs << "filterByColor" << (int)filterByColor;    fs << "blobColor" << (int)blobColor;    fs << "filterByArea" << (int)filterByArea;    fs << "minArea" << minArea;    fs << "maxArea" << maxArea;    fs << "filterByCircularity" << (int)filterByCircularity;    fs << "minCircularity" << minCircularity;    fs << "maxCircularity" << maxCircularity;    fs << "filterByInertia" << (int)filterByInertia;    fs << "minInertiaRatio" << minInertiaRatio;    fs << "maxInertiaRatio" << maxInertiaRatio;    fs << "filterByConvexity" << (int)filterByConvexity;    fs << "minConvexity" << minConvexity;    fs << "maxConvexity" << maxConvexity;}/**/BlobDetector::BlobDetector(const BlobDetector::Params ¶meters) : params(parameters){}void BlobDetector::read( const cv::FileNode& fn ){    params.read(fn);}void BlobDetector::write( cv::FileStorage& fs ) const{    params.write(fs);}/**先找出轮廓,再通过轮廓的距求出其圆心和半径*/void BlobDetector::findBlobs(const cv::Mat &image, const cv::Mat &binaryImage, vector<Center> ¢ers) const{    (void)image;    centers.clear();    vector < vector<Point> > contours;    Mat tmpBinaryImage = binaryImage.clone();    findContours(tmpBinaryImage, contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);//找轮廓#ifdef DEBUG_BLOB_DETECTOR// Mat keypointsImage;// cvtColor( binaryImage, keypointsImage, CV_GRAY2RGB );//// Mat contoursImage;// cvtColor( binaryImage, contoursImage, CV_GRAY2RGB );// drawContours( contoursImage, contours, -1, Scalar(0,255,0) );// imshow("contours", contoursImage );#endif    for (size_t contourIdx = 0; contourIdx < contours.size(); contourIdx++)    {        Center center;        center.confidence = 1;        Moments moms = moments(Mat(contours[contourIdx]));        //根据各种筛选模式筛选斑点        if (params.filterByArea)        {            double area = moms.m00;            if (area < params.minArea || area >= params.maxArea)            continue;        }        if (params.filterByCircularity)        {            double area = moms.m00;            double perimeter = arcLength(Mat(contours[contourIdx]), true);            double ratio = 4 * CV_PI * area / (perimeter * perimeter);            if (ratio < params.minCircularity || ratio >= params.maxCircularity)            continue;        }        if (params.filterByInertia)        {            double denominator = sqrt(pow(2 * moms.mu11, 2) + pow(moms.mu20 - moms.mu02, 2));            const double eps = 1e-2;            double ratio;            if (denominator > eps)            {                double cosmin = (moms.mu20 - moms.mu02) / denominator;                double sinmin = 2 * moms.mu11 / denominator;                double cosmax = -cosmin;                double sinmax = -sinmin;                double imin = 0.5 * (moms.mu20 + moms.mu02) - 0.5 * (moms.mu20 - moms.mu02) * cosmin - moms.mu11 * sinmin;                double imax = 0.5 * (moms.mu20 + moms.mu02) - 0.5 * (moms.mu20 - moms.mu02) * cosmax - moms.mu11 * sinmax;                ratio = imin / imax;            }            else            {                ratio = 1;            }            if (ratio < params.minInertiaRatio || ratio >= params.maxInertiaRatio)                continue;            center.confidence = ratio * ratio;        }        if (params.filterByConvexity)        {            vector < Point > hull;            convexHull(Mat(contours[contourIdx]), hull);            double area = contourArea(Mat(contours[contourIdx]));            double hullArea = contourArea(Mat(hull));            double ratio = area / hullArea;            if (ratio < params.minConvexity || ratio >= params.maxConvexity)                continue;        }        center.location = Point2d(moms.m10 / moms.m00, moms.m01 / moms.m00); //得出圆心坐标        if (params.filterByColor)        {            if (binaryImage.at<uchar> (cvRound(center.location.y), cvRound(center.location.x)) != params.blobColor)                continue;         }        //compute blob radius 计算半径        {            vector<double> dists;            for (size_t pointIdx = 0; pointIdx < contours[contourIdx].size(); pointIdx++)            {                Point2d pt = contours[contourIdx][pointIdx];                dists.push_back(norm(center.location - pt));            }            std::sort(dists.begin(), dists.end());            center.radius = (dists[(dists.size() - 1) / 2] + dists[dists.size() / 2]) / 2.;        }        centers.push_back(center);#ifdef DEBUG_BLOB_DETECTOR// circle( keypointsImage, center.location, 1, Scalar(0,0,255), 1 );#endif    }#ifdef DEBUG_BLOB_DETECTOR// imshow("bk", keypointsImage );// waitKey();#endif}void BlobDetector::detectImpl(const cv::Mat& image, std::vector<cv::KeyPoint>& keypoints, const cv::Mat&) const{    //TODO: support mask    keypoints.clear();    Mat grayscaleImage;    if (image.channels() == 3)        cvtColor(image, grayscaleImage, CV_BGR2GRAY);    else        grayscaleImage = image;    vector < vector<Center> > centers;    for (double thresh = params.minThreshold; thresh < params.maxThreshold; thresh += params.thresholdStep)    {        Mat binarizedImage;        threshold(grayscaleImage, binarizedImage, thresh, 255, THRESH_BINARY);#ifdef DEBUG_BLOB_DETECTOR// Mat keypointsImage;// cvtColor( binarizedImage, keypointsImage, CV_GRAY2RGB );#endif        vector < Center > curCenters;        findBlobs(grayscaleImage, binarizedImage, curCenters);        vector < vector<Center> > newCenters;        for (size_t i = 0; i < curCenters.size(); i++)        {#ifdef DEBUG_BLOB_DETECTOR// circle(keypointsImage, curCenters[i].location, curCenters[i].radius, Scalar(0,0,255),-1);#endif            bool isNew = true;            for (size_t j = 0; j < centers.size(); j++)            {                double dist = norm(centers[j][ centers[j].size() / 2 ].location - curCenters[i].location);                isNew = dist >= params.minDistBetweenBlobs && dist >= centers[j][ centers[j].size() / 2 ].radius && dist >=                                     curCenters[i].radius;                if (!isNew)                {                    centers[j].push_back(curCenters[i]);                    size_t k = centers[j].size() - 1;                    while( k > 0 && centers[j][k].radius < centers[j][k-1].radius )                    {                        centers[j][k] = centers[j][k-1];                        k--;                    }                    centers[j][k] = curCenters[i];                    break;                }            }            if (isNew)            {                newCenters.push_back(vector<Center> (1, curCenters[i]));//centers.push_back(vector<Center> (1, curCenters[i]));            }        }        std::copy(newCenters.begin(), newCenters.end(), std::back_inserter(centers));#ifdef DEBUG_BLOB_DETECTOR// imshow("binarized", keypointsImage );//waitKey();#endif    }    for (size_t i = 0; i < centers.size(); i++)    {        if (centers[i].size() < params.minRepeatability)        continue;        Point2d sumPoint(0, 0);        double normalizer = 0;        for (size_t j = 0; j < centers[i].size(); j++)        {            sumPoint += centers[i][j].confidence * centers[i][j].location;            normalizer += centers[i][j].confidence;        }        sumPoint *= (1. / normalizer);        KeyPoint kpt(sumPoint, (float)(centers[i][centers[i].size() / 2].radius));        keypoints.push_back(kpt);    }#ifdef DEBUG_BLOB_DETECTOR    namedWindow("keypoints", CV_WINDOW_NORMAL);    Mat outImg = image.clone();    for(size_t i=0; i<keypoints.size(); i++)    {        circle(outImg, keypoints[i].pt, keypoints[i].size, Scalar(255, 0, 255), -1);    }//drawKeypoints(image, keypoints, outImg);    imshow("keypoints", outImg);    waitKey();#endif}void BlobDetector::detect(const Mat &image, vector<KeyPoint> &keypoints, const Mat &mask) const{    keypoints.clear();    if( image.empty() )        return;    CV_Assert( mask.empty() || (mask.type() == CV_8UC1 && mask.size() == image.size()) );    detectImpl(image,keypoints,mask);}void BlobDetector::detect(const vector<Mat> &images, vector<vector<KeyPoint> > &keypoints, const vector<Mat> &masks) const{    keypoints.resize(images.size());    for( size_t i = 0; i< images.size(); i++ )        detect(images[i], keypoints[i], masks.empty()? Mat():masks[i]);}Ptr<BlobDetector> BlobDetector::create(const string &detectorName){    BlobDetector* fd = 0;    if( !detectorName.compare("Blob") )        fd = new BlobDetector();    return fd;}void BlobDetector::blobTest(){    cout << "----------blob debug-----------" << endl;    cout << params.thresholdStep << endl << params.minThreshold << endl << params.maxThreshold << endl                << params.minRepeatability << endl << params.minDistBetweenBlobs << endl                << params.minArea << endl;// VideoCapture camera(0); // video source for webcam// camera.set(CV_CAP_PROP_FRAME_WIDTH,640);// camera.set(CV_CAP_PROP_FRAME_HEIGHT,480);}

/**测试:采集摄像头,进行斑点检测*///测试blob工具,斑点检测// Initialize blob detectorBlobDetector::Params params;params.minThreshold = 40;params.maxThreshold = 60;params.thresholdStep = 5;params.minArea = 1000;params.minConvexity = .4f;params.minInertiaRatio = .1f;params.maxArea = 8000;params.maxConvexity = 2;params.filterByColor = false;params.filterByCircularity = false;BlobDetector blobDetector( params );blobDetector.create("Blob");vector<KeyPoint> keyPoints;blobDetector.blobTest();Mat blurImage; // blur imageMat hsvImage; // HSV imageMat hue; // hue channelMat hue1; // Hue upper boundMat hue2; // Hue lower boundMat hue3; // hue color filteringMat final; // Final display imagevector<Mat> slices;// Theshold Settingsint HuethresL = 30, HuethresH =71, blurSize = 1; //Greenfor(;;){camera->read(camImage);// blur imageblur(camImage, blurImage, Size(2,2));//imshow("blurImage", blurImage);// convert raw image to hsvcvtColor (camImage, hsvImage, CV_RGB2HSV);//imshow("hsvImage", hsvImage);blur(hsvImage, hsvImage, Size(3,3));//imshow("hsvImage blurImage", hsvImage);// split image to H,S and V imagessplit(hsvImage,slices);slices[0].copyTo(hue); // get the hue channelimshow("hue", hue);threshold (hue,hue1,HuethresL,255, CV_THRESH_BINARY); // get lower boundimshow("hue1", hue1);threshold (hue,hue2,HuethresH,255, CV_THRESH_BINARY_INV); // get upper boundimshow("hue2", hue2);hue3 = hue1 & hue2; // multiply to get color range//Just to show we can access the keyPoints array directly//You can also investigate the properties of the features to determine their _size_camImage.copyTo(final);blobDetector.detect(hue3, keyPoints);for(int i=0; i<keyPoints.size(); i++){circle(final, keyPoints[i].pt, 20, cvScalar(255,0,0), 10);}//Alternatively, there exists a simple function://drawKeypoints(camImage, keyPoints, final, CV_RGB(0,255,0), 4);// show imagesimshow("Webcam Orignal", camImage);imshow("Hue color",hue3);imshow("Final",final);if( cvWaitKey(10) >= 0 )break;}


0 0