コード例 #1
0
ファイル: CutMask.cpp プロジェクト: 1062054548/extend-mesh
void CutMask::fillMask(int x, int y, MatrixXf & m)
{
	if(x >= 0 && x < BlockSize && y >= 0 && y < BlockSize && m(y,x) == 1)
	{
		m(y,x) = 0; 

		fillMask(x + 1, y,     m);       
		fillMask(x - 1, y,     m);       
		fillMask(x,     y + 1, m);
		fillMask(x,     y - 1, m);              
	}   
}
コード例 #2
0
ファイル: CutMask.cpp プロジェクト: 1062054548/extend-mesh
void CutMask::fillMask(MatrixXf & m, BlockType type)
{
	switch(type)
	{
	case VERTICAL:
		for(int i = 0; i < BlockSize; i++)
			fillMask(0, i, m);
		break;

	case V_BOTHSIDES:
		for(int i = 0; i < BlockSize; i++)
		{
			fillMask(0, i, m);
			fillMask(BlockSize - 1, i, m);
		}
		break;

	case L_SHAPED:
	case N_SHAPED:
		for(int i = 0; i < BlockSize; i++)
		{
			fillMask(i, 0, m);
			fillMask(0, i, m);

			if(type == L_SHAPED && i < BandSize)
				fillMask(BlockSize - 1, i, m);
			else if(type == N_SHAPED)
				fillMask(BlockSize - 1, i, m);
		}
		break;

        case NONE_BLOCK:
        case HORIZONTAL:
                break;
	}
}
コード例 #3
0
void CharacterSegmenter::filterEdgeBoxes(vector<Mat> thresholds, const vector<Rect> charRegions, float avgCharWidth, float avgCharHeight)
{
  const float MIN_ANGLE_FOR_ROTATION = 0.4;
  int MIN_CONNECTED_EDGE_PIXELS = (avgCharHeight * 1.5);
  
  // Sometimes the rectangle won't be very tall, making it impossible to detect an edge
  // Adjust for this here.
  int alternate = thresholds[0].rows * 0.92;
  if (alternate < MIN_CONNECTED_EDGE_PIXELS && alternate > avgCharHeight)
    MIN_CONNECTED_EDGE_PIXELS = alternate;
  
  // 
  // Pay special attention to the edge boxes.  If it's a skinny box, and the vertical height extends above our bounds... remove it.
  //while (charBoxes.size() > 0 && charBoxes[charBoxes.size() - 1].width < MIN_SEGMENT_WIDTH_EDGES)
  //  charBoxes.erase(charBoxes.begin() + charBoxes.size() - 1);
  // Now filter the "edge" boxes.  We don't want to include skinny boxes on the edges, since these could be plate boundaries
  //while (charBoxes.size() > 0 && charBoxes[0].width < MIN_SEGMENT_WIDTH_EDGES)
  //  charBoxes.erase(charBoxes.begin() + 0);  
  
    
  // TECHNIQUE #1
  // Check for long vertical lines.  Once the line is too long, mask the whole region
  
  if (charRegions.size() <= 1)
    return;
  
  // Check both sides to see where the edges are
  // The first starts at the right edge of the leftmost char region and works its way left
  // The second starts at the left edge of the rightmost char region and works its way right.
  // We start by rotating the threshold image to the correct angle
  // then check each column 1 by 1.
    
  vector<int> leftEdges;
  vector<int> rightEdges;
  
  for (int i = 0; i < thresholds.size(); i++)
  {
    Mat rotated;
    
    if (top.angle > MIN_ANGLE_FOR_ROTATION)
    {
      // Rotate image:
      rotated = Mat(thresholds[i].size(), thresholds[i].type());
      Mat rot_mat( 2, 3, CV_32FC1 );
      Point center = Point( thresholds[i].cols/2, thresholds[i].rows/2 );
      
      rot_mat = getRotationMatrix2D( center, top.angle, 1.0 );
      warpAffine( thresholds[i], rotated, rot_mat, thresholds[i].size() );
    }
    else
    {
	rotated = thresholds[i];
    }

    int leftEdgeX = 0;
    int rightEdgeX = rotated.cols;
    // Do the left side
    int col = charRegions[0].x + charRegions[0].width;
    while (col >= 0)
    {
      
      int rowLength = getLongestBlobLengthBetweenLines(rotated, col);
      
      if (rowLength > MIN_CONNECTED_EDGE_PIXELS)
      {
	leftEdgeX = col;
	break;
      }
      
      col--;
    }
    
    col = charRegions[charRegions.size() - 1].x;
    while (col < rotated.cols)
    {
      
      int rowLength = getLongestBlobLengthBetweenLines(rotated, col);
      
      if (rowLength > MIN_CONNECTED_EDGE_PIXELS)
      {
	rightEdgeX = col;
	break;
      }
      col++;
    }
    
    
    if (leftEdgeX != 0)
      leftEdges.push_back(leftEdgeX);
    if (rightEdgeX != thresholds[i].cols)
      rightEdges.push_back(rightEdgeX);
    
  }
  
  int leftEdge = 0;
  int rightEdge = thresholds[0].cols;
  
  // Assign the edge values to the SECOND closest value
  if (leftEdges.size() > 1)
  {
    sort (leftEdges.begin(), leftEdges.begin()+leftEdges.size());
    leftEdge = leftEdges[leftEdges.size() - 2] + 1;
  }
  if (rightEdges.size() > 1)
  {
    sort (rightEdges.begin(), rightEdges.begin()+rightEdges.size());
    rightEdge = rightEdges[1] - 1;
  }
  
  if (leftEdge != 0 || rightEdge != thresholds[0].cols)
  {
    Mat mask = Mat::zeros(thresholds[0].size(), CV_8U);
    rectangle(mask, Point(leftEdge, 0), Point(rightEdge, thresholds[0].rows), Scalar(255,255,255), -1);
    
    if (top.angle > MIN_ANGLE_FOR_ROTATION)
    {
      // Rotate mask:
      Mat rot_mat( 2, 3, CV_32FC1 );
      Point center = Point( mask.cols/2, mask.rows/2 );
      
      rot_mat = getRotationMatrix2D( center, top.angle * -1, 1.0 );
      warpAffine( mask, mask, rot_mat, mask.size() );
    }

    
    // If our edge mask covers more than x% of the char region, mask the whole thing...
    const float MAX_COVERAGE_PERCENT = 0.6;
    int leftCoveragePx = leftEdge - charRegions[0].x;
    float leftCoveragePercent = ((float) leftCoveragePx) / ((float) charRegions[0].width);
    float rightCoveragePx = (charRegions[charRegions.size() -1].x + charRegions[charRegions.size() -1].width) - rightEdge;
    float rightCoveragePercent = ((float) rightCoveragePx) / ((float) charRegions[charRegions.size() -1].width);
    if ((leftCoveragePercent > MAX_COVERAGE_PERCENT) ||
      (charRegions[0].width - leftCoveragePx < config->segmentationMinBoxWidthPx))
    {
      rectangle(mask, charRegions[0], Scalar(0,0,0), -1);	// Mask the whole region
      if (this->config->debugCharSegmenter)
	cout << "Edge Filter: Entire left region is erased" << endl;
    }
    if ((rightCoveragePercent > MAX_COVERAGE_PERCENT) ||
      (charRegions[charRegions.size() -1].width - rightCoveragePx < config->segmentationMinBoxWidthPx))
    {
      rectangle(mask, charRegions[charRegions.size() -1], Scalar(0,0,0), -1);
      if (this->config->debugCharSegmenter)
	cout << "Edge Filter: Entire right region is erased" << endl;
    }
    
    for (int i = 0; i < thresholds.size(); i++)
    {
      bitwise_and(thresholds[i], mask, thresholds[i]);
    }
    
    
    if (this->config->debugCharSegmenter)
    {
      cout << "Edge Filter: left=" << leftEdge << " right=" << rightEdge << endl;  
      Mat bordered = addLabel(mask, "Edge Filter #1");
      imgDbgGeneral.push_back(bordered);
      
      Mat invertedMask(mask.size(), mask.type());
      bitwise_not(mask, invertedMask);
      for (int z = 0; z < imgDbgCleanStages.size(); z++)
	fillMask(imgDbgCleanStages[z], invertedMask, Scalar(0,0,255));
    }
  }
  
  // TECHNIQUE #2
  // Check for tall skinny blobs on the edge boxes.  If they're too long and skinny, maks the whole char region
  /*
   * 
  float MIN_EDGE_CONTOUR_HEIGHT = avgCharHeight * 0.7;
  float MIN_EDGE_CONTOUR_AREA_PCT = avgCharHeight * 0.1;
   
  for (int i = 0; i < thresholds.size(); i++)
  {
      // Just check the first and last char box.  If the contour extends too far above/below the line.  Drop it.
      
      for (int boxidx = 0; boxidx < charRegions.size(); boxidx++)
      {
	if (boxidx != 0 || boxidx != charRegions.size() -1)
	{
	  // This is a middle box.  we never want to filter these here.
	  continue;
	}
	
	vector<vector<Point> > contours;
	Mat mask = Mat::zeros(thresholds[i].size(),CV_8U);
	rectangle(mask, charRegions[boxidx], Scalar(255,255,255), CV_FILLED);
	
	bitwise_and(thresholds[i], mask, mask);
	findContours(mask, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
	//int tallContourIndex = isSkinnyLineInsideBox(thresholds[i], charRegions[boxidx], allContours[i], hierarchy[i], avgCharWidth, avgCharHeight);
	float tallestContourHeight = 0;
	float fattestContourWidth = 0;
	float biggestContourArea = 0;
	for (int c = 0; c < contours.size(); c++)
	{
	    Rect r = boundingRect(contours[c]);
	    if (r.height > tallestContourHeight)
	      tallestContourHeight = r.height;
	    if (r.width > fattestContourWidth)
	      fattestContourWidth = r.width;
	    float a = r.area();
	    if (a > biggestContourArea)
	      biggestContourArea = a;
	}
	
	float minArea = charRegions[boxidx].area() * MIN_EDGE_CONTOUR_AREA_PCT;
	if ((fattestContourWidth < MIN_BOX_WIDTH_PX) || 
	  (tallestContourHeight < MIN_EDGE_CONTOUR_HEIGHT) ||
	  (biggestContourArea < minArea)
	)
	{
	  // Find a good place to MASK this contour.
	  // for now, just mask the whole thing
	  if (this->debug)
	  {
	    
	    rectangle(imgDbgCleanStages[i], charRegions[boxidx], COLOR_DEBUG_EDGE, 2);
	    cout << "Edge Filter: threshold " << i << " box " << boxidx << endl;
	  }
	  rectangle(thresholds[i], charRegions[boxidx], Scalar(0,0,0), -1);
	}
	else
	{
	  filteredCharRegions.push_back(charRegions[boxidx]);  
	}
      }
  }
  */
  
}
コード例 #4
0
ファイル: CutMask.cpp プロジェクト: 1062054548/extend-mesh
CutMask::CutMask(MatrixXf & overlap, BlockType type)
{
	for(int y = 0; y < BlockSize; y++)
	{
		for(int x = 0; x < BlockSize; x++)
		{
			points[nodes.size()] = Point(x,y);
			nodes[Point(x,y)] = nodes.size();
		}
	}

	protectCore(overlap, type);

	costMatrix = overlap;

	for(int y = 0; y < BlockSize; y++)
	{
		for(int x = 0; x < BlockSize; x++)
		{
			Point p1 = Point(x    , y    );
			Point p2 = Point(x + 1, y    );
			Point p3 = Point(x    , y + 1);

			if(point(p2))	g.AddEdge(nodes[p1], nodes[p2], cost(p1,p2));
			if(point(p3))	g.AddEdge(nodes[p1], nodes[p3], cost(p1,p3));
		}
	}

	// Add start and end nodes
	int start = nodes.size();
	int end = start + 1;

	BlockType originalType = type;
	
	if(originalType == V_BOTHSIDES)
	{
		// convert it to N_SHAPED
		for(int i = BandSize - 1; i < BlockSize - BandSize; i++)
		{
			g.SetEdgeWeight(nodes[Point(i,0)], nodes[Point(i+1,0)], 0);
			g.SetEdgeWeight(nodes[Point(i+1,0)], nodes[Point(i,0)], 0);
		}

		type = N_SHAPED;
	}

	// connect start and end to graph, first is start node case
	switch(type)
	{
	case VERTICAL:
		for(int i = 0; i < BandSize; i++)
			g.AddEdge(start, nodes[Point(i, 0)], 0);
		break;

	case L_SHAPED:
		//for(int i = 0; i < BandSize; i++)
		//	g.AddEdge(start, nodes[Point(BlockSize - 1, i)], 0);
		g.AddEdge(start, nodes[Point(BlockSize - 1, BandSize - 1)], 0);
		break;

	case N_SHAPED:
		for(int i = 0; i < BandSize; i++)
			g.AddEdge(start, nodes[Point((BlockSize - 1) - i, BlockSize - 1)], 0);
		break;

        case NONE_BLOCK:
        case V_BOTHSIDES:
        case HORIZONTAL:
                break;
	}

	// end node connections
	for(int i = 0; i < BandSize; i++)
		g.AddEdge(end, nodes[Point(i, BlockSize - 1)], 0);

	// Find the shortest path
	std::list<int> path = g.DijkstraShortestPath(start, end);

	// Remove start and end points
	path.pop_front();
	path.pop_back();

	// turn into boolean mask
	mask = MatrixXf::Ones(BlockSize, BlockSize);

	for(std::list<int>::iterator i = path.begin(); i != path.end(); i++)
	{
		Point p = points[*i];
		mask(p.y, p.x) = 0;
	}

	fillMask(mask, type);

	// Special case: fix V_BOTHSIDES mask
	if(originalType == V_BOTHSIDES)
	{
		for(int i = BandSize; i < BlockSize - BandSize; i++)
		{
			mask(0, i) = 1.0f;
		}
	}
}