예제 #1
0
RotatedRect::RotatedRect(const Point2f& _point1, const Point2f& _point2, const Point2f& _point3)
{
    Point2f _center = 0.5f * (_point1 + _point3);
    Vec2f vecs[2];
    vecs[0] = Vec2f(_point1 - _point2);
    vecs[1] = Vec2f(_point2 - _point3);
    double x = std::max(norm(_point1), std::max(norm(_point2), norm(_point3)));
    double a = std::min(norm(vecs[0]), norm(vecs[1]));
    // check that given sides are perpendicular
    CV_Assert( std::fabs(vecs[0].ddot(vecs[1])) * a <= FLT_EPSILON * 9 * x * (norm(vecs[0]) * norm(vecs[1])) );

    // wd_i stores which vector (0,1) or (1,2) will make the width
    // One of them will definitely have slope within -1 to 1
    int wd_i = 0;
    if( std::fabs(vecs[1][1]) < std::fabs(vecs[1][0]) ) wd_i = 1;
    int ht_i = (wd_i + 1) % 2;

    float _angle = std::atan(vecs[wd_i][1] / vecs[wd_i][0]) * 180.0f / (float) CV_PI;
    float _width = (float) norm(vecs[wd_i]);
    float _height = (float) norm(vecs[ht_i]);

    center = _center;
    size = Size2f(_width, _height);
    angle = _angle;
}
예제 #2
0
void Label::DoLayout(Rect boundaryRectangle)
{	
	LOGD(LOGTAG_INPUT,"Adding myself(Label) to layout. Rect = (%d,%d,%d,%d)",boundaryRectangle.x,boundaryRectangle.y,boundaryRectangle.width,boundaryRectangle.height);
	
	if (scaleToFit)
	{
		FitTextToBoundary(Size2f(boundaryRectangle.width,boundaryRectangle.height));
	}


	Point2i newPoint = Point2i( boundaryRectangle.x, boundaryRectangle.y);
	if (centerX || centerY)
	{
		if (centerY)
			newPoint.y =  boundaryRectangle.y + boundaryRectangle.height/2;
		if (centerX)
			newPoint.x = boundaryRectangle.x + boundaryRectangle.width/2;

		SetCenter(newPoint);	
	}
	else
	{
		Position = newPoint;
	}

}
예제 #3
0
vector<RotatedRect> CControl::GetRotatedRect(Point2i n_ptcenter)
{
  float n_degreestep;
  if(nControlOptions.nAngelCout<10)
    n_degreestep=180/nControlOptions.nAngelCout;
  else
    n_degreestep=360/nControlOptions.nAngelCout;
  vector<RotatedRect> n_rotatedrectvct;
  for(int i=0;i<nControlOptions.nAngelCout;i++)
    {
      float n_degree=i*n_degreestep;
      RotatedRect n_rotatedrect(Point2f(n_ptcenter.x,n_ptcenter.y),Size2f(nControlOptions.nWidth,nControlOptions.nHeight),n_degree);
      //检查角点
      Point2f n_vertices[4];
      n_rotatedrect.points(n_vertices);
      bool n_inside=true;
      for(int j=0;j<4;j++)
	if(!CheckBoundary(n_vertices[j]))
	  n_inside=false;
      //检查外包矩形是否在图像内(旋转需要)
      Rect n_boundrect=n_rotatedrect.boundingRect();
      Point2f n_pttl=n_boundrect.tl();
      Point2f n_ptbr=n_boundrect.br();
      if(!CheckBoundary(n_pttl)||!CheckBoundary(n_ptbr))
	n_inside=false;

      if(!n_inside)
	continue;
      n_rotatedrectvct.push_back(n_rotatedrect);
    }
   return n_rotatedrectvct;
}
예제 #4
0
vector<RotatedRect> CControl::GetRotatedRect(Point2i n_ptcenter,vector<float> n_anglevct)
{
  vector<RotatedRect> n_rotatedrectvct;
  for(int i=0;i<n_anglevct.size();i++)
    {
      float n_degree=n_anglevct.at(i);
      RotatedRect n_rotatedrect(Point2f(n_ptcenter.x,n_ptcenter.y),Size2f(nControlOptions.nWidth,nControlOptions.nHeight),n_degree);
      //检查角点
      Point2f n_vertices[4];
      n_rotatedrect.points(n_vertices);
      bool n_inside=true;
      for(int j=0;j<4;j++)
	if(!CheckBoundary(n_vertices[j]))
	  n_inside=false;
      /*
      //检查外包矩形是否在图像内(旋转需要)
      Rect n_boundrect=n_rotatedrect.boundingRect();
      Point2f n_pttl=n_boundrect.tl();
      Point2f n_ptbr=n_boundrect.br();
      if(!CheckBoundary(n_pttl)||!CheckBoundary(n_ptbr))
	n_inside=false;
      */
      if(!n_inside)
	continue;
      n_rotatedrectvct.push_back(n_rotatedrect);
    }
   return n_rotatedrectvct;
}
예제 #5
0
RotatedRect CamShift( const Mat& probImage, Rect& window,
                      TermCriteria criteria )
{
    CvConnectedComp comp;
    CvBox2D box;
    CvMat _probImage = probImage;
    cvCamShift(&_probImage, window, (CvTermCriteria)criteria, &comp, &box);
    window = comp.rect;
    return RotatedRect(Point2f(box.center), Size2f(box.size), box.angle);
}
예제 #6
0
vector<Rect> CharacterSegmenter::combineCloseBoxes( vector<Rect> charBoxes, float biggestCharWidth)
{
  vector<Rect> newCharBoxes;
  
  for (int i = 0; i < charBoxes.size(); i++)
  {
    if (i == charBoxes.size() - 1)
    {
	newCharBoxes.push_back(charBoxes[i]);
	break;
    }
    float bigWidth = (charBoxes[i + 1].x + charBoxes[i + 1].width - charBoxes[i].x);
    
    float w1Diff = abs(charBoxes[i].width - biggestCharWidth);
    float w2Diff = abs(charBoxes[i + 1].width - biggestCharWidth);
    float bigDiff = abs(bigWidth - biggestCharWidth);
    bigDiff *= 1.3;	// Make it a little harder to merge boxes. 
    
    if (bigDiff < w1Diff && bigDiff < w2Diff)
    {
      Rect bigRect(charBoxes[i].x, charBoxes[i].y, bigWidth, charBoxes[i].height);
      newCharBoxes.push_back(bigRect);
      if (this->config->debugCharSegmenter)
      {
	for (int z = 0; z < charAnalysis->thresholds.size(); z++)
	{
	  Point center(bigRect.x + bigRect.width / 2, bigRect.y + bigRect.height / 2);
	  RotatedRect rrect(center, Size2f(bigRect.width, bigRect.height + (bigRect.height / 2)), 0);
	  ellipse(imgDbgCleanStages[z], rrect, Scalar(0,255,0), 1);
	}
	cout << "Merging 2 boxes -- " << i << " and " << i + 1 << endl;
      }
      
      i++;
    }
    else
    {
	newCharBoxes.push_back(charBoxes[i]);
    }
    
    
    
  }
  
  return newCharBoxes;
}
예제 #7
0
    int getGroundTruth(map<string, vector<CPlate>>& xmlMap, const char* path) {

#ifdef OS_WINDOWS
      XMLNode::setGlobalOptions(XMLNode::char_encoding_GBK);
#endif
      XMLNode xMainNode = XMLNode::openFileHelper(path, "tagset");

      int n = xMainNode.nChildNode("image");

      // this prints the "coefficient" value for all the "NumericPredictor" tags:
      for (int i = 0; i < n; i++) {
        XMLNode imageNode = xMainNode.getChildNode("image", i);
        string imageName = imageNode.getChildNode("imageName").getText();

        vector<CPlate> plateVec;
        int m = imageNode.getChildNode("taggedRectangles").nChildNode("taggedRectangle");
        for (int j = 0; j < m; j++) {
          XMLNode plateNode = imageNode.getChildNode("taggedRectangles").getChildNode("taggedRectangle", j);

          int x = atoi(plateNode.getAttribute("x"));
          int y = atoi(plateNode.getAttribute("y"));
          int width = atoi(plateNode.getAttribute("width"));
          int height = atoi(plateNode.getAttribute("height"));
          int angle = atoi(plateNode.getAttribute("rotation"));

          string plateStr = plateNode.getText();

          RotatedRect rr(Point2f(float(x), float(y)), Size2f(float(width), float(height)), angle);

          CPlate plate;
          plate.setPlateStr(plateStr);
          plate.setPlatePos(rr);
          plateVec.push_back(plate);
        }

        xmlMap[imageName] = plateVec;
      }

      return 0;
    }
