Beispiel #1
0
void PAN::rotate(Mat image){
	//namedWindow("", WINDOW_NORMAL);
	//imshow("", image);
	//waitKey();
	//namedWindow("", WINDOW_NORMAL);
	//imshow("", *panimage.img);
	//waitKey();
	cvtColor(image,image, CV_BGR2GRAY);
	Mat part1(image, Rect(Point((image.cols / 2) - 5, image.rows), Point(image.cols / 2, image.rows)));
	Mat part2(image, Rect(Point(image.cols - 5, 0), Point(image.cols, image.rows)));
	adaptiveThreshold(part1, part1, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY,3, 11);
	adaptiveThreshold(part1, part1, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 3, 11);
	PAN::Image temp1(&part1, 0, part1.cols, 0, part1.rows, Point(0, 0));
	PAN::Image temp2(&part2, 0, part2.cols, 0, part2.rows, Point(0, 0));
	
	cout << "here";
	namedWindow("o", WINDOW_NORMAL);
	imshow("o", *temp1.img);
	waitKey();
	imshow("o", *temp2.img);
	waitKey();



	
	
		
}
Mat prepare(Mat input, int blockSize, double C ){
    //Mat gray = convertToGray(input);
    Mat gray = input;
    Mat bw;
    
    adaptiveThreshold(~gray, bw, 255, CV_ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, blockSize, C);
    
    
    Mat horizontal = getHorizontal(bw);
    Mat vertical = getVertical(bw);
    
    
    
    Mat edges;
    adaptiveThreshold(horizontal, edges, 255, CV_ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 3, -2);
    
    Mat kernel = Mat::ones(2, 2, CV_8UC1);
    dilate(edges, edges, kernel);
    
    Mat smooth;
    vertical.copyTo(smooth);
    
    blur(smooth, smooth, Size(2, 2));
    
    smooth.copyTo(horizontal, edges);
    return horizontal;
}
Beispiel #3
0
//! choose the bese threshold method for chinese
void CCharsSegment::judgeChinese(Mat in, Mat& out, Color plateType) {
  
  Mat auxRoi = in;
  float valOstu = -1.f, valAdap = -1.f;
  Mat roiOstu, roiAdap;
  bool isChinese = true;
  if (1) {
    if (BLUE == plateType) {
      threshold(auxRoi, roiOstu, 0, 255, CV_THRESH_BINARY + CV_THRESH_OTSU);
    }
    else if (YELLOW == plateType) {
      threshold(auxRoi, roiOstu, 0, 255, CV_THRESH_BINARY_INV + CV_THRESH_OTSU);
    }
    else if (WHITE == plateType) {
      threshold(auxRoi, roiOstu, 0, 255, CV_THRESH_BINARY_INV + CV_THRESH_OTSU);
    }
    else {
      threshold(auxRoi, roiOstu, 0, 255, CV_THRESH_OTSU + CV_THRESH_BINARY);
    }
    roiOstu = preprocessChar(roiOstu);
    if (0) {
      imshow("roiOstu", roiOstu);
      waitKey(0);
      destroyWindow("roiOstu");
    }
    auto character = CharsIdentify::instance()->identifyChinese(roiOstu, valOstu, isChinese);
  }
  if (1) {
    if (BLUE == plateType) {
      adaptiveThreshold(auxRoi, roiAdap, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 3, 0);
    }
    else if (YELLOW == plateType) {
      adaptiveThreshold(auxRoi, roiAdap, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV, 3, 0);
    }
    else if (WHITE == plateType) {
      adaptiveThreshold(auxRoi, roiAdap, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV, 3, 0);
    }
    else {
      adaptiveThreshold(auxRoi, roiAdap, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 3, 0);
    }
    roiAdap = preprocessChar(roiAdap);
    auto character = CharsIdentify::instance()->identifyChinese(roiAdap, valAdap, isChinese);
  }

  std::cout << "valOstu: " << valOstu << std::endl;
  std::cout << "valAdap: " << valAdap << std::endl;

  if (valOstu >= valAdap) {
    out = roiOstu;
  }
  else {
    out = roiAdap;
  }

}
Beispiel #4
0
	/* 提取runlength 特征*/
	void RunLength::Dorunlength(float* feature){
		
		img_resize();
		/* 二值化 */
		adaptiveThreshold(image_resize, image_binary, 255, CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY, 31, 15);

		Mat _Pyramid = Mat(1, 4, CV_32F);
		Mat coords = Mat(1, 4, CV_32F);

		for (int i = 0; i < Pyramid.rows; i++){

			_Pyramid = Pyramid(Rect(0, i, 4, 1));
			

			coords = _Pyramid.mul(width_height);
			
			int x1 = (int)coords.at<float>(0, 0);
			int x2 = (int)coords.at<float>(0, 1);
			int y1 = (int)coords.at<float>(0, 2);
			int y2 = (int)coords.at<float>(0, 3);
			Mat test = image_binary(Range(y1, y2), Range(x1, x2));

			runlength_encoding(test, &feature[72 * i]);
		}

	}
/*
 * converts the src-image into a gray image with enhanced edges
 * and a bw-image via the adaptive-threshold method
 */
