Exemple #1
0
Bleb::Bleb(vector<Point> &bunch, Point2f &centroid, int &BIN)
{
    //bleb size
    size = bunch.size();

    //bleb center
    vector<Point> hull;
    convexHull(bunch, hull);
    Moments mu = moments(hull);
    Point2f blebCtr = Point2f(mu.m10/mu.m00, mu.m01/mu.m00);
    center.x = blebCtr.x;
    center.y = blebCtr.y;

    // bleb bunch in polar coordinates
    double theta = 0;
    for(unsigned int n = 0; n < bunch.size(); n++){
        polarPoint pt = cartesianToPolar1(bunch[n], centroid);
        bunch_polar.push_back(pt);
        theta += pt.theta;
    }
    theta /= bunch.size();
    bin = theta/(3.1415926*2/BIN)+BIN/2;


    // bleb bounding ellipse
    roughArea =  fitEllipse(Mat(bunch));

}
Exemple #2
0
void CvMSER::onNewImage()
{
    LOG(LTRACE) << "CvMSER::onNewImage\n";
	try {
		// img: a RGB image.
		cv::Mat img = in_img.read();
		cv::Mat yuv,gray;
		cvtColor(img,yuv, COLOR_BGR2YCrCb);
		cvtColor(img, gray, COLOR_BGR2GRAY);
		vector<vector<Point> > regions;
		cv::MSER ms;
		ms(img, regions, cv::Mat());
		for (int i = 0; i < regions.size(); i++)
		    {
		        ellipse(img, fitEllipse(regions[i]), Scalar(255));
		    }

		// Write contours to the output.
		out_contours.write(regions);
		out_img.write(img);

	} catch (...) {
        LOG(LERROR) << "CvMSER::onNewImage failed\n";
	}
}
void BallDetector::contourDetection()
{
    Canny(thrs,cannyImg, 50, 150, 3);
    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;
    findContours(cannyImg, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0,0));
    vector<RotatedRect> minRect(contours.size());
    vector<Point2f> center(contours.size());
    vector<float> radius(contours.size());
    for( size_t i = 0; i < contours.size(); i++)
    {
        if(contours[i].size() > 5)
            minRect[i] = fitEllipse(Mat(contours[i]));
        minEnclosingCircle(contours[i],center[i],radius[i]);
    }
    
    RNG rng(12345);
    Mat drawing = Mat::zeros(cannyImg.size(),CV_8UC3);
    for( size_t i = 0; i < contours.size(); i++)
    {
        Scalar color = Scalar(rng.uniform(0,255),rng.uniform(0,255),rng.uniform(0,255));
        Size2f s = minRect[i].size;
        Point2f c = minRect[i].center;
        if(contours[i].size() > 5 && s.width/s.height > 0.7 && s.width/s.height < 1.4 && s.width > 5 && s.height > 5)
            // && arcLength(contours[i],true)/(2*CV_PI*radius[i])>0.8 && arcLength(contours[i],true)/(2*CV_PI*radius[i]) < 1.2 )
        {
            drawContours(drawing, contours, (int)i, color, -1, 8, hierarchy, 0, Point());
            cout<<c.x<<" "<<c.y<<endl;
            cout<<s.width<<" "<<s.height<<endl<<endl;
        }
    }
    imshow("contours",drawing);
    imwrite("images/contours.png",drawing);
}
bool ManualLabeling::manualLabelingCallback(cwru_opencv_common::image_label::Request& request,
                                            cwru_opencv_common::image_label::Response& response) {
    // Put sensor_msgs::Image in cv::Mat
    const sensor_msgs::Image::Ptr &image = boost::make_shared<sensor_msgs::Image>(request.imageQuery);
    cv::Mat rawImageIn = cv_bridge::toCvShare(image, "bgr8")->image.clone();
    // Declare labeled image
    cv::Mat labeledImage;
    // Initialize blobs
    std::vector<cv::Mat> labeledBlobs;
    labeledBlobs.clear();
    // Apply adaptive threshold
    cv::Mat imgHSV;
    cv::cvtColor(rawImageIn, imgHSV, CV_BGR2HSV);
    // create a click window:
    cv::Point imagePt(-1, -1);
    cv::namedWindow("Selectable Points");
    cv::setMouseCallback("Selectable Points", cv_ui::getCoordinates, &imagePt);
    int imageCount(0);
    // fill the blobs.
    while (true) {
        int blobCount = (int) floor((double) imageCount / 2.0);
        int lr = imageCount % 2; // select the points from right side to left side
        imshow("Selectable Points", rawImageIn);

        char keyIn = cv::waitKey(50);

        if (imagePt.x > 0) {

            cv::Mat labeledBlob;
            labeledBlob = cv::Mat::zeros(rawImageIn.size(), CV_8UC1);

            ManualLabeling::growFromSeedRaw(rawImageIn, labeledBlob, imagePt);
            std::vector<std::vector<cv::Point2i> > contours;
            cv::Mat hierarchy;
            findContours(labeledBlob, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
            cv::RotatedRect newRect(fitEllipse(contours[0]));
            ROS_INFO("Finished point at index %d \n Image side %d \n next point.\n", blobCount, lr);
            labeledBlobs.push_back(labeledBlob);
            imageCount++;
            imagePt.x = -1;
        }
        // if the Esc key is pressed, break out.
        if (keyIn == 27) break;
    }
    cv::destroyWindow("Selectable Points");
    printf("Finished the catheter display image. \n");

    // Merge blob to label image
    if(labeledBlobs.size() > 0)
    {
        merge(labeledBlobs, labeledImage);
        cv_bridge::CvImage(std_msgs::Header(), "bgr8", labeledImage).toImageMsg(response.imageResp);
        return true;
    }
    else
        return false;
}
//--------------------------------------------------------------
void openniTracking::computeContourAnalysis(){

	for (unsigned int i = 0; i < contourFinder.nBlobs; i++){

		int length_of_contour = contourFinder.blobs[i].pts.size();

		// ellipse
		fitEllipse(contourFinder.blobs[i].pts, box[i]);

		// angles
		blobAngle[i] =  getOrientation(contourFinder.blobs[i].pts);

		// assign smoothed and normalized blobs geometry vectors vars
		if(computeContourGeometry){

			findLines(contourFinder.blobs[i].pts,geomLines[i],30,40,30);

			_s_blobGeom[i].clear();
			_s_blobGeom[i].assign(geomLines[i].size(), ofVec4f());
			_osc_blobGeom[i].clear();
			_osc_blobGeom[i].assign(geomLines[i].size(), ofVec4f());

		}

		// smoothed, simple and convexHull contours computing
		contourReg[i].clear();
		contourReg[i].assign(length_of_contour, ofVec2f());
		contourSmooth[i].clear();
		contourSmooth[i].assign(length_of_contour, ofVec2f());

		_s_contourSmooth[i].clear();
		_s_contourSmooth[i].assign(length_of_contour, ofVec2f());
		_osc_contourSmooth[i].clear();
		_osc_contourSmooth[i].assign(length_of_contour, ofVec2f());


		for(int j = 0; j < length_of_contour; j++){
			contourReg[i].at(j) = contourFinder.blobs[i].pts[j];
		}

		contourS.smooth(contourReg[i], contourSmooth[i], smoothPct);

		contourSimple[i].clear();
		contourS.simplify(contourSmooth[i], contourSimple[i], tolerance);

		_s_contourSimple[i].clear();
		_s_contourSimple[i].assign(contourSimple[i].size(), ofVec2f());
		_osc_contourSimple[i].clear();
		_osc_contourSimple[i].assign(contourSimple[i].size(), ofVec2f());

	}
}
Exemple #6
0
void MserFeatureDetector::detectImpl(const Mat& image, const Mat& mask, vector<KeyPoint>& keypoints) const {
    vector<vector<Point> > msers;
    mser(image, msers, mask);

    keypoints.resize(msers.size());
    vector<vector<Point> >::const_iterator contour_it = msers.begin();
    vector<KeyPoint>::iterator keypoint_it = keypoints.begin();
    for (; contour_it != msers.end(); ++contour_it, ++keypoint_it) {
        // TODO check transformation from MSER region to KeyPoint
        RotatedRect rect = fitEllipse(Mat(*contour_it));
        *keypoint_it = KeyPoint(rect.center, sqrt(rect.size.height * rect.size.width), rect.angle);
    }
}
Exemple #7
0
void ShapeFeature::compute(Mat& src)
{
    resultingImage = src;

    Mat channel[3];
    // The actual splitting.
    split(resultingImage, channel);

    channel[1].setTo(Scalar(0));

    Mat br;
    merge(channel,3,br);

    channel[0].setTo(Scalar(0));
    Mat r;
    merge(channel,3,r);

    cvtColor(r, r, CV_BGR2GRAY);
    medianBlur(r, r, 9 );
    equalizeHist(r, r);

    threshold(r, r, 120, 255, THRESH_BINARY);

    erode(r, r, Mat());
    dilate(r, r, Mat());




    vector< vector <Point> > contours; // Vector for storing contour
    vector< Vec4i > hierarchy;
    int largest_contour_index=0;
    int largest_area=0;
    findContours( r.clone(), contours, hierarchy,RETR_EXTERNAL, CHAIN_APPROX_SIMPLE ); // Find the contours in the image
    for( int i = 0; i< contours.size(); i++ ){
        double a=contourArea( contours[i],false);  //  Find the area of contour
        if(a>largest_area){
            largest_area=a;
            largest_contour_index=i;                //Store the index of largest contour
        }
    }

    Mat pointsf;
    Mat(contours[largest_contour_index]).convertTo(pointsf, CV_32F);
    RotatedRect boxE = fitEllipse(pointsf);
    if(boxE.size.width<boxE.size.height)
        value = (float)boxE.size.width/boxE.size.height;
    else
        value = (float)boxE.size.height/boxE.size.width;

}
Exemple #8
0
Mat Draw::drawMSERs(const Mat& src, const vector<vector<Point> >& mser_features)
{
    Mat dst = Mat::zeros(src.rows, src.cols, CV_8UC3);
    for (int i = 0; i < mser_features.size(); i++)
    {
        Scalar color = CV_RGB( rand()&255, rand()&255, rand()&255 );
        for (int j = 0; j < mser_features[i].size(); j++)
        {
            circle(dst, mser_features[i][j], 1, color);
        }
        ellipse(dst, fitEllipse(mser_features[i]), CV_RGB(255, 0, 0));
    }
    
    return dst;
}
Exemple #9
0
RotatedRect createArenaMask(float x_rad, float y_rad, Mat cameraMatrix, Mat distCoeffs, Mat rvec, Mat tvec)
{
	Point2f center(0, 0);

	Point3f ellipsePath;

	vector<Point3f> c3d;
	vector<Point2f> c2d;

	RotatedRect ellipseMask;

	for (double angle = 0; angle <= 2 * CV_PI; angle += 0.001) //You are using radians so you will have to increase by a very small amount
	{
		if ( (angle >= 0 && angle < 90) || (angle > 270 && angle <= 360) )
		{
			ellipsePath.x = (x_rad*y_rad) / (sqrt((y_rad*y_rad) + x_rad*x_rad*tan(angle)*tan(angle)));
			ellipsePath.y = (x_rad*y_rad*tan(angle)) / (sqrt((y_rad*y_rad) + x_rad*x_rad*tan(angle)*tan(angle)));
			ellipsePath.z = BASE_HEIGHT;

			c3d.push_back(ellipsePath);
		}

		if (angle > 90 && angle < 270)
		{
			ellipsePath.x = -(x_rad*y_rad) / (sqrt((y_rad*y_rad) + x_rad*x_rad*tan(angle)*tan(angle)));
			ellipsePath.y = -(x_rad*y_rad*tan(angle)) / (sqrt((y_rad*y_rad) + x_rad*x_rad*tan(angle)*tan(angle)));
			ellipsePath.z = BASE_HEIGHT;

			c3d.push_back(ellipsePath);
		}
	}

	projectPoints(c3d, rvec, tvec, cameraMatrix, distCoeffs, c2d);

	ellipseMask = fitEllipse(c2d);

	return ellipseMask;
}
Exemple #10
0
	cv::RotatedRect fitEllipse(const ofPolyline& polyline) {
		return fitEllipse(Mat(toCv(polyline)));
	}
Exemple #11
0
TargetDetector::targetPanel TargetDetector::getSquareBlob(Mat erosion_dst, Mat img_whitebalance, Color::ColorType color )
{
	//perform blob detection for a square
	//for now only do blob detection based on area


	  logger.infoStream() << " Finding Contours, Entered getSquareBlob";
	
	  vector<vector<Point> > contours;
	  vector<Vec4i> hierarchy;

	  /// Find contours
	  findContours(erosion_dst, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );

	  /// Draw contours
	  //Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 );
	 
	  for( unsigned int i = 0; i< contours.size(); i++ )
	  {
		if ((int)contours[i].size() > m_minContourSize)
		{
			if (color == Color::RED)
		     	 drawContours(img_whitebalance, contours, i, Scalar(0,0,255), 2, 8, hierarchy, 0, Point() );
			else if (color == Color::GREEN)
		     	 drawContours(img_whitebalance, contours, i, Scalar(0,255,0), 2, 8, hierarchy, 0, Point() );
			else if (color == Color::YELLOW)
		     	 drawContours(img_whitebalance, contours, i, Scalar(0,255,255), 2, 8, hierarchy, 0, Point() );
			else if (color == Color::BLUE)
		     	 drawContours(img_whitebalance, contours, i, Scalar(255,0,0), 2, 8, hierarchy, 0, Point() );
			else 
		     	 drawContours(img_whitebalance, contours, i, Scalar(255,255,0), 2, 8, hierarchy, 0, Point() );
		}
	     }


	//find contour with the largest area- by area I mean number of pixels
	double maxArea = 0;
	unsigned int maxContour=0;
	RotatedRect temp,maxtemp;
	//targetSmall and targetLarge are within the maxSize contour
	double area=0.0;
	double aspectratio=0;
	//printf("\n number of contours: %d",contours.size());
	for(unsigned int j=0; j<contours.size(); j++)
	{
	        if (contours[j].size() > 6)
		{
			temp = minAreaRect(contours[j]); //finds the rectangle that will encompass all the points
			area = temp.size.width*temp.size.height;
			aspectratio = temp.size.height/temp.size.width;
			if (area > maxArea && aspectratio < m_maxAspectRatio && aspectratio > m_minAspectRatio)
			{	maxContour = j;
				maxtemp = temp;
				maxArea = area;
			}
		}
		
		//printf("\n size %d, width %f, height %f area = %f", contours[j].size(), temp.size.width,temp.size.height,area);
	};


	  logger.infoStream() << " Max contour area " <<maxArea <<" at " <<maxContour;
	targetPanel answer;
	//printf("\n area = %f, maxsize = %d",area,maxsize);
	if (maxArea < 5)
	{
		//unable to find any contours
		answer.foundLarge = false;
		answer.foundSmall = false;
		answer.foundOutline = false;
		logger.infoStream() << " Unable to find Contours with an area more than 5" ;
		
		return(answer);
	
	}
	else	
	{
		answer.foundOutline = true;
		logger.infoStream() << "Contours FOund with maxSize = "<<maxContour <<" with area : "<<maxArea;
		Point2f vertices[4];
		maxtemp.points(vertices);
		//given the vertices find the min and max X and min and maxY
		double minX= 90000;
		double maxX = 0;
		double minY= 90000;
		double maxY=0;	
		for (int i = 0; i < 4; i++)
		{
			//printf("\n verticle = (%f, %f)",vertices[i].x, vertices[i].y);
			if (vertices[i].x < minX)
				minX = vertices[i].x;
			if (vertices[i].x > maxX)
				maxX = vertices[i].x;
			if (vertices[i].y < minY)
				minY = vertices[i].y;
			if (vertices[i].y > maxY)
				maxY = vertices[i].y;
		};

	
		RotatedRect minEllipse;
		RotatedRect targetLarge;
		RotatedRect targetSmall;
		double targetLargeArea = 0;
		double targetSmallArea = 0;
		for(unsigned int j=0; j<contours.size(); j++)
		{
			if (j != maxContour && (int(contours[j].size()) > m_minSize))
			{
		     		//make sure the center of the next contour is within the bouding area
				//have the center, height and width
				minEllipse = fitEllipse( Mat(contours[j])); //finds the rectangle that will encompass all the points
				//printf("\n center = (%f,%f), Xrange = %f,%f, Yrange = %f,%f",minEllipse.center.x,minEllipse.center.y,minX,maxX,minY,maxY);
				if (minEllipse.center.x > minX && minEllipse.center.x < maxX && minEllipse.center.y < maxY && minEllipse.center.y >minY)
				{
					//in the middle, therefore save
					//should also be roughly circular - width should be about equal to height
					aspectratio = minEllipse.size.height/minEllipse.size.width;
					if (minEllipse.size.height*minEllipse.size.width > targetLargeArea)// && aspectratio < m_maxAspectRatio && aspectratio > m_minAspectRatio)
					{	
						//before we go over the large one, save the previous large one to the small one
						targetSmall = targetLarge;
						targetSmallArea = targetLargeArea;
						targetLarge = minEllipse;
						targetLargeArea = minEllipse.size.height*minEllipse.size.width;
					}
					else if (minEllipse.size.height*minEllipse.size.width > targetSmallArea)
					{
						targetSmall = minEllipse;
						targetSmallArea = minEllipse.size.height*minEllipse.size.width;
					}

				}//end if in the center
			} //end if j!=maxcounter
		};


			logger.infoStream() << " TargetLareArea = " <<targetLargeArea <<" Small Area "<<targetSmallArea;
		//imshow("internal",img_whitebalance);

		//Display Purposes
	
	
		maxtemp.points(vertices);
		for (int i = 0; i < 4; i++)
		{

			if (color == Color::RED)
			{
			 line(img_whitebalance, vertices[i], vertices[(i+1)%4], Scalar(0,0,255),12);
			}
			else if (color == Color::GREEN)
			{
				 line(img_whitebalance, vertices[i], vertices[(i+1)%4], Scalar(0,255,0),12);
			}
			else if (color == Color::BLUE)
			{
			 line(img_whitebalance, vertices[i], vertices[(i+1)%4], Scalar(255,0,0),12);
			}
			else if (color == Color::YELLOW)
			{
			 line(img_whitebalance, vertices[i], vertices[(i+1)%4], Scalar(0,255,255),12);
			}
			else 
			{
			 line(img_whitebalance, vertices[i], vertices[(i+1)%4], Scalar(255,255,0),12);
			}
		}
	 
	
		if (targetLargeArea > 0)
			answer.foundLarge = true;
		else
			answer.foundLarge = false;

		if (targetSmallArea > 0)
			answer.foundSmall = true;
		else
			answer.foundSmall = false;
	
		answer.outline = maxtemp;
		answer.targetSmall = targetSmall;
		answer.targetLarge = targetLarge;

		logger.infoStream() << "Sending data: found outline = " <<answer.foundOutline <<" TargetLarge "<<answer.foundLarge << "Target Smaller "<< answer.foundSmall;
		return(answer);
	}//end able to find contours
		answer.foundLarge = false;
		answer.foundSmall = false;
		answer.foundOutline = false;
	return(answer);
};
Exemple #12
0
/*******************************************************************************
* Function:      extractFGTargets  
* Description:   extract FG targets with given conditions and return objects
* Arguments:
	inImg           -   input image
	fgImg           -   output FG mask image
	seLength        -   length of structuring elements (opening)
	threshVal       -   threshold value for converting to binary image
	minArea         -   minimum area of FG targets
	maxArea         -   maximum area of FG targets
	minAspRatio     -   minimum aspect ratio of FG targets
	maxAspRatio     -   maximum aspect ratio of FG targets
	
* Returns:       vector<FGObject>* - all extracted FG targets
* Comments:
* Revision: 
*******************************************************************************/
vector<FGObject>*
FGExtraction::extractFGTargets(InputArray inImg, OutputArray fgImg, int seLength, int threshVal, 
                                   double minArea, double maxArea, 
								   double minAspRatio, double maxAspRatio)
{
	double theta = 0.4;

	if(!inImg.obj) return NULL;

	_inImg = inImg.getMat();
	this->init();

	//showImage("inImg", _inImg);

	// background subtraction by opening
    int err = subtractBGOpenDiagonal(inImg, _bgsImg, threshVal, seLength);

	if (err>0) {
		vector<FGObject>* fgObjects = new vector<FGObject>;
		return fgObjects;
	}

	//subtractBGMedian(inImg.getMat(), bgSubImg, threshVal, seLength);
	//showImage("inImg", _inImg, 0, 1);
	//showImage("bgSub", _bgsImg);
	
    // get the contour
    vector<vector<Point>> contours = extractContours(_bgsImg);
	//cout<<contours.size()<<endl;

    // double local thresholding
    // histogram backprojection
    Mat mask = Mat::zeros(_bgsImg.size(), CV_8U); 
	vector<int> areas(contours.size());
	int cnt = 0;
	int argMax = 0;
	int max_area = 0;
    for(vector<vector<Point> >::const_iterator it = contours.begin(); it != contours.end(); ++it){
        Rect uprightBox = boundingRect(*it);
		areas[cnt] = uprightBox.height*uprightBox.width;
		if (areas[cnt]>max_area) {
			max_area = areas[cnt];
			argMax = cnt;
		}
		cnt++;
	}
	//showImage("inImg", _inImg, 0, 1);

	vector<Point> largestContour = contours[argMax];	//***** only use the largest contour
		RotatedRect orientedBox = orientedBoundingBox(largestContour);
		orientedBox.size.width *= 1.5;
        orientedBox.size.height *= 1.5;
		ellipse(mask, orientedBox, Scalar(255), -1);

		//Rect tempRect = boundingRect(largestContour);
		//Mat tempImg = mask(tempRect);
		//imshow("tempImg", tempImg);
		//imshow("mask", mask);
		//waitKey(0);

		// double local thresholding
		double percentage = 0.8;
		doubleThresholdByValue(percentage, mask);
		
		/*finish = clock();
		duration = (double)(finish - start) / (double)CLOCKS_PER_SEC;
		cout << duration << " sec" << endl;
		start = clock();*/

		// remove noise by a median filter
		medianBlur(_fgHighImg, _fgHighImg, 3);
		medianBlur(_fgLowImg, _fgLowImg, 3);
		//showImage("_fgHighImg", _fgHighImg);
		//showImage("_fgLowImg", _fgLowImg);

		/*finish = clock();
		duration = (double)(finish - start) / (double)CLOCKS_PER_SEC;
		cout << duration << " sec" << endl;
		
		start = clock();*/
		// merge two masks using histogram backprojection
		//showImage("_fgImg", _fgImg);
		//showImage("mask", mask);
		updateByHistBackproject(theta, mask);
		

		ellipse(mask, orientedBox, Scalar(0), -1);
		ellipse(_fgHighImg, orientedBox, Scalar(0), -1);
		ellipse(_fgLowImg, orientedBox, Scalar(0), -1);

    //}

	
    // thresholding by area and variance
#ifdef IMAGE_DOWNSAMPLING
	int dilateSESize = 3;
	int erodeSESize = 3;
	int varThresh = 30;
#else
	int dilateSESize = 7;
	int erodeSESize = 7;
	int varThresh = 30;
#endif

    //showImage("fg high", _fgHighImg, 0, 1);
    //showImage("fg low", _fgLowImg, 0, 1);
	//showImage("after histbp", _fgImg, 0);

	thresholdByAreaRatioVar(minArea, maxArea, dilateSESize, erodeSESize, minAspRatio, maxAspRatio, varThresh);
	
	//showImage("after area threshold", _fgImg, 0);

	// post-processing
    postProcessing(_fgImg, _fgImg);
	//imshow("_fgImg",_fgImg);
	//waitKey(0);

	// fill the holes of the fgImg
	_fgImg.copyTo(fgImg);
	floodFill(fgImg, cv::Point(0,0), Scalar(255));
	//imshow("fgImg",fgImg);
	//waitKey(0);

    bitwise_not(fgImg, fgImg);
	bitwise_or(fgImg, _fgImg, _fgImg);
	//imshow("inImg", inImg);
	//imshow("_fgImg",_fgImg);
	//waitKey(0);

	// opening
	RotatedRect rotatedR = fitEllipse(Mat(largestContour));
	float objHeight = min(rotatedR.size.height,rotatedR.size.width);
	int seSize = int(objHeight/10.0+0.5);
	
	Mat se = getStructuringElement(MORPH_ELLIPSE, Size(seSize, seSize));		//***** choose different size according to object height
	morphologyEx(_fgImg, _fgImg, MORPH_OPEN, se);

	//imshow("_fgImg",_fgImg);
	//waitKey(0);


	// close
	morphologyEx(_fgImg, _fgImg, MORPH_CLOSE, se);

	// timer
	/*clock_t start, finish;
	double duration = 0.0;
	start = clock();

	finish = clock();
	duration = (double)(finish - start) / (double)CLOCKS_PER_SEC;
	cout << duration << " sec" << endl;*/

	thresholdByAreaRatioVar(0.5*minArea, maxArea, 1, 1, minAspRatio, maxAspRatio, 30);

	// push targets into our vector
	//Mat largeInImg;
#ifdef IMAGE_DOWNSAMPLING
	resize(_fgImg, _fgImg, Size(), 2, 2, INTER_LINEAR);
	resize(_inImg, largeInImg, Size(), 2, 2, INTER_LINEAR);
#endif
	//tempImg = _fgImg.clone(); 
	//findContours(tempImg, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
	//tempImg.release();

	//imshow("_fgImg",_fgImg);
	//waitKey(0);
	contours = extractContours(_fgImg);

	vector<FGObject>* fgObjects = new vector<FGObject>;
	//Mat mask8U = Mat::zeros(largeInImg.size(), CV_8U); 
	for (size_t i = 0; i < contours.size(); i++){
		double area = contourArea(contours[i]);
		RotatedRect orientedRect = orientedBoundingBox(contours[i]);
		Point2f points[4];
		orientedRect.points(points);
		/*
		orientedRect.size.width *= 1.5;
        orientedRect.size.height *= 1.5;
		ellipse(mask8U, orientedRect, Scalar(255), -1);
		
		int channels[] = {0};
		int nbins = 16;
		const int histSize[] = {nbins};
		float range[] = {0, 255};
		const float* ranges[] = {range};
		Mat hist;
		cv::calcHist(&largeInImg, 1, channels, mask8U, hist, 1, histSize, ranges);
		*/
		// push targets into our vector
		FGObject* obj = new FGObject;
		//obj->histogram = hist;
		obj->setObjectProperties(area, orientedRect.angle, contours[i], points, SOURCE_UNRECTIFIED);

		if(obj->isPartialOut(_fgImg.cols, _fgImg.rows) == false){
			fgObjects->push_back(*obj);
		}
		delete obj;

		//ellipse(mask8U, orientedRect, Scalar(0), -1);
		
	}

	//  eliminate artifacts with width of 1 at the border...
	rectangle(_fgImg, Point(0,0), Point(_fgImg.cols-1, _fgImg.rows-1), Scalar(0));
	
	fgImg.getMatRef() = _fgImg.clone();
	return fgObjects;
}
//majorAxis and minorAxis is the estimated particle size in px
void ProgSortByStatistics::processInprocessInputPrepareSPTH(MetaData &SF, bool trained)
{
    //#define DEBUG
    PCAMahalanobisAnalyzer tempPcaAnalyzer0;
    PCAMahalanobisAnalyzer tempPcaAnalyzer1;
    PCAMahalanobisAnalyzer tempPcaAnalyzer2;
    PCAMahalanobisAnalyzer tempPcaAnalyzer3;
    PCAMahalanobisAnalyzer tempPcaAnalyzer4;

    //Morphology
    tempPcaAnalyzer0.clear();
    //Signal to noise ratio
    tempPcaAnalyzer1.clear();
    tempPcaAnalyzer2.clear();
    tempPcaAnalyzer3.clear();
    //Histogram analysis, to detect black points and saturated parts
    tempPcaAnalyzer4.clear();

    double sign = 1;//;-1;
    int numNorm = 3;
    int numDescriptors0=numNorm;
    int numDescriptors2=4;
    int numDescriptors3=11;
    int numDescriptors4 = 10;

    MultidimArray<float> v0(numDescriptors0);
    MultidimArray<float> v2(numDescriptors2);
    MultidimArray<float> v3(numDescriptors3);
    MultidimArray<float> v4(numDescriptors4);

    if (verbose>0)
    {
        std::cout << " Sorting particle set by new xmipp method..." << std::endl;
    }

    int nr_imgs = SF.size();
    if (verbose>0)
        init_progress_bar(nr_imgs);

    int c = XMIPP_MAX(1, nr_imgs / 60);
    int imgno = 0, imgnoPCA=0;

    bool thereIsEnable=SF.containsLabel(MDL_ENABLED);
    bool first=true;

    // We assume that at least there is one particle
    size_t Xdim, Ydim, Zdim, Ndim;
    getImageSize(SF,Xdim,Ydim,Zdim,Ndim);

    //Initialization:
    MultidimArray<double> nI, modI, tempI, tempM, ROI;
    MultidimArray<bool> mask;
    nI.resizeNoCopy(Ydim,Xdim);
    modI.resizeNoCopy(Ydim,Xdim);
    tempI.resizeNoCopy(Ydim,Xdim);
    tempM.resizeNoCopy(Ydim,Xdim);
    mask.resizeNoCopy(Ydim,Xdim);
    mask.initConstant(true);

    MultidimArray<double> autoCorr(2*Ydim,2*Xdim);
    MultidimArray<double> smallAutoCorr;

    Histogram1D hist;
    Matrix2D<double> U,V,temp;
    Matrix1D<double> D;

    MultidimArray<int> radial_count;
    MultidimArray<double> radial_avg;
    Matrix1D<int> center(2);
    MultidimArray<int> distance;
    int dim;
    center.initZeros();

    v0.initZeros(numDescriptors0);
    v2.initZeros(numDescriptors2);
    v3.initZeros(numDescriptors3);
    v4.initZeros(numDescriptors4);

    ROI.resizeNoCopy(Ydim,Xdim);
    ROI.setXmippOrigin();
    FOR_ALL_ELEMENTS_IN_ARRAY2D(ROI)
    {
        double temp = std::sqrt(i*i+j*j);
        if ( temp < (Xdim/2))
            A2D_ELEM(ROI,i,j)= 1;
        else
            A2D_ELEM(ROI,i,j)= 0;
    }

    Image<double> img;
    FourierTransformer transformer(FFTW_BACKWARD);

    FOR_ALL_OBJECTS_IN_METADATA(SF)
    {
        if (thereIsEnable)
        {
            int enabled;
            SF.getValue(MDL_ENABLED,enabled,__iter.objId);
            if ( (enabled==-1)  )
            {
                imgno++;
                continue;
            }
        }

        img.readApplyGeo(SF,__iter.objId);
        if (targetXdim!=-1 && targetXdim!=XSIZE(img()))
        	selfScaleToSize(LINEAR,img(),targetXdim,targetXdim,1);

        MultidimArray<double> &mI=img();
        mI.setXmippOrigin();
        mI.statisticsAdjust(0,1);
        mask.setXmippOrigin();
        //The size of v1 depends on the image size and must be declared here
        int numDescriptors1 = XSIZE(mI)/2; //=100;
        MultidimArray<float> v1(numDescriptors1);
        v1.initZeros(numDescriptors1);

        double var = 1;
        normalize(transformer,mI,tempI,modI,0,var,mask);
        modI.setXmippOrigin();
        tempI.setXmippOrigin();
        nI = sign*tempI*(modI*modI);
        tempM = (modI*modI);

        A1D_ELEM(v0,0) = (tempM*ROI).sum();
        int index = 1;
        var+=2;
        while (index < numNorm)
        {
            normalize(transformer,mI,tempI,modI,0,var,mask);
            modI.setXmippOrigin();
            tempI.setXmippOrigin();
            nI += sign*tempI*(modI*modI);
            tempM += (modI*modI);
            A1D_ELEM(v0,index) = (tempM*ROI).sum();
            index++;
            var+=2;
        }

        nI /= tempM;
        tempPcaAnalyzer0.addVector(v0);
        nI=(nI*ROI);

        auto_correlation_matrix(mI,autoCorr);
        if (first)
        {
            radialAveragePrecomputeDistance(autoCorr, center, distance, dim);
            first=false;
        }
        fastRadialAverage(autoCorr, distance, dim, radial_avg, radial_count);

        for (int n = 0; n < numDescriptors1; ++n)
            A1D_ELEM(v1,n)=(float)DIRECT_A1D_ELEM(radial_avg,n);

        tempPcaAnalyzer1.addVector(v1);

#ifdef DEBUG

        //String name = "000005@Images/Extracted/run_002/extra/BPV_1386.stk";
        String name = "000010@Images/Extracted/run_001/extra/KLH_Dataset_I_Training_0028.stk";
        //String name = "001160@Images/Extracted/run_001/DefaultFamily5";

        std::cout << img.name() << std::endl;

        if (img.name()==name2)
        {
            FileName fpName    = "test_1.txt";
            mI.write(fpName);
            fpName    = "test_2.txt";
            nI.write(fpName);
            fpName    = "test_3.txt";
            tempM.write(fpName);
            fpName    = "test_4.txt";
            ROI.write(fpName);
            //exit(1);
        }
#endif
        nI.binarize(0);
        int im = labelImage2D(nI,nI,8);
        compute_hist(nI, hist, 0, im, im+1);
        size_t l;
        int k,i,j;
        hist.maxIndex(l,k,i,j);
        A1D_ELEM(hist,j)=0;
        hist.maxIndex(l,k,i,j);
        nI.binarizeRange(j-1,j+1);

        double x0=0,y0=0,majorAxis=0,minorAxis=0,ellipAng=0;
        size_t area=0;
        fitEllipse(nI,x0,y0,majorAxis,minorAxis,ellipAng,area);

        A1D_ELEM(v2,0)=majorAxis/((img().xdim) );
        A1D_ELEM(v2,1)=minorAxis/((img().xdim) );
        A1D_ELEM(v2,2)= (fabs((img().xdim)/2-x0)+fabs((img().ydim)/2-y0))/((img().xdim)/2);
        A1D_ELEM(v2,3)=area/( (double)((img().xdim)/2)*((img().ydim)/2) );

        for (int n=0 ; n < numDescriptors2 ; n++)
        {
            if ( std::isnan(std::abs(A1D_ELEM(v2,n))))
                A1D_ELEM(v2,n)=0;
        }

        tempPcaAnalyzer2.addVector(v2);

        //mI.setXmippOrigin();
        //auto_correlation_matrix(mI*ROI,autoCorr);
        //auto_correlation_matrix(nI,autoCorr);
        autoCorr.window(smallAutoCorr,-5,-5, 5, 5);
        smallAutoCorr.copy(temp);
        svdcmp(temp,U,D,V);

        for (int n = 0; n < numDescriptors3; ++n)
            A1D_ELEM(v3,n)=(float)VEC_ELEM(D,n); //A1D_ELEM(v3,n)=(float)VEC_ELEM(D,n)/VEC_ELEM(D,0);

        tempPcaAnalyzer3.addVector(v3);


        double minVal=0.;
        double maxVal=0.;
        mI.computeDoubleMinMax(minVal,maxVal);
        compute_hist(mI, hist, minVal, maxVal, 100);

        for (int n=0 ; n <= numDescriptors4-1 ; n++)
        {
            A1D_ELEM(v4,n)= (hist.percentil((n+1)*10));
        }
        tempPcaAnalyzer4.addVector(v4);

#ifdef DEBUG

        if (img.name()==name1)
        {
            FileName fpName    = "test.txt";
            mI.write(fpName);
            fpName    = "test3.txt";
            nI.write(fpName);
        }
#endif
        imgno++;
        imgnoPCA++;

        if (imgno % c == 0 && verbose>0)
            progress_bar(imgno);
    }

    tempPcaAnalyzer0.evaluateZScore(2,20,trained);
    tempPcaAnalyzer1.evaluateZScore(2,20,trained);
    tempPcaAnalyzer2.evaluateZScore(2,20,trained);
    tempPcaAnalyzer3.evaluateZScore(2,20,trained);
    tempPcaAnalyzer4.evaluateZScore(2,20,trained);

    pcaAnalyzer.push_back(tempPcaAnalyzer0);
    pcaAnalyzer.push_back(tempPcaAnalyzer1);
    pcaAnalyzer.push_back(tempPcaAnalyzer1);
    pcaAnalyzer.push_back(tempPcaAnalyzer3);
    pcaAnalyzer.push_back(tempPcaAnalyzer4);

}