예제 #8
0
void FindObjectMain::process_camshift()
{
// Some user defined parameters
	int vmin = config.vmin;
	int vmax = config.vmax;
	int smin = config.smin;
	float hranges[] = { 0, 180 };
	const float* phranges = hranges;


// Create aligned, RGB images
	if(!object_image)
	{
		object_image = cvCreateImage( 
			cvSize(object_image_w, object_image_h), 
			8, 
			3);
	}

	if(!scene_image)
	{
		scene_image = cvCreateImage( 
			cvSize(scene_image_w, scene_image_h), 
			8, 
			3);
	}

// Temporary row pointers
	unsigned char **object_rows = new unsigned char*[object_image_h];
	unsigned char **scene_rows = new unsigned char*[scene_image_h];
	for(int i = 0; i < object_image_h; i++)
	{
		object_rows[i] = (unsigned char*)(object_image->imageData + i * object_image_w * 3);
	}
	for(int i = 0; i < scene_image_h; i++)
	{
		scene_rows[i] = (unsigned char*)(scene_image->imageData + i * scene_image_w * 3);
	}

// Transfer object & scene to RGB images for OpenCV
	if(!prev_object) prev_object = new unsigned char[object_image_w * object_image_h * 3];
// Back up old object image
	memcpy(prev_object, object_image->imageData, object_image_w * object_image_h * 3);

	BC_CModels::transfer(object_rows,
		get_input(object_layer)->get_rows(),
		0,
		0,
		0,
		0,
		0,
		0,
		object_x1,
		object_y1,
		object_w,
		object_h,
		0,
		0,
		object_w,
		object_h,
		get_input(object_layer)->get_color_model(),
		BC_RGB888,
		0,
		0,
		0);
	BC_CModels::transfer(scene_rows,
		get_input(scene_layer)->get_rows(),
		0,
		0,
		0,
		0,
		0,
		0,
		scene_x1,
		scene_y1,
		scene_w,
		scene_h,
		0,
		0,
		scene_w,
		scene_h,
		get_input(scene_layer)->get_color_model(),
		BC_RGB888,
		0,
		0,
		0);

	delete [] object_rows;
	delete [] scene_rows;

// from camshiftdemo.cpp
// Compute new object	
	if(memcmp(prev_object, 
		object_image->imageData, 
		object_image_w * object_image_h * 3) ||
		!hist.dims)
	{
		Mat image(object_image);
		Mat hsv, hue, mask;
		cvtColor(image, hsv, CV_RGB2HSV);
    	int _vmin = vmin, _vmax = vmax;
//printf("FindObjectMain::process_camshift %d\n", __LINE__);

    	inRange(hsv, 
			Scalar(0, smin, MIN(_vmin,_vmax)),
        	Scalar(180, 256, MAX(_vmin, _vmax)), 
			mask);
    	int ch[] = { 0, 0 };
    	hue.create(hsv.size(), hsv.depth());
    	mixChannels(&hsv, 1, &hue, 1, ch, 1);

		Rect selection = Rect(0, 0, object_w, object_h);
		trackWindow = selection;
		int hsize = 16;
		Mat roi(hue, selection), maskroi(mask, selection);
		calcHist(&roi, 1, 0, maskroi, hist, 1, &hsize, &phranges);
		normalize(hist, hist, 0, 255, CV_MINMAX);
	}


// compute scene
	Mat image(scene_image);
	Mat hsv, hue, mask, backproj;
	cvtColor(image, hsv, CV_RGB2HSV);
    int _vmin = vmin, _vmax = vmax;

    inRange(hsv, 
		Scalar(0, smin, MIN(_vmin,_vmax)),
        Scalar(180, 256, MAX(_vmin, _vmax)), 
		mask);
    int ch[] = {0, 0};
    hue.create(hsv.size(), hsv.depth());
    mixChannels(&hsv, 1, &hue, 1, ch, 1);
	
//printf("FindObjectMain::process_camshift %d %d %d\n", __LINE__, hist.dims, hist.size[1]);
	RotatedRect trackBox = RotatedRect(
		Point2f((object_x1 + object_x2) / 2, (object_y1 + object_y2) / 2), 
		Size2f(object_w, object_h), 
		0);
	trackWindow = Rect(0, 
		0,
        scene_w, 
		scene_h);
	if(hist.dims > 0)
	{
		

		calcBackProject(&hue, 1, 0, hist, backproj, &phranges);
		backproj &= mask;
//printf("FindObjectMain::process_camshift %d\n", __LINE__);
// 		if(trackWindow.width <= 0 ||
// 			trackWindow.height <= 0)
// 		{
// 			trackWindow.width = object_w;
// 			trackWindow.height = object_h;
// 		}

		trackBox = CamShift(backproj, 
			trackWindow,
        	TermCriteria( CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1 ));
//printf("FindObjectMain::process_camshift %d\n", __LINE__);


//     	if( trackWindow.area() <= 1 )
//     	{
//         	int cols = backproj.cols;
// 			int rows = backproj.rows;
// 			int r = (MIN(cols, rows) + 5) / 6;
//         	trackWindow = Rect(trackWindow.x - r, trackWindow.y - r,
//                         	   trackWindow.x + r, trackWindow.y + r) &
//                     	  Rect(0, 0, cols, rows);
//     	}
	}
// printf("FindObjectMain::process_camshift %d %d %d %d %d\n", 
// __LINE__,
// trackWindow.x,
// trackWindow.y,
// trackWindow.width,
// trackWindow.height);


// Draw mask over scene
	if(config.draw_keypoints)
	{
		for(int i = 0; i < scene_h; i++)
		{
			switch(get_input(scene_layer)->get_color_model())
			{
				case BC_YUV888:
				{
					unsigned char *input = backproj.data + i * scene_image_w;
					unsigned char *output = get_input(scene_layer)->get_rows()[i + scene_y1] + scene_x1 * 3;
					for(int j = 0; j < scene_w; j++)
					{
						output[0] = *input;
						output[1] = 0x80;
						output[2] = 0x80;
						output += 3;
						input++;
					}
					break;
				}
			}
		}
	}

// Get object outline in the scene layer
// printf("FindObjectMain::process_camshift %d %d %d %d %d %d\n", 
// __LINE__,
// (int)trackBox.center.x,
// (int)trackBox.center.y,
// (int)trackBox.size.width,
// (int)trackBox.size.height,
// (int)trackBox.angle);
	double angle = trackBox.angle * 2 * M_PI / 360;
	double angle1 = atan2(-(double)trackBox.size.height / 2, -(double)trackBox.size.width / 2) + angle;
	double angle2 = atan2(-(double)trackBox.size.height / 2, (double)trackBox.size.width / 2) + angle;
	double angle3 = atan2((double)trackBox.size.height / 2, (double)trackBox.size.width / 2) + angle;
	double angle4 = atan2((double)trackBox.size.height / 2, -(double)trackBox.size.width / 2) + angle;
	double radius = sqrt(SQR(trackBox.size.height / 2) + SQR(trackBox.size.width / 2));
	border_x1 = (int)(trackBox.center.x + cos(angle1) * radius) + scene_x1;
	border_y1 = (int)(trackBox.center.y + sin(angle1) * radius) + scene_y1;
	border_x2 = (int)(trackBox.center.x + cos(angle2) * radius) + scene_x1;
	border_y2 = (int)(trackBox.center.y + sin(angle2) * radius) + scene_y1;
	border_x3 = (int)(trackBox.center.x + cos(angle3) * radius) + scene_x1;
	border_y3 = (int)(trackBox.center.y + sin(angle3) * radius) + scene_y1;
	border_x4 = (int)(trackBox.center.x + cos(angle4) * radius) + scene_x1;
	border_y4 = (int)(trackBox.center.y + sin(angle4) * radius) + scene_y1;

}
void QRFinder::FindFinderPatterns(cv::Mat& inputImg, Rect regionOfInterest, vector<FinderPattern*> & finderPatterns, vector<Drawable*> & debugVector)
{
	struct timespec start,end;
	SET_TIME(&start);	

	//Get parameters from config
	edgeThreshold = config->GetIntegerParameter("EdgeThreshold");
	debugLevel = config->GetIntegerParameter("QR Debug Level");
	int verticalResolution = config->GetIntegerParameter("YResolution");
	nonMaxEnabled = config->GetBooleanParameter("EdgeNonMax");
	minimumFinderPatternScore = config->GetIntegerParameter("MinimumFPScore");
	detectorSize = config->GetIntegerParameter("DetectorSize");

	int yBorder = detectorSize;
	vector<Point3i> exclusionZones;
	
	//Calculate limits
	int maxColumn = regionOfInterest.x + regionOfInterest.width;
	maxColumn -= detectorSize;	
	int maxRow = regionOfInterest.y + regionOfInterest.height;
	int xStart = regionOfInterest.x;
	int yStart = regionOfInterest.y;
	xStart += detectorSize;
	yStart += detectorSize;
	maxColumn -= detectorSize;
	maxRow -= detectorSize;

	
	if (debugLevel > 0)
		debugVector.push_back(new DebugRectangle(Rect(Point2i(xStart,yStart),Point2i(maxColumn,maxRow)),Colors::Aqua,1));

	
	//Find horizontal edges
	SET_TIME(&start);
	FindEdgesClosed(inputImg,regionOfInterest,edgeArray,edgeThreshold,nonMaxEnabled,detectorSize);
	SET_TIME(&end);
	double edgeTime_local = calc_time_double(start,end);
	edgeTime = (edgeTime + edgeTime_local)/2.0;
	config->SetLabelValue("EdgeTime",(float)edgeTime/1000.0f);
	
	//If debug level set, find all vertical edges and draw them
	if (debugLevel <= -2)
	{
		for (int x = 1; x < verticalEdgeArray.rows-1; x ++)
		{
			FindEdgesVerticalClosed(inputImg,x);		
			const short * verticalEdgePtr = verticalEdgeArray.ptr<short>(x);
			for (int y = 0; y < (verticalEdgeArray.cols);y++)
			{
				short transition = verticalEdgePtr[y];
				if (transition < 0)
				{
					debugVector.push_back(new DebugCircle(Point2i(x,y),0,Colors::Fuchsia,true));
				}
				else if (transition > 0)
				{
					debugVector.push_back(new DebugCircle(Point2i(x,y),0,Colors::Cyan,true));
				}
			}
		}	
	}
	//END
	
	
	int bw[6] = { 0 };
	int k = 0;
	//LOGV(LOGTAG_QR,"ImgSize=[%d,%d] EdgeSize=[%d,%d]",inputImg.rows,inputImg.cols,edgeArray.rows,edgeArray.cols);

	int yDirection = 1;
	int yCenter = yStart + (maxRow - yStart)/2;
	int y = yStart, absOffset = 0;

	LOGV(LOGTAG_QR,"Beginning search. y[%d->%d], Center=%d, x[%d->%d]",yStart,maxRow,yCenter,xStart,maxColumn);
	
	while (y < maxRow && y >= yStart)
	{	
		y = yCenter + absOffset * yDirection;

		if (yDirection == 1) absOffset += verticalResolution;	//Increment every other frame		
		yDirection = -yDirection;								//Change direction every frame

		k = 0;
		bw[0] = bw[1] = bw[2] = bw[3] = bw[4] = bw[5] = 0;

		const short * edgeRowPtr = edgeArray.ptr<short>(y);
		for (int x = xStart; x < maxColumn; x++)
		{
			if (isInRadius(exclusionZones,Point2i(x,y)))
				continue;

			int transition =  edgeRowPtr[x]; //getTransition(Mi,x,threshold);

			
			if (k == 0) //Haven't found edge yet
			{
				if (transition < 0) /* Light->dark transistion */
				{					
					k++;
				}
			}
			else //Found at least one edge
			{
				if ((k & 1) == 1) //Counting dark
				{
					if (transition > 0) //dark to light
					{					
						++k;
					}
				}
				else //Counting light
				{
					if (transition < 0) //light to dark
					{					
						++k;
					}
				}
			}

			if (k > 0) ++bw[k-1];

			if (FP_DEBUG_ENABLED && (debugLevel == -1 || debugLevel == -2))
			{				
				if (transition < 0)
					debugVector.push_back(new DebugCircle(Point2i(x,y),0,Colors::Lime,true));
				else if (transition > 0)
					debugVector.push_back(new DebugCircle(Point2i(x,y),0,Colors::Yellow,true));

				
			}	


			if (k == 6)
			{		
				int result = 0;
				result = CheckRatios(bw,NULL);

				if (result == 1)
				{	
					//LOGV(LOGTAG_QR,"Ratio check pass");
					//Center based on initial ratio					
					float patternCenterWidth = (float)bw[2];
					int tempXCenter = (x - bw[4] - bw[3]) - (int)round(patternCenterWidth/2.0f); 
					float xOffset = (patternCenterWidth/6.0f);
					
					//y coordinate of center. If check fails, returns 0.
					int tempYCenterArray[] = {0,0,0};

					int * verticalPatternSizes[3];

					for (int i = 0;i < 3;i++)
						verticalPatternSizes[i] = new int[5];

					tempYCenterArray[0] = FindCenterVertical(inputImg, tempXCenter, y, bw, debugVector,verticalPatternSizes[0]);
					tempYCenterArray[1] = FindCenterVertical(inputImg, tempXCenter - xOffset, y, bw, debugVector,verticalPatternSizes[1]);
					tempYCenterArray[2] = FindCenterVertical(inputImg, tempXCenter + xOffset, y, bw, debugVector,verticalPatternSizes[2]);
										
					int tempYCenter = 0;
					int passCount = 0;
					float avgYSize = 0;

					int averageVerticalSize[5] = {0,0,0,0,0};

					for (int yTest = 0; yTest < 3; yTest++)
					{
						if (tempYCenterArray[yTest] > 0)
						{
							passCount++;
							tempYCenter += tempYCenterArray[yTest];
							for (int i=0;i<5;i++)
							{
								averageVerticalSize[i] += (verticalPatternSizes[yTest])[i];
								avgYSize += (verticalPatternSizes[yTest])[i]; 
							}
						}						
					}

					if (passCount >= 2)
					{
						//LOGV(LOGTAG_QR,"Vertical test pass-1");
						
						tempYCenter = (int)round((float)tempYCenter / (float)passCount);
						avgYSize = (float)avgYSize / (float)passCount;

						int allowedVariance = (int)avgYSize >> 2;
						bool yVarianceTest = true;
						for (int yTest = 0; yTest < 3; yTest++)
						{
							if (tempYCenterArray[yTest] > 0)
							{
								if (abs(tempYCenterArray[yTest] - tempYCenter) > allowedVariance)
								{
									yVarianceTest = false;
									break;
								}
							}						
						}

						if (yVarianceTest)
						{
							//LOGV(LOGTAG_QR,"Vertical test pass-2. Passcount=%d",passCount);
							//Average the vertical pattern sizes
							for (int i=0;i<5;i++)
							{
								averageVerticalSize[i] = idiv(averageVerticalSize[i],passCount);
							}
							//LOGV(LOGTAG_QR,"Averaged sizes. Center=%d",averageVerticalSize[2]);

							int tempXCenterArray[] = {0,0,0};
							int xSizeArray[] = {0,0,0};
							int yOffset = idiv(averageVerticalSize[2],6.0f);

							//LOGV(LOGTAG_QR,"Yoffset=%d,yCenter=%d",yOffset,tempYCenter);
							tempXCenterArray[0] = FindCenterHorizontal(tempXCenter, tempYCenter-yOffset, bw, xSizeArray[0], debugVector); 
							tempXCenterArray[1] = FindCenterHorizontal(tempXCenter, tempYCenter, bw, xSizeArray[1], debugVector); 
							tempXCenterArray[2] = FindCenterHorizontal(tempXCenter, tempYCenter+yOffset, bw, xSizeArray[2], debugVector); 

							tempXCenter = 0;
							passCount = 0;
							float avgXSize = 0;

							for (int xTest = 0; xTest < 3; xTest++)
							{
								if (tempXCenterArray[xTest] > 0)
								{
									passCount++;
									tempXCenter += tempXCenterArray[xTest];
									avgXSize += xSizeArray[xTest];
								}						
							}

							if (passCount >= 2)
							{
								
								//LOGV(LOGTAG_QR,"Horizontal test pass");
								tempXCenter = (int)round((float)tempXCenter / (float)passCount);
								avgXSize = (float)avgXSize/(float)passCount;
								//allowedVariance = (int)round((float)avgYSize/1.5f);
								float aspectRatio = avgXSize/avgYSize;
								
								if (aspectRatio > 0.33f && aspectRatio < 3.0f)
								{
									
									//LOGV(LOGTAG_QR,"Size test pass");
									Point2i finderPatternCenter = Point2i(tempXCenter,tempYCenter); //Center of finder pattern

									int finderPatternSize =  MAX(avgXSize,avgYSize);
									int fpRadius = (int)round((float)finderPatternSize/2.0f);
									int fpRadiusExclude = ipow(finderPatternSize,2);

									//LOGD(LOGTAG_QR,"Creating new pattern[%d,%d]",avgXSize,avgYSize);
									//Create a new pattern
									FinderPattern * newPattern = new FinderPattern(finderPatternCenter,Size2i(avgXSize,avgYSize));
									Size2f patternSearchSize = Size2f(avgXSize,avgYSize);

									vector<Point2i> corners;
									struct timespec fastStart,fastEnd;
									SET_TIME(&fastStart);
									fastQRFinder->LocateFPCorners(inputImg,newPattern,corners,debugVector);
//									fastQRFinder->CheckAlignmentPattern(inputImg,finderPatternCenter,patternSearchSize,corners,debugVector);
									SET_TIME(&fastEnd);
									double fastFPTime_Local = calc_time_double(fastStart,fastEnd);
									fastFPTime += fastFPTime_Local;
									if (corners.size() == 4)
									{
										//if (validatePattern(newPattern,finderPatterns))
										//{
										newPattern->patternCorners = corners;
										exclusionZones.push_back(Point3i(finderPatternCenter.x,finderPatternCenter.y, fpRadiusExclude));
										finderPatterns.push_back(newPattern);
										if (FP_DEBUG_ENABLED && debugLevel > 0)
										{
											debugVector.push_back(new DebugCircle(finderPatternCenter,fpRadius,Colors::MediumSpringGreen,1,true));
											for (int i=0;i<corners.size();i++)
											{
												if (FP_DEBUG_ENABLED && debugLevel > 0)
													debugVector.push_back(new DebugCircle(corners[i],10,Colors::DodgerBlue,2));
											}
										}
										//}
										//else
										//{
										//	//LOGV(LOGTAG_QR,"Compare check failed");
										//	if (FP_DEBUG_ENABLED && debugLevel > 0)
										//		debugVector.push_back(new DebugCircle(finderPatternCenter,fpRadius,Colors::HotPink,2));
										//}
									}
									else
									{
										
										//LOGV(LOGTAG_QR,"FAST check failed");
										if (FP_DEBUG_ENABLED && debugLevel > 0)
											debugVector.push_back(new DebugCircle(finderPatternCenter,fpRadius,Colors::Red,2));
										delete newPattern;
									}
								}
								else
								{
									//LOGV(LOGTAG_QR,"Size check failed");
									//Size check failed
									if (FP_DEBUG_ENABLED && debugLevel > 1)
										debugVector.push_back(new DebugCircle(Point2i(tempXCenter,tempYCenter),13, Colors::HotPink,1));
								}
							}
							else
							{
								//LOGV(LOGTAG_QR,"Horizontal check failed");
								//Vertical check succeeded, but horizontal re-check failed
								if (FP_DEBUG_ENABLED && debugLevel > 1)
									debugVector.push_back(new DebugCircle(Point2i(tempXCenter,tempYCenter),12, Colors::OrangeRed,1));
							}
						}
						else
						{
							//LOGV(LOGTAG_QR,"Variance test failed. AllowedVariance = %d, yCenters = %d,%d,%d [avg=%d], AvgYSize=%d",allowedVariance,tempYCenterArray[0],tempYCenterArray[1],tempYCenterArray[2],tempYCenter,avgYSize);
							//Vertical variance test failed
							if (FP_DEBUG_ENABLED && debugLevel > 1)
								debugVector.push_back(new DebugCircle(Point2i(tempXCenter,tempYCenter),14, Colors::MediumSpringGreen,1));
						}

					} else
					{
						//Ratios were correct but vertical check failed
						if (FP_DEBUG_ENABLED && debugLevel > 2)
						{
							if (tempYCenter == 0) //ratio fail
								debugVector.push_back(new DebugCircle(Point2i(tempXCenter,y),10,Colors::Aqua,1));
							else if (tempYCenter == -1)	//topcheck fail				
								debugVector.push_back(new DebugCircle(Point2i(tempXCenter,y),10,Colors::Orange,1));
							else if (tempYCenter == -2)	//bottomcheck fail							
								debugVector.push_back(new DebugCircle(Point2i(tempXCenter,y),10,Colors::Lime,1));
						}
					}
				}
	Size2f getSize() const {
		return Size2f(0, 0);
	}
예제 #11
0
int DetectorBarcode::Detect() {
    std::cout << "DetectorBarcode::Detect()" << std::endl;

    assert(this->image_.data != NULL);

    bool debugstripecode = true; //@TODO MAKE SURE TO SET ME TO FALSE IN PRODUCTION
    bool useAdaptiveThersholding = true;

    int dpi = 400; //this works well for all scales and sizes..

    Mat matImageK;
    cvtColor(this->image_, matImageK, cv::COLOR_BGR2GRAY);
    cv::Mat matThres;

    // VARIABLES //
    double bar_height_mm_min = 3.7; //[7.5mm=our NMNH c39] [10.7mm=NMNH cover c39]
    double bar_height_mm_max = 20;

    double bar_ar_min = 4;
    double bar_ar_max = 110;

    int min_characters = 5; //minimum characters in barcode string

    double bar_dist_group_mm_max = 9.0; //Maximum distance between any grouped bar to be part of the bar group

    // COMPUTE //
    double bar_height_px_min = bar_height_mm_min/25.4*dpi;
    double bar_height_px_max = bar_height_mm_max/25.4*dpi;

    double bar_area_px_min = bar_height_px_min*(bar_height_px_min*1.0/bar_ar_max);

    //Dont allow the area to be less than 1px row
    bar_area_px_min = bar_area_px_min < bar_height_px_min ? bar_height_px_min : bar_area_px_min;

    double bar_area_px_max = bar_height_px_max*(bar_height_px_max*1.0/bar_ar_min);

    double bar_dist_group_px_max = bar_dist_group_mm_max/25.4*dpi;

    if (useAdaptiveThersholding) {
        //int AT_blocksize = dpi*0.05; 
        int AT_blocksize = bar_height_px_min*0.5;
        int AT_iseven=AT_blocksize%2;
        AT_blocksize += 1+AT_iseven; //Makes sure the blocksize is an even number
        //cout << "AT_blocksize=" << AT_blocksize << endl;
        adaptiveThreshold(matImageK, matThres, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, AT_blocksize, 20);
    } else {
        threshold(matImageK, matThres, 127, 255, THRESH_BINARY_INV);
    }

    if (debugstripecode) {
        //cout << "dpi=" << dpi << endl;
        imwrite("/Users/tzaman/Desktop/bc/matImage.tif", this->image_);
        imwrite("/Users/tzaman/Desktop/bc/matThres.tif", matThres);
    }

    vector< vector<Point> > contours;
    vector<Vec4i> hierarchy;
    findContours( matThres, contours, hierarchy, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE );
    
    //cout << "contours.size()=" << contours.size() << endl;
    
    if (contours.size() == 0) {
        string strErr = "No contours found.";
        cout << strErr << endl;
        return RET_NONE_FOUND;
    }

    //RANSAC vars
    int min_inliers = (min_characters+2)*5*0.75; //+2 (start&stop), *5 (stripes per char), *0.x (margin)
    double max_px_dist = (bar_height_px_min+bar_height_px_max)*0.5*0.05; //Maximum distance from RANSAC line to a point

    vector<RotatedRect> stripeCandidates;
    for(int i = 0; i >= 0; i = hierarchy[i][0] ) {
        double cArea = contourArea( contours[i],false); 
        if (cArea < bar_area_px_min*0.5){
            continue;
        }
        if (cArea > bar_area_px_max){
            continue;
        }
        //cout << "[" << i << "]" << " cArea=" << cArea << endl;

        RotatedRect rotRect= minAreaRect(contours[i]);
        double ar = max(double(rotRect.size.width),double(rotRect.size.height)) / min(double(rotRect.size.width),double(rotRect.size.height));

        if (ar < bar_ar_min){
            continue;
        }
        if (ar > bar_ar_max){
            continue;
        }

        double width = std::min(rotRect.size.width, rotRect.size.height);
        double height = std::max(rotRect.size.width, rotRect.size.height);

        //Check the length
        if (height < bar_height_px_min){
            //Stripe too small
            continue;
        }

        if (height > bar_height_px_max ){
            //Stripe too long
            continue;
        }


        //cout << i << " rotRect: sz=" << rotRect.size << " cp=" << rotRect.center << " a=" << rotRect.angle << " ar=" << ar << endl;


        Rect rCrop = boundingRect(contours[i]);

        //Below parameter is dynamic, plz note
        double min_area_fill=0.15;// = 0.25 ;// 0.4 means 40% of the bounding rectangle of the contour needs to be filled
        //The min_area_fill threshold should be dependent on the width in pixels, because there's more noise in thinner ones
        if (width<3){
            min_area_fill = 0.05;
        } else if (width <5){
            min_area_fill = 0.10;
        }


        //Check if the rectangle is actually filled well
        int fullarea = rCrop.area();

        
        if ( (double(cArea)/double(fullarea)) < min_area_fill){
            continue;
        }

        //cout << i << " fullarea=" << fullarea << " carea=" << cArea << endl;

        if (debugstripecode){
            imwrite("/Users/tzaman/Desktop/seg/" + std::to_string(i) +  ".tif", matImageK(rCrop));
        }
        stripeCandidates.push_back(rotRect);
    }


    if (debugstripecode){
        Mat matBarcodeFull = this->image_.clone();
        for (int j=0; j<stripeCandidates.size(); j++){
            util::rectangle(matBarcodeFull, stripeCandidates[j], cv::Scalar(255,0,0), 2);
        }
        imwrite("/Users/tzaman/Desktop/bc/_candidates.tif", matBarcodeFull);
    }


    //cout << "stripeCandidates.size()=" << stripeCandidates.size() << endl;

    if (stripeCandidates.size() < min_inliers){
        string strErr = "Code 39 did not find enough bars to accurately make a code.";
        cout << strErr << endl;
        return RET_NONE_FOUND;
    }
    
    std::vector<Point> vecPtRectCenter = util::vecrotrect2vecpt(stripeCandidates);
    std::vector<std::vector<int> > vecGroupIdxs = util::groupPoints(vecPtRectCenter, bar_dist_group_px_max, min_inliers);
    //std::vector<std::vector<cv::Point> > vecGroupPts(vecGroupIdxs.size());
    std::vector<std::vector<cv::RotatedRect> > vecGroupRects(vecGroupIdxs.size());

    //Relate indexes to points and add to group vector
    for (int i=0; i<vecGroupIdxs.size(); i++){
        //vecGroupPts[i].resize(vecGroupIdxs[i].size());
        vecGroupRects[i].resize(vecGroupIdxs[i].size());
        for (int j=0; j<vecGroupIdxs[i].size(); j++){
            //cout << i << "," << j << endl;
            //vecGroupPts[i][j] = vecPtRectCenter[vecGroupIdxs[i][j]];
            vecGroupRects[i][j] = stripeCandidates[vecGroupIdxs[i][j]];
        }
    }

    //Draw all groups
    //if(debugstripecode){
    //  for (int i=0; i<vecGroupPts.size(); i++){
    //      Mat matGroup = matImage.clone();
    //      for (int j=0; j<vecGroupPts[i].size(); j++){
    //          circle(matGroup, vecGroupPts[i][j], 5, Scalar(255,0,255), 1, CV_AA,0);              
    //      }
    //      imwrite("/Users/tzaman/Desktop/bc/_group_" + std::to_string(i) + ".tif", matGroup);
    //  }
    //}
    //exit(-1);

    //cout << "vecGroupPts.size()=" << vecGroupPts.size() << endl;
    //Erase small groups
    //for (int i=vecGroupPts.size()-1; i>=0; i--){
    //  if (vecGroupPts[i].size() < min_inliers){
    //      //Skipping group, too small.
    //      vecGroupIdxs.erase(vecGroupIdxs.begin()+i);
    //      vecGroupPts.erase(vecGroupPts.begin()+i);
    //  }
    //}
    //cout << "vecGroupPts.size()=" << vecGroupPts.size() << endl;

    if (vecGroupIdxs.size() == 0) {
        string strErr = "Code 39 failed to ransac bars in a line.";
        cout << strErr << endl;
        return RET_NONE_FOUND;
    }

    //Now cycle over the groups
    vector<vector<int> > vecVecInlierIdx;
    vector<Vec4f> vecLines;
    vector<int> vecFromGroup; //Keeps track of which group the vecvecInlierIdx belongs to
    for (int i = 0; i < vecGroupRects.size(); i++) {
        Ransac(vecGroupRects[i], min_inliers, max_px_dist, vecVecInlierIdx, vecLines, this->image_);
        vecFromGroup.resize(vecVecInlierIdx.size(), i);
    }

    if (vecLines.size() == 0) {
        string strErr = "Code 39 failed to ransac bars in a line.";
        cout << strErr << endl;
        return RET_NONE_FOUND;
    } else {
        //cout << "Code39 ransac succesfull" << endl;
    }

    //for (int i=0; i<vecGroupIdxs.size(); i++){
    //  cout << "Group " << i << " (" << vecGroupIdxs[i].size() << ") : ";
    //  for (int j=0; j<vecGroupIdxs[i].size(); j++){
    //      cout << vecGroupIdxs[i][j] << " ";
    //  }
    //  cout << endl;
    //}


    //Convert back vecVecInlierIdx to original indices
    for (int i=0; i<vecVecInlierIdx.size(); i++){
        //cout << "vecVecInlierIdx[" << i << "] is from group " << vecFromGroup[i] << endl;
        for (int j=0; j<vecVecInlierIdx[i].size(); j++){
            //cout << " " << vecVecInlierIdx[i][j] << " -> " << vecGroupIdxs[vecFromGroup[i]][vecVecInlierIdx[i][j]] << endl;
            vecVecInlierIdx[i][j] = vecGroupIdxs[vecFromGroup[i]][vecVecInlierIdx[i][j]];
        }
    }


    for (int i=0; i < vecLines.size(); i++){
        int numpts = vecVecInlierIdx[i].size();
        cout << "Potential barcode #" << i << " with " << numpts << " points." << endl;

        
        //double angle=atan2(vecLines[i][1],vecLines[i][0])*180/M_PI; //For some reason it clips from [-90,90]
        double angle_rad = atan2(vecLines[i][1],vecLines[i][0]); //For some reason it clips from [-90,90]
        double angle_deg = angle_rad*180.0/M_PI;
        //cout << " angle_deg=" << angle_deg << endl;

        vector<double> bar_heights(numpts);
        vector<double> bar_widths(numpts);
        vector<double> coords_x(numpts);
        //Loop over all found and ransac-verified stripes in this barcode
        vector<cv::RotatedRect> stripesVerified(numpts);
        for (int j=0; j < numpts; j++){
            //cout << vecVecInlierIdx[i][j] << endl;
            //cout << "checking out stripecandidate[" << vecVecInlierIdx[i][j] << "] #" << vecVecInlierIdx[i][j] << endl;
            stripesVerified[j] = stripeCandidates[vecVecInlierIdx[i][j]];
            double dim_smallest = min(stripesVerified[j].size.width, stripesVerified[j].size.height); //For rotation invariance
            double dim_tallest  = max(stripesVerified[j].size.width, stripesVerified[j].size.height); //For rotation invariance
            bar_heights[j] = dim_tallest;
            bar_widths[j]  = dim_smallest;

            //Rotate the points straight
            Point2f ptRot = util::rotatePoint(stripesVerified[j].center, Point(matImageK.cols, matImageK.rows), angle_rad);
            //cout << ptRot << endl;
            coords_x[j]    = ptRot.x;
        }
        
        double height_median = util::calcMedian(bar_heights);
        double width_mean = util::calcMean(bar_widths);
        //cout << "height_median=" << height_median <<" width_mean=" << width_mean << endl;

        //Find the start and end position for reading
        vector<size_t> coords_sorted_index;
        vector<double> coords_x_sorted;
        sort(coords_x, coords_x_sorted, coords_sorted_index);
        //cout << coords_x_sorted[0] << " -> " << coords_x_sorted[coords_x_sorted.size()-1] << endl;

        //Get extrema-stripes
        Point2f pt_stripe_left = stripeCandidates[vecVecInlierIdx[i][coords_sorted_index[0]]].center;
        Point2f pt_stripe_right = stripeCandidates[vecVecInlierIdx[i][coords_sorted_index[coords_sorted_index.size() - 1]]].center;
        //cout << "pt_stripe_left=" << pt_stripe_left << endl;
        //cout << "pt_stripe_right=" << pt_stripe_right << endl;

        Point2f pt_barcode_center = (pt_stripe_left + pt_stripe_right) * 0.5;
        //cout << "pt_barcode_center=" << pt_barcode_center << endl;

        //Calculate width of the barcode
        double barcode_width = util::pointDist(pt_stripe_left, pt_stripe_right);
        //cout << "barcode_width=" << barcode_width << endl;

        //Make the rotated rectangle around the barcode
        cv::RotatedRect rotrect_candidate(pt_barcode_center, Size2f(barcode_width, height_median), angle_deg);

        const double add_width_on_sides_before_decoding = 7.0; // this number will be multiplied by average bar width

        //Add margin (of a few median widths)
        rotrect_candidate.size += Size2f(width_mean * add_width_on_sides_before_decoding, 0);

        const double height_retrainer_for_collapse = 0.25;

        //Extract the barcode itself
        cv::RotatedRect rotrect_candidate_thin = rotrect_candidate;

        //Crop off some margin in thickness because we dont want to collapse the entire barcode.
        if (rotrect_candidate_thin.size.width < rotrect_candidate_thin.size.height) {
            rotrect_candidate_thin.size.width *= height_retrainer_for_collapse;
        } else {
            rotrect_candidate_thin.size.height *= height_retrainer_for_collapse;
        }

        openbarcode::code code_candidate;
        code_candidate.rotrect = rotrect_candidate_thin;

        this->code_candidates_.push_back(code_candidate);
    }

    return RET_SUCCESS;
}