void prepareSrc(const Mat& src, Mat& bw_thresh, Mat& gray) {
	cvtColor(src, gray, CV_BGR2GRAY);

	///blurring was used prior the canny filter
//	blur(gray, canny_output, Size(3, 3));

	//invert the image !
	gray = ~gray;

	//earlier attempt with the canny filter
//	Canny(gray, canny_output, 50, 150, 3);
//	namedWindow("Canny", CV_WINDOW_AUTOSIZE);
//	imshow("Canny", canny_output);

//resizing is an option if the src image is too big for the screen display
//	resize(src, src, blank.size());

//	namedWindow(skel_window, CV_WINDOW_AUTOSIZE);

	adaptiveThreshold(gray, bw_thresh, 255, CV_ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 15, -8);

	//other ideas to use the canny filter to enhance edges
//	gray += ~gray;
//	gray /= 2;
//	gray += .4 * canny_output;

	gray += .4 * bw_thresh;

}
void CvAdaptiveThreshold_Processor::onNewImage()
{
	Mat image = in_img.read();

	int aM = 0;
	if (method() == "ADAPTIVE_THRESH_MEAN_C") {
		aM = ADAPTIVE_THRESH_MEAN_C;
	} else if (method() == "ADAPTIVE_THRESH_GAUSSIAN_C") {
		aM = ADAPTIVE_THRESH_GAUSSIAN_C;
	} else {
		LOG(LFATAL) << name() << ": CvAdaptiveThreshold_Processor: adaptiveMethod is wrong (" << method() << ")";
	}

	int tT = 0;
	if (thresholdType() == "THRESH_BINARY") {
		tT = THRESH_BINARY;
	} else if (thresholdType() == "THRESH_BINARY_INV") {
		tT = THRESH_BINARY_INV;
	} else {
		LOG(LFATAL) << name() << ": CvAdaptiveThreshold_Processor: thresholdType is wrong (" << thresholdType()
				<< ")";
	}

	adaptiveThreshold(image, thresholdedImage, maxValue, aM, tT, blockSize, C);
	out_img.write(thresholdedImage);
}
Mat Normalized::preprocess2(Mat& im)
{
	// 1) assume white on black and does local thresholding
	// 2) only allow voting top is white and buttom is black(buttom text line)
	Mat thresh;
	//thresh=255-im;
	thresh = im.clone();
	adaptiveThreshold(thresh, thresh, 255, CV_ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 15, -2);
	/*int kernel_size = 3;
	int scale = 1;
	int delta = 0;
	int ddepth = CV_8UC1;
	cv::Laplacian(thresh, thresh, ddepth, kernel_size, scale, delta, BORDER_DEFAULT);*/

	Mat ret = Mat::zeros(im.size(), CV_8UC1);
	for (int x = 1; x<thresh.cols - 1; x++)
	{
		for (int y = 1; y<thresh.rows - 1; y++)
		{
			bool toprowblack = thresh.at<uchar>(y - 1, x) == 0 || thresh.at<uchar>(y - 1, x - 1) == 0 || thresh.at<uchar>(y - 1, x + 1) == 0;
			bool belowrowblack = thresh.at<uchar>(y + 1, x) == 0 || thresh.at<uchar>(y + 1, x - 1) == 0 || thresh.at<uchar>(y + 1, x + 1) == 0;

			uchar pix = thresh.at<uchar>(y, x);
			if ((!toprowblack && pix == 255 && belowrowblack))
			{
				ret.at<uchar>(y, x) = 255;
			}
		}
	}
	return ret;
}
Beispiel #8
0
/* Color-Cartoon Filter Imaplementation */
void colorCartoonFilter(Mat& src, Mat& dst, int edgeThickness, int edgeThreshold) 
{	
	// denormalize params
	edgeThickness = (edgeThickness*(CARTOON_THICK_MAX - CARTOON_THICK_MIN))/INPUT_MAX + CARTOON_THICK_MIN;
	if(edgeThickness%2 == 0) edgeThickness++;
	edgeThreshold = (edgeThreshold*(CARTOON_THRESH_MAX - CARTOON_THRESH_MIN))/INPUT_MAX + CARTOON_THRESH_MIN;
	
    Mat src_blurred, src_gray, quantized, edges;

    // Denoise image
    GaussianBlur(src, src_blurred, Size(5,5), 0);
    // Get src image grayscale
    cvtColor(src_blurred, src_gray, CV_RGBA2GRAY);
    // Quantize gray img to get discrete shades
    quantize(src_gray, quantized);
	cvtColor(quantized, dst, CV_GRAY2RGBA);
    // superimpose gray shades on color src img
    //subtract(src_blurred, ~dst, dst);
    add(0.7*src_blurred,0.7*dst,dst);
    // get illumination-resistant edges by adaptive thresholding
    adaptiveThreshold(src_gray, src_gray, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, edgeThickness, edgeThreshold);
    cvtColor(src_gray, edges, CV_GRAY2RGBA);
    // superimpose edges on shaded src img
    subtract(dst, ~edges, dst);
}
Beispiel #9
0
char* VideoProcessor::setFrameImage(int width, int height, int size, char* imgData, int withStep) 
{
    //Fill in the OpenCV image struct from the data from CoreVideo.
    frameImage->nSize       = sizeof(IplImage);
    frameImage->ID          = 0;
    frameImage->nChannels   = 4;
    frameImage->depth       = IPL_DEPTH_8U;
    frameImage->dataOrder   = 0;
    frameImage->origin      = 0; //Top left origin.
    frameImage->width       = width;
    frameImage->height      = height;
    frameImage->roi         = 0; //Region of interest. (struct IplROI).
    frameImage->maskROI     = 0;
    frameImage->imageId     = 0;
    frameImage->tileInfo    = 0;
    frameImage->imageSize   = size;
    frameImage->imageData   = imgData;
    frameImage->widthStep   = withStep;
    frameImage->imageDataOrigin = imgData;
    
    //Change the function used to process the image.
    
    return adaptiveThreshold(frameImage);
    //return close(frameImage);
    //return erode(frameImage);
    //return canny(frameImage);

}
Beispiel #10
0
void FindContour::binaryImage(const Mat &img, Mat &binaryImg){
    Mat frameGray;
    cv::cvtColor(img, frameGray, CV_RGB2GRAY);

    Mat tmp = Mat::zeros(frameGray.rows, frameGray.cols, frameGray.type());
    adaptiveThreshold(frameGray, tmp, 255.0, ADAPTIVE_THRESH_GAUSSIAN_C,
                      CV_THRESH_BINARY_INV, blockSize, constValue);
    dilErod(tmp, binaryImg, dilSize);

    cvtColor(binaryImg, binaryImg, CV_GRAY2RGB);
}
Beispiel #11
0
Mat PAN::getcontours(Mat test,vector<vector<Point>> &finalcontours, int parameter,String database){
	Mat img;
	finalcontours._Pop_back_n(finalcontours.size());
	Image image = PAN::Image(&img, 0, 0, 0, 0, Point(0, 0));
	Mat mod=test.clone();
	if (parameter == 1){ mod = preprocess(panimage.img, &image, REMOVE_EMBLEM,database); }//used for cropping the image
	else if (parameter == 2){ mod = panimage.img->clone(); }
	int erosion_size;
	if (parameter == 0){
				erosion_size = 4;
	}
else{
	erosion_size = 4 / parameter;
}
	Mat element = getStructuringElement(MORPH_RECT, Size(2 * erosion_size + 1, 2 * erosion_size + 1), Point(erosion_size, erosion_size));
	*image.img = mod.clone();
	int kernel_size = 3;
	int threshold = 81;
	int ratio = 2 ;
	if (parameter == 0){
		ratio = 2;
	}
	else{
		ratio = 2 / parameter;
	}

	int lowThreshold = 100;
	if (image.img->channels() >= 2){ cvtColor(*image.img, *image.img, CV_BGR2GRAY); }
	adaptiveThreshold(*image.img, *image.img, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, threshold, threshold);
	erode(*image.img, *image.img, element);
	blur(*image.img, *image.img, Size(kernel_size, kernel_size));
	Canny(*image.img, *image.img, lowThreshold, lowThreshold*(2 * ratio + 1), 3, true);
	vector<vector<Point>> contours;
	findContours(*image.img, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE, Point(0, 0));
	
	for (unsigned int i = 0; i< contours.size(); i++){
		if (contours[i].size()>40 ){
			vector<Point>temp = contours[i];
						finalcontours.push_back(temp);
				}
		
	}

	RNG rng(1235);
	for (unsigned int i = 0; i<finalcontours.size(); i++){
		Scalar color = Scalar(rng.uniform(150, 255), rng.uniform(150, 255), rng.uniform(150, 255));
		drawContours(*image.img, finalcontours, i, color, 2, 8);
	}
	namedWindow("output", WINDOW_NORMAL);
	imshow("output", *image.img);
	waitKey();
	return mod;
}
Beispiel #12
0
void Detector::doThreshold(const Mat& source, Mat& dest, double thresholdvalue, double maxvalue, int type, bool adaptive)
{
    Mat planes[3] = {Mat(source.rows, source.cols, CV_8UC1)};
    dest = Mat(source.rows, source.cols, CV_8UC1);
    split(source, planes);
    Mat tmp = (planes[0]+planes[1]+planes[2])/3;
    if (adaptive) {
        adaptiveThreshold(tmp, dest, thresholdvalue,CV_ADAPTIVE_THRESH_MEAN_C, type, 3, 5);
    } else {
        threshold(tmp, dest, thresholdvalue, maxvalue, type);
    }
}
Beispiel #13
0
int Methods::preprocess(Mat *bin_image, vector<Image> *output,int doc) {
	Image temp_image(bin_image , 0, bin_image->rows, 0, bin_image->cols,Point2f(0,0));
	if (bin_image->channels()> 2){ cvtColor(*bin_image, *bin_image, CV_BGR2GRAY); }
	if (doc==1){
	adaptiveThreshold(*bin_image, *bin_image, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 51, 45);}
	else{
		adaptiveThreshold(*bin_image, *bin_image, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 13, 23);
	}
		int sensitivity = 4;
		CropImage(&temp_image, sensitivity);
		if (temp_image.x_right < 10 || temp_image.y_lower < 10){  return 0; }
		resize(*bin_image, *bin_image, Size(200, 100), 0, 0);
		//rotate here and then resize--1-11-2015
	//	signAlign(*bin_image);

		temp_image.y_lower = 100;
		temp_image.x_right = 200;
		temp_image.y_upper = 0;
		temp_image.x_left = 0;
		temp_image.imgCOG = calculateCOG(&temp_image);
		sampleCOG = temp_image.imgCOG;
		output->push_back(temp_image);
		return 1;
}
	void findGoodCorners2(const Mat &grayFrame, const SoccerPitchData &data, Mat &currToKeyTrans, Mat &keyToTopTrans) {
		Mat topToCurrTrans;
		invert(keyToTopTrans * currToKeyTrans, topToCurrTrans);
		vector<Point2f> imagePitchOuterContour;
		perspectiveTransform(data.pitchOuterPoints, imagePitchOuterContour, topToCurrTrans);

		vector<Point2f> hull;
		convexHull(imagePitchOuterContour, hull);

		Mat mask = Mat::zeros(frameSize, CV_8UC1);
		fillConvexPoly(mask, vector<Point>(hull.begin(), hull.end()), Scalar(1, 0, 0));

		dilate(mask, mask, getStructuringElement(MORPH_ELLIPSE, Size(3, 3)));

		Mat bin;
		adaptiveThreshold(grayFrame, bin, 255, ADAPTIVE_THRESH_MEAN_C , THRESH_BINARY, 5, -10);
		
		vector<Point2f> candidateCorners;
		goodFeaturesToTrack(bin, candidateCorners, 100, 0.01, 24, mask);

		cornerSubPix(bin, candidateCorners, Size(5, 5), Size(-1, -1), TermCriteria(CV_TERMCRIT_EPS & CV_TERMCRIT_ITER, 40, 0.001));

		vector<Point2f> goodPoints;
		for (Point2f corner : candidateCorners) {
			if (goodCornerCheck(corner, bin) && !closeToBoundary(corner))
				goodPoints.push_back(corner);
		}

		if (goodPoints.size() > 0) {
			vector<Point2f> reprojGoodPoints;
			perspectiveTransform(goodPoints, reprojGoodPoints, keyToTopTrans * currToKeyTrans);
			// try to add these new corners into the relocatedCorners
			for (int i = 0; i < reprojGoodPoints.size(); i++) {
				// if does not exists already and coincide with reproj of 28 points
				bool exists = hasSimilarPoint(relocatedPitchPoints, reprojGoodPoints[i], 10) ;
				int minId = findClosestPoint(data.pitchPoints, reprojGoodPoints[i]);
				double minDist = norm(reprojGoodPoints[i] - data.pitchPoints[minId]);
				if ((!exists ) && (minDist < 16) && (minDist < reprojErr[minId])) {
					relocatedCorners.push_back(goodPoints[i]);
					relocatedPitchPoints.push_back(data.pitchPoints[minId]);
					reprojErr[minId] = minDist;
				}
			}
		}

		cout<<relocatedCorners.size()<<" points relocated"<<endl;
	}
	int CharacterCut::loadImage(String imagePath){

		Mat image = imread(imagePath,0);  
		if(!image.data)  
		{  
			cout << "Fail to load image" << endl;  
			return 0;  
		}  
		//局部自适应二值化
		Mat imageShold;  
		int blockSize = 25;
		int constValue = 10;
		adaptiveThreshold(image, imageShold, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, blockSize, constValue);
		//腐蚀
		Mat img_erode;
		erode(imageShold,img_erode,Mat()); 
		//查找连通域
		vector<vector<Point>> contours;  
		findContours(img_erode, contours, CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE, cvPoint(0,0));  
		//筛选连通域大小
		getSizeContours(contours); 
		//初次分割 基于连通域
		vector<Rect> firstCut;
		//利用连通域矩形 提取单字
		for(int i=0;i<contours.size();i++){
			Rect r=boundingRect(Mat(contours[i]));
			rectangle(image,r,Scalar(0),1);
			Rect rect(r.x,r.y,r.width,r.height);

			firstCut.push_back(rect);
		}

		//连通域排序
		sortContours(firstCut); 
		//求平均宽度
		int m=findEvenwidth(firstCut,imageShold);
		//连通域合并
		mergeContours(firstCut,m);	
		//cout<<"EvenWidth: "<<m<<endl;
		vector<Rect>::reverse_iterator it;
		//投影分割
		for(it=firstCut.rbegin();it!=firstCut.rend();it++){
			secondCut(imageShold((*it)),m);
		} 
		return 1;  
	}
/**
 * @function Threshold_Demo
 */
void Threshold_Demo( int, void* )
{
  /* 0: Binary
     1: Binary Inverted
     2: Threshold Truncated
     3: Threshold to Zero
     4: Threshold to Zero Inverted
   */
  if (threshold_adaptive)
  {
	int size = ((threshold_size ? threshold_size : 1) * 2 + 1);
	adaptiveThreshold(src_gray, dst, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, size, threshold_value - 128);
  }
  else
	threshold( src_gray, dst, threshold_value, max_BINARY_value,threshold_type );

  imshow( window_name, dst );
}
Beispiel #17
0
Mat processInput(Mat img)
{
	Mat img_gray, img_adpth;

	// convert to gray
	if(img.channels() == 3 || img.channels() == 4)
	{
		cvtColor(img, img_gray, CV_BGR2GRAY);
	}
	else
	{
		img_gray = img.clone();
	}

	// adaptive threshold
	adaptiveThreshold(img_gray, img_adpth, 255, 1, 1, 15, 10);

	return img_adpth;
}
int main (int argc, char** argv)
{
	IplImage* cvFrame;
	IplImage* binImg;
	int key;

	cvFrame = cvLoadImage("image.bmp", -1);
	binImg = cvCreateImage(cvSize(IMAGE_WIDTH, IMAGE_HEIGHT), 8, 1);

	cvNamedWindow("Input", 1);
	cvNamedWindow("Output", 1);

	adaptiveThreshold((unsigned char*)cvFrame->imageData, (unsigned char*)binImg->imageData);

	cvShowImage("Input", cvFrame);
	cvShowImage("Output", binImg);

	key = cvWaitKey(0);

	return 0;
}
Beispiel #19
0
Mat processInput(Mat img)
{
    Mat img_gray, img_adpth;

    // convert to gray
    if(img.channels() == 3 || img.channels() == 4)
    {
        cvtColor(img, img_gray, CV_BGR2GRAY);
    }
    else
    {
        img_gray = img.clone();
    }

    // adjust the block size of the input image
    unsigned int block_size = 0.03 * img.cols;
    if(block_size % 2 == 0) block_size ++;

    // adaptive threshold
    adaptiveThreshold(img_gray, img_adpth, 255, 1, 1, block_size, 10);

    return img_adpth;
}
Beispiel #20
0
void PreProcessImage(const Mat& inImage, Mat& outImage, int sizex, int sizey)
{
	Mat grayImage, blurredImage, thresholdImage, contourImage, regionOfInterest;

	vector<vector<Point> > contours;

	try{
		cvtColor(inImage, grayImage, COLOR_BGR2GRAY);
	}
	catch (exception& ex){
		grayImage = inImage.clone();
	}

	GaussianBlur(grayImage, blurredImage, Size(5, 5), 2, 2);
	adaptiveThreshold(blurredImage, thresholdImage, 255, 1, 1, 11, 2);
	thresholdImage.copyTo(contourImage);

	findContours(contourImage, contours, RETR_LIST, CHAIN_APPROX_SIMPLE);

	int idx = 0;
	size_t area = 0;
	for (size_t i = 0; i < contours.size(); i++)
	{
		if (area < contours[i].size())
		{
			idx = i;
			area = contours[i].size();
		}
	}

	Rect rec = boundingRect(contours[idx]);

	regionOfInterest = thresholdImage(rec);

	resize(regionOfInterest, outImage, Size(sizex, sizey));

}
void Processor::Img_pro() {

	_rotation();

	imwrite("/storage/emulated/0/baidu/img.jpg",_img);
	Mat gray;
	cvtColor(_img, gray, CV_RGB2GRAY);

	Mat bin;
	adaptiveThreshold(gray, bin, 255, CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY_INV, 101, 1);
	imwrite("/storage/emulated/0/baidu/bin.jpg", bin);

	std::vector<std::vector<cv::Point> > contours;
	//des,contours,�ⲿ������������
	findContours(bin, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);

	Mat des(_img.size(), CV_8UC1, Scalar(0));

	for (int i = 0; i < contours.size(); i++) {
		if (contourArea(contours[i]) < 350)
			continue;
		drawContours(des, contours, i, Scalar(255), -1);
	}
	imwrite("/storage/emulated/0/baidu/des.jpg", des);
	Mat element = getStructuringElement(MORPH_RECT, Size(3,3));
	dilate(des, des, element);


	contours.clear();
	findContours(des, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);

	for (int i = 0; i < contours.size(); i++) {
		if (contourArea(contours[i]) < 350)
			continue;

		Mat sample(_img.size(), CV_8UC1, Scalar(0));
		drawContours(sample, contours, i, Scalar(255), - 1);

		Mat regionOfInterest;
		Rect rec = boundingRect(contours[i]);

		Sample_Elem tmp;
		tmp.x_position = rec.x;
		tmp.y_position = rec.y;
		tmp.height = rec.height;
		tmp.weight = rec.width;

		if (rec.width < rec.height) {
			rec.x -= (rec.height - rec.width) / 2;
			if (rec.x < 0)
				rec.x = 0;
			if (rec.x + rec.height>sample.cols)
				rec.width = sample.cols - rec.x;
			else
			rec.width = rec.height;
		}
		else{
			rec.y -= (rec.width - rec.height) / 2;
			if (rec.y < 0)
				rec.y = 0;
			if (rec.y + rec.width>sample.rows)
				rec.height = sample.rows - rec.y;
			else
				rec.height = rec.width;
			tmp.y_position = rec.y;
			tmp.height = rec.width;
		}

/*	    FILE* fp;
		fp = fopen(".\\data\\sample_rect_data.txt", "a+");
		if (fp == NULL) {
			std::cout << "rect error";
			return;
		}

		fprintf(fp, "%d,%d,%d,%d\n", rec.x, rec.y, rec.width, rec.height);
		fclose(fp);
*/
		regionOfInterest = sample(rec);
		resize(regionOfInterest, regionOfInterest, Size(SAMPLE_SIZE, SAMPLE_SIZE));

		tmp.img = regionOfInterest;
		_Mat_contours.append(tmp);
	}
}
bool find_square(Mat grayImage)
{
    if (grayImage.channels() != 1)
    {
        std::cout << "[find_square]: expected grayscale image, returning false" << std::endl;
        return false;
    }

    Mat adapt;
    adaptiveThreshold(
        grayImage,
        adapt,
        255,
        ADAPTIVE_THRESH_GAUSSIAN_C,
        THRESH_BINARY,
        7,
        10
    );

    int erosion_size = 1;
    int square_size  = erosion_size * 2 + 1;
    Mat element = getStructuringElement(
        MORPH_RECT,
        Size(square_size, square_size),
        Point(erosion_size, erosion_size)
    );

    erode(adapt, adapt, element);

    
    disjoint_set ds;
    Mat labels = Mat::zeros(grayImage.size(), CV_32SC1);

    clock_t t = clock();
    // do label based connected components with a
    // disjoint set data structure.
    int label = 0;
    for (int i = 0; i < adapt.rows; ++i)
    {
        for (int j = 0; j < adapt.cols; ++j)
        {

            uchar   cur_pixel = adapt.at<uchar>(i, j);
            int&    cur_label = labels.at<int>(i, j);
            int      up_label = (i == 0) ? -1 : labels.at< int >(i - 1, j    );
            int    left_label = (j == 0) ? -1 : labels.at< int >(i    , j - 1);
            uchar    up_pixel = (i == 0) ? -1 :  adapt.at<uchar>(i - 1, j    );
            uchar  left_pixel = (j == 0) ? -1 :  adapt.at<uchar>(i    , j - 1);

            bool same_left = left_pixel == cur_pixel;
            bool same_up   =   up_pixel == cur_pixel;

            if (same_left)
            {
                if (same_up)
                {
                    cur_label = min(up_label, left_label);
                    ds.join(up_label, left_label);
                }
                else
                {
                    cur_label = left_label;
                }
            }
            else if (same_up)
            {
                cur_label = up_label;
            }
            else
            {
                ++label;
                labels.at<uint>(i, j) = label;
                ds.add(label);
            }
        }
    }

    if (0)
    {
        RNG rng(0);
        map<int, Vec3b> colorMap;
        for (int i = 1; i <= label; ++i)
        {
            colorMap[i] = Vec3b(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
        }

        Mat assignment = Mat::zeros(grayImage.size(), CV_8UC3);
        for (int i = 0; i < assignment.rows; ++i)
        {
            for (int j = 0; j < assignment.cols; ++j)
            {
                int label_value = ds.find(labels.at<int>(i, j));
                assignment.at<Vec3b>(i, j) = colorMap[label_value];
            }
        }

        imshow("Connections", assignment);
        waitKey();
    }

    t = clock() - t;
    cout << ((float) t) / CLOCKS_PER_SEC << endl;
    
    // imshow("Find", adapt);
    return true;
}
Beispiel #23
0
inline bool Face::extractEyeCorners (Mat eyeImg, Point efcps [5], Point ceye)
{
    Mat eyesSobel, eyesTh, eyesSTh;
    Mat eyeBlur;

    //equalizeHist( eyeImg, eyeImg );

    GaussianBlur( eyeImg , eyeBlur, Size(3,3), 2, 2 );

    //Sobel filter. Horizontal, 2nd order, single channel 255 bit-depth, 3x3 kernel.
    Sobel(eyeBlur, eyesSobel,CV_8UC1, 0, 2 , 3, 1, 0, BORDER_REPLICATE);

    //Thresholding so only hard edges stay.Automatic threshold estimated with Otsu algorithm. Both numbers 255 are ignored (dummy).
    //threshold(eyesSobel, eyesSTh, 255,255, THRESH_BINARY | THRESH_OTSU);
    adaptiveThreshold(eyesSobel, eyesSTh,255,ADAPTIVE_THRESH_GAUSSIAN_C,THRESH_BINARY,/*((eyesSobel.size().width) % 2 == 1? (eyesSobel.size().width) : (eyesSobel.size().width) + 1 )*/ 3,-2);


    //The extraction will be based on:
    //  - Sorting contours by area*darkness
    //  - Considering only the 4 first of those.
    //  - The first of them will be the upper eyelid contour.
    //  - The lowest located of them will be the lower eyelid.
    //  - Upper and lower eyelids contours could be the same one.
    //  - The bounding points of the union of these two contours are the 4 characteristic points of the eye.
    //  - The eye center is not extracted here. It is keeped the value from previous algorithms.
    vector<vector<Point> > contours;
    Mat imContours;

    eyesSTh.copyTo(imContours);
    findContours(imContours,contours,CV_RETR_LIST,CV_CHAIN_APPROX_NONE);

    //Sorting by area and darkness.
    const int CAREAS_SZ = 500;
    int cAreasIdx [CAREAS_SZ];
    int cAreas [CAREAS_SZ];
    /*Computing areas and sorting (bubble sort .. improve)*/
    unsigned j;
    for( j = 0 ; j < contours.size() && j < CAREAS_SZ; j++)
    {
        int aux1, aux2, auxIdx1, auxIdx2;
        Mat matcnt (contours[j]);
        Rect bbox = boundingRect(matcnt);

        //Cost funtion to maximize: max(area * darkest)
        double costf = sum(eyesSTh(bbox)) [0] ; //Other things tryed: (sum(eyeNeg(halfsideBox))[0]))  + ((bbox.y + (bbox.height/2)) / halfImContours.size().height ; //bbox.area();

        //cout << "Area " << j << ": " << area << endl;

        //Sorting
        int i = 0;
        while (i < j && costf <= cAreas[i]) i++;

        aux1 = costf;
        auxIdx1 = j;
        while (i <= j)
        {
            aux2 = cAreas[i];
            cAreas[i] = aux1;
            aux1 = aux2;

            auxIdx2 = cAreasIdx[i];
            cAreasIdx[i] = auxIdx1;
            auxIdx1 = auxIdx2;

            i++;
        }
    }

    //We will get consider only the 4 first contours. Then the lowest located of those, will be the low eyelid.
    //The upper eyelid will be the first in sort.
    int uIdx = -1 , lIdx = -1;
    if (contours.size() > 0)
    {
        uIdx = cAreasIdx[0]; //Upper eyelid will be the widest and darkest

        //Low eyelid will be the lowest located among the 4 wider.
        int maxy = 0;
        for( j = 0 ; j < contours.size() && j < 4; j++)
        {
            Mat matcnt (contours[cAreasIdx[j]]);
            Rect bbox = boundingRect(matcnt);

            if (bbox.br().y > maxy )
            {
                maxy = bbox.br().y;
                lIdx = cAreasIdx[j];
            }
        }
    }



    Point laux, raux, uaux, daux;

    if (uIdx >=0 && lIdx >= 0)
    {
        findBoundingPoints(contours[uIdx],&efcps[0], &efcps[1], &efcps[2], &efcps[3]);
        findBoundingPoints(contours[lIdx],&laux, &raux, &uaux, &daux);

        //Getting leftmost and rightmost
        efcps[0] = (laux.x < efcps[0].x) ? laux : efcps[0];
        efcps[1] = (raux.x > efcps[1].x) ? raux : efcps[1];

        //Getting uppermost and downmost
        efcps[2] = (uaux.y < efcps[2].y) ? uaux : efcps[2];
        efcps[3] = (daux.y > efcps[3].y) ? daux : efcps[3];

        //Centering the upper and lower points
        efcps[2].x = (efcps[1].x + efcps[0].x) / 2;
        efcps[3].x = efcps[2].x;

        //Centero of the eye will be the same. Maybe improved in the future.
        efcps[4] = ceye;



    }else
        return false; //cerr << "Exception: NO EYE CORNERS DETECTED !! " << endl;

/*
    //DEBUG
            circle (eyeBlur, efcps[0], 0, CV_RGB (255,255,255),2);
            circle (eyeBlur, efcps[1], 0, CV_RGB (255,255,255),2);
            circle (eyeBlur, efcps[2], 0, CV_RGB (255,255,255),2);
            circle (eyeBlur, efcps[3], 0, CV_RGB (255,255,255),2);


    cv::imshow( "SEyes", eyesSobel);
    cvMoveWindow("SEyes", 700, 500 );

    cv::imshow( "SThEyes", eyesSTh);
    cvMoveWindow("SThEyes", 1000, 300 );

    cv::imshow( "EyeImg", eyeBlur);
    cvMoveWindow("EyeImg", 1100, 300 );
*/
    return 0;
}
Beispiel #24
0
inline bool Face::extractMouthPoints (Mat mouthImg, Point& llips, Point& rlips, Point& ulips, Point& dlips)
{
    Mat mouthImgTh, mouthSobel, kernel(1,5,CV_8UC1,1);

    //Sobel filter. Horizontal, 2nd order, single channel 255 bit-depth, 3x3 kernel.
    Sobel(mouthImg, mouthSobel, CV_8UC1, 0, 2, 3);


    //Thresholding so only hard edges stay.Automatic threshold estimated with Otsu algorithm. Both numbers 255 are ignored (dummy).
    threshold(mouthSobel, mouthImgTh, 255,255, THRESH_BINARY | THRESH_OTSU);

    Mat mouthAdapTh;
    adaptiveThreshold(mouthSobel,mouthAdapTh,255,ADAPTIVE_THRESH_GAUSSIAN_C,THRESH_BINARY,((mouthSobel.size().width) % 2 == 1? (mouthSobel.size().width) : (mouthSobel.size().width) + 1 ),-15);


    vector<vector<Point> > contours;
    Rect bigBox;
    Mat imContours;

    mouthAdapTh.copyTo(imContours);
    findContours(imContours,contours,CV_RETR_LIST,CV_CHAIN_APPROX_NONE);

    int cind;
    for( unsigned  j = 0 ; j < contours.size(); j++)
    {

        Mat matcnt (contours[j]);
        Rect bbox = boundingRect (matcnt);

        if (bbox.width > bigBox.width) {
            // O novo pasa a maior
            bigBox = bbox;
            cind = j;
        }
    }


    if (contours.size()>0)
        Face::findBoundingPoints(contours.at(cind),&llips,&rlips,&ulips, &dlips);
    else
        return false; //The image got totally black. No mouth detected.



    //Finding Upper lip y coordinate. The longest horizontal edge within the brightest.
    //integral(mouthSobel, mouthIntegral);
    Mat mouthEroded;
    erode(mouthAdapTh, mouthEroded, kernel);
    Mat lip2 = mouthEroded(bigBox);
    Mat vPrj (lip2.size().height, 1, CV_32FC1); //One coloumn
    Point p1,p2;
    double pv1,pv2;

    Face::project(lip2, NULL, &vPrj);

    minMaxLoc(vPrj,&pv2, &pv1,&p2, &p1);

    ulips.y = p1.y + bigBox.tl().y;

    //Adjust de upper and lower lip 'x' coordinates to the middle. Otherwise they will be moving with noise.
    ulips.x = int((rlips.x + llips.x)/2);




    /* Detecting Lower Lip (dlip) */
    Mat lipmap;
    Mat mouthComp = Mat(mouthImg.size(),mouthImg.type(), CV_RGB(255,255,255)) - mouthImg  ;
    addWeighted( mouthSobel, 0.5, mouthComp, 0.5, 0, lipmap);
    Mat mouthAdapTh3;
    adaptiveThreshold(lipmap, mouthAdapTh3,255,ADAPTIVE_THRESH_GAUSSIAN_C,THRESH_BINARY,((mouthSobel.size().width) % 2 == 1? (mouthSobel.size().width) : (mouthSobel.size().width) + 1 ),-10);


    mouthAdapTh3.copyTo(imContours);
    //mouthImgTh.copyTo(imContours);
    findContours(imContours,contours,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_NONE);

    //Sorting by area and darkness. TODO: improve heuristics to sort by (e.g: use area or width/mean value (max area and darkest)*relative down position)
    const int CAREAS_SZ = 500;
    int cAreasIdx [CAREAS_SZ];
    int cAreas [CAREAS_SZ];
    /*Computing areas and sorting (bubble sort .. improve)*/
    unsigned j;
    for( j = 0 ; j < contours.size() && j < CAREAS_SZ; j++)
    {
        int aux1, aux2, auxIdx1, auxIdx2;
        Mat matcnt (contours[j]);
        Rect bbox = boundingRect(matcnt);

        //Cost funtion to maximize: max(area * darkest)  // this does not work lowest located in 'y' coordinate
        double costf = bbox.width; //sum(lipmap(bbox)) [0] ;// (sum(eyeNeg(halfsideBox))[0]))  + ((bbox.y + (bbox.height/2)) / halfImContours.size().height ;

        //cout << "Area " << j << ": " << area << endl;

        //Sorting
        int i = 0;
        while (i < j && costf <= cAreas[i]) i++;

        aux1 = costf;
        auxIdx1 = j;
        while (i <= j)
        {
            aux2 = cAreas[i];
            cAreas[i] = aux1;
            aux1 = aux2;

            auxIdx2 = cAreasIdx[i];
            cAreasIdx[i] = auxIdx1;
            auxIdx1 = auxIdx2;

            i++;
        }
    }

    if (contours.size() >= 1) {
        Mat matcnt (contours.at(cAreasIdx[0]));
        bigBox = boundingRect(matcnt);
        Face::findBoundingPoints(contours.at(cAreasIdx[0]),NULL, NULL, NULL, &dlips);
        //Adjust de upper and lower lip 'x' coordinates to the middle. Otherwise they will be moving with noise.
        ulips.x = int((rlips.x + llips.x)/2);
        dlips.x = int((rlips.x + llips.x)/2);

    }

    return true;
}
Beispiel #25
0
int CCharsSegment::charsSegment(Mat input, vector<Mat>& resultVec, Color color) {
  if (!input.data) return 0x01;

  Mat input_grey;
  cvtColor(input, input_grey, CV_BGR2GRAY);

  if (1) {
    imshow("plate", input_grey);
    waitKey(0);
    destroyWindow("plate");
  }

  Mat img_threshold;

  // 二值化
  // 根据车牌的不同颜色使用不同的阈值判断方法
  // TODO:使用MSER来提取这些轮廓

  //if (BLUE == plateType) {
  //  // cout << "BLUE" << endl;
  //  img_threshold = input_grey.clone();

  //  int w = input_grey.cols;
  //  int h = input_grey.rows;
  //  Mat tmp = input_grey(Rect_<double>(w * 0.1, h * 0.1, w * 0.8, h * 0.8));
  //  int threadHoldV = ThresholdOtsu(tmp);
  //  threshold(input_grey, img_threshold, threadHoldV, 255, CV_THRESH_BINARY);

  //} else if (YELLOW == plateType) {
  //  // cout << "YELLOW" << endl;
  //  img_threshold = input_grey.clone();
  //  int w = input_grey.cols;
  //  int h = input_grey.rows;
  //  Mat tmp = input_grey(Rect_<double>(w * 0.1, h * 0.1, w * 0.8, h * 0.8));
  //  int threadHoldV = ThresholdOtsu(tmp);
  //  // utils::imwrite("resources/image/tmp/inputgray2.jpg", input_grey);

  //  threshold(input_grey, img_threshold, threadHoldV, 255,
  //            CV_THRESH_BINARY_INV);

  //} else if (WHITE == plateType) {
  //  // cout << "WHITE" << endl;

  //  threshold(input_grey, img_threshold, 10, 255,
  //            CV_THRESH_OTSU + CV_THRESH_BINARY_INV);
  //} else {
  //  // cout << "UNKNOWN" << endl;
  //  threshold(input_grey, img_threshold, 10, 255,
  //            CV_THRESH_OTSU + CV_THRESH_BINARY);
  //}

  Color plateType = color;

  img_threshold = input_grey.clone();
  spatial_ostu(img_threshold, 8, 2, plateType);

  if (0) {
    imshow("plate", img_threshold);
    waitKey(0);
    destroyWindow("plate");
  }

  // 去除车牌上方的柳钉以及下方的横线等干扰
  // 并且也判断了是否是车牌
  // 并且在此对字符的跳变次数以及字符颜色所占的比重做了是否是车牌的判别条件
  // 如果不是车牌,返回ErrorCode=0x02

  if (!clearLiuDing(img_threshold)) return 0x02;
  //clearLiuDing(img_threshold);

  // 在二值化图像中提取轮廓

  Mat img_contours;
  img_threshold.copyTo(img_contours);

  vector<vector<Point> > contours;
  findContours(img_contours,
               contours,               // a vector of contours
               CV_RETR_EXTERNAL,       // retrieve the external contours
               CV_CHAIN_APPROX_NONE);  // all pixels of each contours

  vector<vector<Point> >::iterator itc = contours.begin();
  vector<Rect> vecRect;

  // 将不符合特定尺寸的字符块排除出去

  while (itc != contours.end()) {
    Rect mr = boundingRect(Mat(*itc));
    Mat auxRoi(img_threshold, mr);

    if (verifyCharSizes(auxRoi)) vecRect.push_back(mr);
    ++itc;
  }

  // 如果找不到任何字符块,则返回ErrorCode=0x03

  if (vecRect.size() == 0) return 0x03;

  // 对符合尺寸的图块按照从左到右进行排序;
  // 直接使用stl的sort方法,更有效率

  vector<Rect> sortedRect(vecRect);
  std::sort(sortedRect.begin(), sortedRect.end(),
            [](const Rect& r1, const Rect& r2) { return r1.x < r2.x; });

  size_t specIndex = 0;

  // 获得特殊字符对应的Rectt,如苏A的"A"

  specIndex = GetSpecificRect(sortedRect);

  // 根据特定Rect向左反推出中文字符
  // 这样做的主要原因是根据findContours方法很难捕捉到中文字符的准确Rect,因此仅能
  // 退过特定算法来指定

  Rect chineseRect;
  if (specIndex < sortedRect.size())
    chineseRect = GetChineseRect(sortedRect[specIndex]);
  else
    return 0x04;

  if (0) {
    rectangle(img_threshold, chineseRect, Scalar(255));
    imshow("plate", img_threshold);
    waitKey(0);
    destroyWindow("plate");
  }

  //新建一个全新的排序Rect
  //将中文字符Rect第一个加进来,因为它肯定是最左边的
  //其余的Rect只按照顺序去6个,车牌只可能是7个字符!这样可以避免阴影导致的“1”字符

  vector<Rect> newSortedRect;
  newSortedRect.push_back(chineseRect);
  RebuildRect(sortedRect, newSortedRect, specIndex);

  if (newSortedRect.size() == 0) return 0x05;

  // 开始截取每个字符

  for (size_t i = 0; i < newSortedRect.size(); i++) {
    Rect mr = newSortedRect[i];

    // Mat auxRoi(img_threshold, mr);

    // 使用灰度图来截取图块,然后依次对每个图块进行大津阈值来二值化

    Mat auxRoi(input_grey, mr);
    Mat newRoi;

    if (BLUE == plateType) {
      //newRoi = auxRoi.clone();
      //spatial_ostu(newRoi, 5, 5, plateType);
      if (i != 0) 
        threshold(auxRoi, newRoi, 0, 255, CV_THRESH_BINARY + CV_THRESH_OTSU);
      else
        adaptiveThreshold(auxRoi, newRoi, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 3, 0);
      
    } else if (YELLOW == plateType) {
      threshold(auxRoi, newRoi, 0, 255, CV_THRESH_BINARY_INV + CV_THRESH_OTSU);

    } else if (WHITE == plateType) {
      threshold(auxRoi, newRoi, 0, 255, CV_THRESH_OTSU + CV_THRESH_BINARY_INV);
    } else {
      threshold(auxRoi, newRoi, 0, 255, CV_THRESH_OTSU + CV_THRESH_BINARY);
    }

    // 归一化大小
    newRoi = preprocessChar(newRoi);

    if (0) {
      if (i == 0) {
        imshow("chinese", newRoi);
        waitKey(0);
        destroyWindow("chinese");
      }
    }

    // 每个字符图块输入到下面的步骤进行处理
    resultVec.push_back(newRoi);
  }

  return 0;
}
void processFrame(int, void*)
{
    int BLUR_SIZE = 3;           // 3
    double BLUR_SIGMA = 1.5;     //1.5
    int THRESHOLD_SIZE = 9;     //15  //10 ko
    int THRESHOLD_C = -8;        //-8

    // original to grayscale (4ms)
    cvtColor(frame, frameGray, CV_BGR2GRAY);

    // horizontal flip (<1ms)
    flip(frameGray, frameGray, 1);

    // extract roi (<1ms)
    frameROI = frameGray(roi).clone();


    //DEBUG
    //resize(frameROI, frameDebugRoi, Size(320, 240));

    //printf("isBalanceDone  = %d\n", isBalanceDone);
    if (!isBalanceDone ){
        if (!isFakeMode){

          char filename[100];
          //sprintf(filename, "frame_balance_%03d.jpg", frameCpt);
          sprintf(filename, "frame_balance.jpg", frameCpt);

          printf("SAVE %s\n", filename);
          imwrite(filename, frame);


          GaussianBlur(frameROI, frameBalance, cv::Size(BLUR_SIZE, BLUR_SIZE), BLUR_SIGMA, BLUR_SIGMA);

        }else{
          Mat balanceFrame = imread("frame_balance.jpg");
          cvtColor(balanceFrame, balanceFrame, CV_BGR2GRAY);
          flip(balanceFrame, balanceFrame, 1);
          Mat balanceFrameROI = balanceFrame(roi).clone();

          GaussianBlur(balanceFrameROI, frameBalance, cv::Size(BLUR_SIZE, BLUR_SIZE), BLUR_SIGMA, BLUR_SIGMA);
          printf("LOAD frame_balance.jpg\n");
        }

        isBalanceDone = true;
    }

    if (frameCpt == 50){
        imwrite("frame.jpg", frame);
        printf("SAVE frame.jpg\n");
    }


    // 1ms
    GaussianBlur(frameROI, frameROI, cv::Size(BLUR_SIZE, BLUR_SIZE), BLUR_SIGMA, BLUR_SIGMA);

    // 1ms
    absdiff(frameROI, frameBalance, frameROI);


    // DEBUG
    //resize(frameROI, frameDebugBalance, Size(320, 240));

    // binary (1ms)
    adaptiveThreshold(frameROI, frameROI, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, THRESHOLD_SIZE, THRESHOLD_C);
    //threshold(frameROI, frameROI, 15, 255, THRESH_BINARY);


    // dilate(6ms) + erode
    //erode(frameROI, frameROI, dummyMat, Point(-1, -1), 1);
    //dilate(frameROI, frameROI, dummyMat, Point(-1, -1), 2);


    // DEBUG
    //resize(frameROI, frameDebug, Size(320, 240));

    // resize (3ms)
    resize(frameROI, frameROI, Size(320, 240));


    // find contours (5ms)
    frameContours = frameROI;//.clone();
    findContours(frameContours, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0,0));
    vector<vector<Point> > contours_poly( contours.size() );
    //vector<Rect> boundRect( contours.size() );

    boundCount = contours.size();
    boundRect = vector<Rect>(contours.size());

    for( int i = 0; i < contours.size(); i++ )
    {
        approxPolyDP( Mat(contours[i]), contours_poly[i], 3, true );
        boundRect[i] = boundingRect( Mat(contours_poly[i]) );
        //printf("[%d] x:y=%d:%d  w:h=%d:%d\n", i, boundRect[i].x, boundRect[i].y, boundRect[i].width, boundRect[i].height);
        //minEnclosingCircle( (Mat)contours_poly[i], center[i], radius[i] );
    }

}
Beispiel #27
0
Mat skinDetector::detect(Mat captureframe, bool verboseSelect, Mat *skinMask)
{
	verboseOutput=verboseSelect;
	//if (argc>=1) frame = argv[1]);
	//if (argc>=2) singleRegionChoice = int(argv[2]);

	int step = 0;
	Mat3b frame;
	// Forcing resize to 640x480 -> all thresholds / pixel filters configured for this size.....
	// Note returned to original size at end...
    Size s = captureframe.size();
	resize(captureframe,captureframe,Size(640,480));

	
	// CHANGED HERE TO BGR
	//cvtColor(captureframe, captureframe, CV_RGB2BGR);
	if (verboseOutput)	imshow("Raw Image (A)",captureframe);
	/* THRESHOLD ON HSV*/
	// HSV data -> used to find skin
	cvtColor(captureframe, frame, CV_BGR2HSV);
	//cvtColor(captureframe, frame, CV_BGR2HLS);
	GaussianBlur(frame, frame, Size(imgBlurPixels,imgBlurPixels), 1, 1);
	//medianBlur(frame, frame, 15);
	for(int r=0; r<frame.rows; ++r){
		for(int c=0; c<frame.cols; ++c) 
			// 0<H<0.25  -   0.15<S<0.9    -    0.2<V<0.95   
			if( (frame(r,c)[0]>5) && (frame(r,c)[0] < 17) && (frame(r,c)[1]>38) && (frame(r,c)[1]<250) && (frame(r,c)[2]>51) && (frame(r,c)[2]<242) ); // do nothing
			else for(int i=0; i<3; ++i)	frame(r,c)[i] = 0;
	}

	if (verboseOutput)	imshow("Skin HSV (B)",frame);
	/* BGR CONVERSION AND THRESHOLD */
	Mat1b frame_gray;
	cvtColor(frame, frame, CV_HSV2BGR);
	cvtColor(frame, frame_gray, CV_BGR2GRAY);
				
				
	// Adaptive thresholding technique
	// 1. Threshold data to find main areas of skin
	adaptiveThreshold(frame_gray,frame_gray,255,ADAPTIVE_THRESH_GAUSSIAN_C,THRESH_BINARY_INV,9,1);
	if (verboseOutput)	imshow("Adaptive_threshold (D1)",frame_gray);
	// 2. Fill in thresholded areas
	morphologyEx(frame_gray, frame_gray, CV_MOP_CLOSE, Mat1b(imgMorphPixels,imgMorphPixels,1), Point(-1, -1), 2);
	
	
	//GaussianBlur(frame_gray, frame_gray, Size((imgBlurPixels*2)+1,(imgBlurPixels*2)+1), 1, 1);
	GaussianBlur(frame_gray, frame_gray, Size(imgBlurPixels,imgBlurPixels), 1, 1);
	// Select single largest region from image, if singleRegionChoice is selected (1)
	
	if (singleRegionChoice)
	{
		*skinMask = cannySegmentation(frame_gray, -1);
	}
	else // Detect each separate block and remove blobs smaller than a few pixels
	{
		*skinMask = cannySegmentation(frame_gray, minPixelSize);
	}


	// Just return skin
	Mat frame_skin;
	captureframe.copyTo(frame_skin,*skinMask);  // Copy captureframe data to frame_skin, using mask from frame_ttt
	// Resize image to original before return
	resize(frame_skin,frame_skin,s);
	if (verboseOutput)	imshow("Skin segmented",frame_skin);
	return frame_skin;	
	waitKey(1);
}
Mat IITkgp_functions::binarization(Mat image, int type)
{
/**
 * @param type
 * type = 1 for adaptive;
 * type = 2 for Otsu
 * type = 3 for Normal Threshold by GUI
**/

    // Convert the image to Gray

    Mat gray,binary;
    threshold_type = 0;

    cvtColor(image, gray, CV_BGR2GRAY);

    //adaptive Binarization
    if(type == 1)
    {     
      blockSize = (windowsize * 10) + 1;
      adaptiveThreshold(  gray, binary, maximum_BINARY_value, ADAPTIVE_THRESH_GAUSSIAN_C,  threshold_type,  blockSize, tempwinval);
      //TempBinary.copyTo(binary);

    }

    // Otsu Thresholding
    if(type == 2)
    {
      double val = threshold( gray, binary, 100, maximum_BINARY_value, cv::THRESH_OTSU | cv::THRESH_BINARY);
      printf("threshold value is %lf\n",val);
    }

    //GUI Threshold
    if(type == 3)
    {
      gray.copyTo(TempGray);
      /// Create a window to display results
        namedWindow( "BinaryThresholding", CV_WINDOW_KEEPRATIO );

        createTrackbar( "Value", "BinaryThresholding", & binary_threshold_value, maximum_BINARY_value, BinaryThreshold );

        /// Call the function to initialize
        BinaryThreshold( 0, 0 );
        waitKey(0);
        printf("threshold value is %d\n",binary_threshold_value);
        TempBinary.copyTo(binary);

    }
    
    if(type == 4)
    {
      gray.copyTo(TempGray);
      namedWindow( "AdaptiveBinarization", CV_WINDOW_KEEPRATIO );
      createTrackbar( "WindowSize (10n+1)", "AdaptiveBinarization", & windowsize, 100, AdaptiveBinaryThreshold );
      createTrackbar( "Val", "AdaptiveBinarization", & tempwinval, 100, AdaptiveBinaryThreshold );
      /// Call the function to initialize
      AdaptiveBinaryThreshold( 0, 0 );
      waitKey(0);
      TempBinary.copyTo(binary);

    }

    // Fixed Threshold
    if(type == 5)
    {
      binary_threshold_value = 211;
      threshold( gray, binary,  binary_threshold_value, maximum_BINARY_value,threshold_type );
    }

    return (binary);

}
Beispiel #29
0
void FindContour::singleCellDetection(const Mat &img, vector<Point> &cir_org,
                                      Mat &dispImg1, Mat &dispImg2,
                                      int &area, int &perimeter,
                                      Point2f &ctroid, float &shape,
                                      Mat &cell_alpha, // only the area inside cell (without background)
                                      vector<Point> &smooth_contour_curve, // relative position (without counting rect.x and rect.y)
                                      vector<Point> &smooth_contour_curve_abs, // absolut position
                                      Mat &blebsImg,
                                      Rect &rectangle,
                                      //vector<int> &blebs,
                                      int &frameNum)
{
    frame = &img;

    vector<Point> cir; //***global coordinates of circle***
    //cout << "[";
    for(unsigned int i = 0; i < cir_org.size(); i++){
        cir.push_back(Point(cir_org[i].x / scale, cir_org[i].y / scale));
        //cout << int(cir_org[i].x / scale) << ", " << int(cir_org[i].y / scale) << "; ";
    }
    //cout << "]" << endl;

    //enlarge the bounding rect by adding a margin (e) to it
    rect = enlargeRect(boundingRect(Mat(cir)), 5, img.cols, img.rows);
    //cout << "rect_roi " << boundingRect(Mat(cir)) << "\n";
    //cout << "enlarged rect " << rect << endl;

    dispImg1 = (*frame)(rect).clone();

    Mat sub; //*** the rectangle region of ROI (Gray) ***
    cv::cvtColor(dispImg1, sub, CV_RGB2GRAY);
    int width = sub.cols;
    int height = sub.rows;

    rectangle = rect;

//    Mat canny;
//    CannyWithBlur(sub, canny);
//    imshow("canny", canny);

    vector<Point> circle_ROI; //***local coordinates of circle***
    for (unsigned int i = 0; i < cir.size(); i++){
        Point p = Point(cir[i].x - rect.x, cir[i].y - rect.y);
        circle_ROI.push_back(p);
    }

    Mat adapThreshImg1 = Mat::zeros(height, width, sub.type());
    //image edge detection for the sub region (roi rect)
    adaptiveThreshold(sub, adapThreshImg1, 255.0, ADAPTIVE_THRESH_GAUSSIAN_C,
                          CV_THRESH_BINARY_INV, blockSize, constValue);
    //imshow("adapThreshImg1", adapThreshImg1);

    // dilation and erosion
    Mat dilerod;
    dilErod(adapThreshImg1, dilerod, dilSize);

    //display image 2 -- dilerod of adaptive threshold image
    GaussianBlur(dilerod, dilerod, Size(3, 3), 2, 2 );

    //mask for filtering out the cell of interest
    Mat mask_conv = Mat::zeros(height, width, CV_8UC1);
    fillConvexPoly(mask_conv, circle_ROI, Scalar(255));
    //imshow("mask_before", mask_conv);

    //dilate the mask -> region grows
    Mat mask_conv_dil;
    Mat element = getStructuringElement( MORPH_ELLIPSE,
                                         Size( 2*dilSize+1, 2*dilSize+1 ),
                                         Point(dilSize,dilSize) );
    dilate(mask_conv, mask_conv_dil, element);
    //imshow("mask_dil", mask_conv_dil);

    //bitwise AND on mask and dilerod
    bitwise_and(mask_conv_dil, dilerod, dispImg2);

    // findcontours
    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;
    unsigned int largest_contour_index;
    dilErodContours(dispImg2, contours, hierarchy, largest_contour_index, perimeter, dispImg1);

    // find the area of the cell by counting the white area inside the largest contour
    Mat cellArea = Mat::zeros(height, width, CV_8UC1);
    drawContours(cellArea, contours, largest_contour_index, Scalar(255), -1, 8, hierarchy, 0, Point() );
    //imshow("cellArea", cellArea);
    area = countNonZero(cellArea);

    //cout << "frame " << frameNum << "\n";
    //cout << contours[largest_contour_index] << endl;

    //renew circle points as the convex hull
    vector<Point> convHull;
    convexHull(contours[largest_contour_index], convHull);

    // find the centroid of the contour
    Moments mu = moments(contours[largest_contour_index]);
    ctroid = Point2f(mu.m10/mu.m00 + rect.x, mu.m01/mu.m00 + rect.y);

    // find the shape of the cell by the largest contour and centroid
    shape = findShape(ctroid, contours[largest_contour_index]);

    ////---- draw largest contour start ----
    //draw the largest contour
    Mat borderImg = Mat::zeros(height, width, CV_8UC1);
    drawContours(borderImg, contours, largest_contour_index, Scalar(255), 1, 8, hierarchy, 0, Point());
    //QString cellFileName0 = "border" + QString::number(frameNum) + ".png";
    //imwrite(cellFileName0.toStdString(), borderImg);


    Mat cell;
    bitwise_and(cellArea, sub, cell);
    //cell_alpha = createAlphaMat(cell);  // cell image with exactly the contour detected
    //vector<int> compression_params;
    //compression_params.push_back(CV_IMWRITE_PNG_COMPRESSION);
    //compression_params.push_back(9);
//    QString cellFileName1 = "cell" + QString::number(frameNum) + ".png";
//    imwrite(cellFileName1.toStdString(), cell_alpha, compression_params);
    ////---- draw largest contour end ----

    // find the number and the sizes of blebs of the cell
    Mat smooth;
    vector<Point> smoothCurve;
    int WIN = 25;
    smooth = curveSmooth(borderImg, WIN, contours[largest_contour_index], smoothCurve, convHull);
    //smooth = curveSmooth(borderImg, WIN, contours[largest_contour_index], smoothCurve, ctroid/*Point(ctroid.x, ctroid.y)*/);
    //drawPointVectors(dispImg1, smoothCurve, 1, Scalar(159, 120, 28));


    Mat smooth_contour;
    int w = 10;
    smooth_contour = curveSmooth(borderImg, w, contours[largest_contour_index], smooth_contour_curve, convHull);
    //smooth_contour = curveSmooth(borderImg, w, contours[largest_contour_index], smooth_contour_curve, ctroid/*Point(ctroid.x, ctroid.y)*/);
    //imshow("smooth_contour", smooth_contour);

    for(unsigned int i = 0; i < smooth_contour_curve.size(); i++){
         Point p(smooth_contour_curve[i].x + rect.x, smooth_contour_curve[i].y + rect.y);
         smooth_contour_curve_abs.push_back(p);
    }

//    cout << "ctroid X " << ctroid.x << " Y " << ctroid.y << endl;
////    for(unsigned int i = 0; i < contours[largest_contour_index].size(); i++)
////        cout << "(" << contours[largest_contour_index][i].x + rect.x << ", " << contours[largest_contour_index][i].y + rect.y << ") ";
////    cout << endl;
//    for(unsigned int i = 0; i < smooth_contour_curve_abs.size(); i++)
//        cout << "(" << smooth_contour_curve_abs[i].x << ", " << smooth_contour_curve_abs[i].y << ") ";
//    cout << endl;

    //cout << mask_conv_dil.type() << " " << sub.type() << endl;
    Mat cell_convex;
    bitwise_and(smooth_contour, sub, cell_convex);
    cell_alpha = createAlphaMat(cell_convex);
//    imshow("cell_convex_contour", cell_alpha);
    dispImg2 = cell_convex.clone();

    //change dispImg2 from gray to rgb for displaying
    cvtColor(dispImg2, dispImg2, CV_GRAY2RGB);

    bitwise_not(smooth, smooth);
    //Mat blebsImg;
    bitwise_and(smooth, cellArea, blebsImg);
//    imshow("blebs", blebsImg);
//    QString cellFileName2 = "blebs" + QString::number(frameNum) + ".png";
//    imwrite(cellFileName2.toStdString(), blebs);

    //QString cellFileName2 = "dispImg1" + QString::number(frameNum) + ".png";
    //imwrite(cellFileName2.toStdString(), dispImg1);

    cir_org.clear();
    for(unsigned int i = 0; i < convHull.size(); i++)
        cir_org.push_back(Point((convHull[i].x + rect.x)*scale, (convHull[i].y + rect.y)*scale));
}
Beispiel #30
0
// get ROI + edgeDectection
void FindContour::cellDetection(const Mat &img, vector<Point> &cir_org,
                                Mat &dispImg1, Mat &dispImg2,
                                vector<Point2f> &points1, vector<Point2f> &points2,
                                int &area,
                                int &perimeter,
                                Point2f &ctroid,
                                float &shape,
//                                vector<int> &blebs,
                                int &frameNum){
    frame = &img;
    //rect = boundingRect(Mat(cir));


    Mat frameGray;
    cv::cvtColor(*frame, frameGray, CV_RGB2GRAY);
/*
    QString cellFileName0 = "frame" + QString::number(frameNum) + ".png";
    imwrite(cellFileName0.toStdString(), frameGray);*/

    vector<Point> cir; //***global coordinates of circle***
    for(unsigned int i = 0; i < cir_org.size(); i++){
        cir.push_back(Point(cir_org[i].x / scale, cir_org[i].y / scale));
    }
    //cout << "original circle: " << cir_org << "\n" << " scaled circle: " << cir << endl;

    //enlarge the bounding rect by adding a margin (e) to it
    rect = enlargeRect(boundingRect(Mat(cir)), 5, img.cols, img.rows);

    //global circle mask
    Mat mask_cir_org = Mat::zeros(frame->size(), CV_8UC1);
    fillConvexPoly(mask_cir_org, cir, Scalar(255));

    // flow points
    vector<unsigned int> cell_pts_global;
    vector<Point2f> longOptflow_pt1, longOptflow_pt2;
    Point2f avrg_vec = Point2f(0,0);
    for(unsigned int i = 0; i < points1.size(); i++){
        Point p1 = Point(points1[i].x, points1[i].y);
        Point p2 = Point(points2[i].x, points2[i].y);
        if(mask_cir_org.at<uchar>(p1.y,p1.x) == 255 ){
            cell_pts_global.push_back(i);
            if(dist_square(p1, p2) > 2.0){
                longOptflow_pt1.push_back(Point2f(p1.x, p1.y));
                longOptflow_pt2.push_back(Point2f(p2.x, p2.y));
                avrg_vec.x += (p2.x-p1.x);
                avrg_vec.y += (p2.y-p1.y);
            }
        }
    }

//    if(longOptflow_pt1.size()!= 0){
//        avrg_vec.x = avrg_vec.x / longOptflow_pt1.size();
//        avrg_vec.y = avrg_vec.y / longOptflow_pt1.size();
//    }
    Rect trans_rect = translateRect(rect, avrg_vec);


    // ***
    // if (the homography is a good one) use the homography to update the rectangle
    // otherwise use the same rectangle
    // ***
    if (longOptflow_pt1.size() >= 4){
        Mat H = findHomography(Mat(longOptflow_pt1), Mat(longOptflow_pt2), CV_RANSAC, 2);
        //cout << "H: " << H << endl;

        if(determinant(H) >= 0){
            vector<Point> rect_corners;
            rect_corners.push_back(Point(rect.x, rect.y));
            rect_corners.push_back(Point(rect.x+rect.width, rect.y));
            rect_corners.push_back(Point(rect.x, rect.y+rect.height));
            rect_corners.push_back(Point(rect.x+rect.width, rect.y+rect.height));

            vector<Point> rect_update_corners = pointTransform(rect_corners, H);
            trans_rect = boundingRect(rect_update_corners);
        }
    }


    rectangle(frameGray, trans_rect, Scalar(255), 2);
    imshow("frameGray", frameGray);









    dispImg1 = (*frame)(rect).clone();
    //dispImg2 = Mat(dispImg1.rows, dispImg1.cols, CV_8UC3);

    Mat sub; //*** the rectangle region of ROI (Gray) ***
    cv::cvtColor(dispImg1, sub, CV_RGB2GRAY);
    int width = sub.cols;
    int height = sub.rows;

    vector<Point> circle_ROI; //***local coordinates of circle***
    for (unsigned int i = 0; i < cir.size(); i++){
        Point p = Point(cir[i].x - rect.x, cir[i].y - rect.y);
        circle_ROI.push_back(p);
    }

    Mat adapThreshImg1 = Mat::zeros(height, width, sub.type());
    //image edge detection for the sub region (roi rect)
    adaptiveThreshold(sub, adapThreshImg1, 255.0, ADAPTIVE_THRESH_GAUSSIAN_C,
                          CV_THRESH_BINARY_INV, blockSize, constValue);
    //imshow("adapThreshImg1", adapThreshImg1);

    // dilation and erosion
    Mat dilerod;
    dilErod(adapThreshImg1, dilerod, dilSize);

    //display image 2 -- dilerod of adaptive threshold image
    GaussianBlur(dilerod, dilerod, Size(3, 3), 2, 2 );

    //mask for filtering out the cell of interest
    Mat mask_conv = Mat::zeros(height, width, CV_8UC1);
    fillConvexPoly(mask_conv, circle_ROI, Scalar(255));
    //imshow("mask_before", mask_conv);

    //dilate the mask -> region grows
    Mat mask_conv_dil;
    Mat element = getStructuringElement( MORPH_ELLIPSE, Size( 2*2+2, 2*2+1 ), Point(2,2) );
    dilate(mask_conv, mask_conv_dil, element);
    //imshow("mask_dil", mask_conv_dil);



    /*
    Mat mask_conv_ero;
    erode(mask_conv, mask_conv_ero, element);
    Mat ring_dil, ring_ero;
    bitwise_xor(mask_conv, mask_conv_dil, ring_dil);
    bitwise_xor(mask_conv, mask_conv_ero, ring_ero);
    Mat ring;
    bitwise_or(ring_dil, ring_ero, ring);
    imshow("ring", ring);

    vector<unsigned int> opt_onRing_index;
    // use optflow info set rectangle
    for(unsigned int i = 0; i < points2.size(); i++){
        Point p2 = Point(points2[i].x, points2[i].y);
        Point p1 = Point(points1[i].x, points1[i].y);
        if(ring.at<uchar>(p1.y,p1.x) != 255 &&
                ring.at<uchar>(p2.y,p2.x) != 255)
            continue;
        else{
            opt_onRing_index.push_back(i);
        }
    }*/

    /*
    // draw the optflow on dispImg1
    unsigned int size = opt_inside_cl_index.size();
    for(unsigned int i = 0; i < size; i++ ){
        Point p0( ceil( points1[i].x - rect.x ), ceil( points1[i].y - rect.y ) );
        Point p1( ceil( points2[i].x - rect.x ), ceil( points2[i].y - rect.y) );
        //std::cout << "(" << p0.x << "," << p0.y << ")" << "\n";
        //std::cout << "(" << p1.x << "," << p1.y << ")" << std::endl;

        //draw lines to visualize the flow
        double angle = atan2((double) p0.y - p1.y, (double) p0.x - p1.x);
        double arrowLen = 0.01 * (double) (width);
        line(dispImg1, p0, p1, CV_RGB(255,255,255), 1 );
        Point p;
        p.x = (int) (p1.x + arrowLen * cos(angle + 3.14/4));
        p.y = (int) (p1.y + arrowLen * sin(angle + 3.14/4));
        line(dispImg1, p, p1, CV_RGB(255,255,255), 1 );
        p.x = (int) (p1.x + arrowLen * cos(angle - 3.14/4));
        p.y = (int) (p1.y + arrowLen * sin(angle - 3.14/4));

        line(dispImg1, p, Point(2*p1.x - p0.x, 2*p1.y - p0.y), CV_RGB(255,255,255), 1 );
        //line(dispImg1, p, p1, CV_RGB(255,255,255), 1 );
    }*/

/*
    //stop growing when meeting with canny edges that outside the circle

    Mat canny;
    CannyWithBlur(sub, canny);
    Mat cannyColor;
    cvtColor(canny, cannyColor, CV_GRAY2RGB);
    imwrite("canny.png", canny);
    vector<Point> outsideCircle;
    vector<Point> onRing;
    for(int j = 0; j < height; j++){
        for(int i = 0; i < width; i++){
            if(canny.at<uchar>(j,i) != 0 && mask_conv.at<uchar>(j,i) == 0){
                cannyColor.data[cannyColor.channels()*(cannyColor.cols*j + i)+0] = 81;
                cannyColor.data[cannyColor.channels()*(cannyColor.cols*j + i)+1] = 172;
                cannyColor.data[cannyColor.channels()*(cannyColor.cols*j + i)+2] = 251;
                outsideCircle.push_back(Point(i, j));
                if(ring.at<uchar>(j,i) != 0){
                    cannyColor.data[cannyColor.channels()*(cannyColor.cols*j + i)+0] = 255;
                    cannyColor.data[cannyColor.channels()*(cannyColor.cols*j + i)+1] = 255;
                    cannyColor.data[cannyColor.channels()*(cannyColor.cols*j + i)+2] = 0;
                    onRing.push_back(Point(i,j));
                }
            }
        }
    } */

//    QString cannyFileName = "canny" + QString::number(frameNum) + ".png";
//    imwrite(cannyFileName.toStdString(), cannyColor);



    //bitwise AND on mask and dilerod
    bitwise_and(mask_conv/*_dil*/, dilerod, dispImg2);

    // findcontours
    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;
    unsigned int largest_contour_index;
    dilErodContours(dispImg2, contours, hierarchy, largest_contour_index, perimeter, dispImg1);

    // find the area of the cell by counting the white area inside the largest contour
    Mat cellArea = Mat::zeros(height, width, CV_8UC1);
    drawContours(cellArea, contours, largest_contour_index, Scalar(255), -1, 8, hierarchy, 0, Point() );
    //imshow("cell", cell);
    area = countNonZero(cellArea);

    //cout << "frame " << frameNum << "\n";
    //cout << contours[largest_contour_index] << endl;


    //change dispImg2 from gray to rgb for displaying
    cvtColor(dispImg2, dispImg2, CV_GRAY2RGB);

    //renew circle points as the convex hull
    vector<Point> convHull;
    convexHull(contours[largest_contour_index], convHull);


    // find the centroid of the contour
    Moments mu = moments(contours[largest_contour_index]);
    ctroid = Point2f(mu.m10/mu.m00 + rect.x, mu.m01/mu.m00 + rect.y);

    // find the shape of the cell by the largest contour and centroid
    shape = findShape(ctroid, contours[largest_contour_index]);

    ////---- draw largest contour start ----
    //draw the largest contour
    Mat borderImg = Mat::zeros(height, width, CV_8UC1);
    drawContours(borderImg, contours, largest_contour_index, Scalar(255), 1, 8, hierarchy, 0, Point());
    //QString cellFileName0 = "border" + QString::number(frameNum) + ".png";
    //imwrite(cellFileName0.toStdString(), borderImg);
    ////---- draw largest contour end ----

    // find the number and the sizes of blebs of the cell
    Mat smooth;
    vector<Point> smoothCurve;
    int WIN = 25;
    vector< vector<Point> > tmp;
    smooth = curveSmooth(borderImg, WIN, contours[largest_contour_index], smoothCurve, convHull/*ctroid*/);
    tmp.push_back(smoothCurve);
    drawContours(dispImg1, tmp, 0, Scalar(255, 0, 0));

    bitwise_not(smooth, smooth);
    Mat blebsImg;
    bitwise_and(smooth, cellArea, blebsImg);
    //imshow("blebs", blebs);
    //QString cellFileName2 = "blebs" + QString::number(frameNum) + ".png";
    //imwrite(cellFileName2.toStdString(), blebs);

//    vector<Point> blebCtrs;
//    recursive_connected_components(blebsImg, blebs, blebCtrs);
//    for(unsigned int i = 0; i < blebCtrs.size(); i++){
//        circle(dispImg1, blebCtrs[i], 2, Scalar(255, 255, 0));
//    }


    cir_org.clear();
    for(unsigned int i = 0; i < convHull.size(); i++)
        cir_org.push_back(Point((convHull[i].x + rect.x)*scale, (convHull[i].y + rect.y)*scale));

}