Exemple #1
0
cv::Rect MotionDetector::MotionDetect(cv::Mat* frame)
//Detect motion and create ONE recangle that contains all the detected motion
{
	std::vector<std::vector<cv::Point> > contours;
	std::vector<cv::Vec4i> hierarchy;
	cv::Rect bounding_rect;
	std::vector<cv::Rect> rects;
	cv::Rect largest_rect, rect_temp;

	// Detect motion
	pMOG2->operator()(*frame, fgMaskMOG2, -1);
	//Remove noise
	cv::erode(fgMaskMOG2, fgMaskMOG2, getStructuringElement(cv::MORPH_RECT, cv::Size(6, 6)));
	// Find the contours of motion areas in the image
	findContours(fgMaskMOG2, contours, hierarchy, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);
	// Find the bounding rectangles of the areas of motion
	if (contours.size() > 0)
	{
		for (int i = 0; i < contours.size(); i++)
		{
			bounding_rect = boundingRect(contours[i]);
			rects.push_back(bounding_rect);
		}
		// Determine the overall area with motion.
		largest_rect = rects[0];
		for (int i = 1; i < rects.size(); i++)
		{
			rect_temp.x = min(largest_rect.x,rects[i].x);
			rect_temp.y = min(largest_rect.y,rects[i].y);
			rect_temp.width = max(largest_rect.x + largest_rect.width, rects[i].x + rects[i].width)-rect_temp.x;
			rect_temp.height = max(largest_rect.y + largest_rect.height, rects[i].y + rects[i].height) - rect_temp.y;
			largest_rect = rect_temp;
		}
		rectangle(*frame, rect_temp, cv::Scalar(0, 255, 0), 1, 8, 0);
	}
	else
        {
          largest_rect.x = 0;
          largest_rect.y = 0;
          largest_rect.width = 0;
          largest_rect.height = 0;
        }
		
//	imshow("Motion detect", fgMaskMOG2);
	return expandRect(largest_rect, 0, 0, frame->cols, frame->rows);
}
 // Checks if the provided region is partially covered by the mask
 // If so, it is disqualified
 bool DetectorMask::region_is_masked(cv::Rect region) {
   int MIN_WHITENESS = 248;
   
   // If the mean pixel value over the crop is very white (e.g., > 253 out of 255)
   // then this is in the white area of the mask and we'll use it
   
   // Make sure the region doesn't extend beyond the bounds of our image
   expandRect(region, 0, 0, resized_mask.cols, resized_mask.rows);
   Mat mask_crop = resized_mask(region);
   double mean_value = mean(mask_crop)[0];
   
   if (config->debugDetector)
   {
     cout << "region_is_masked: Mean whiteness: " << mean_value << endl;
   }
   return mean_value < MIN_WHITENESS;
 }
Exemple #3
0
  void OCR::performOCR(PipelineData* pipeline_data)
  {
    const int SPACE_CHAR_CODE = 32;

    timespec startTime;
    getTimeMonotonic(&startTime);

    postProcessor.clear();

    // Don't waste time on OCR processing if it is impossible to get sufficient characters
    int total_char_spaces = 0;
    for (unsigned int i = 0; i < pipeline_data->charRegions.size(); i++)
      total_char_spaces += pipeline_data->charRegions[i].size();
    if (total_char_spaces < config->postProcessMinCharacters)
    {
      pipeline_data->disqualify_reason = "Insufficient character boxes detected.  No OCR performed.";
      pipeline_data->disqualified = true;
      return;
    }

    for (unsigned int i = 0; i < pipeline_data->thresholds.size(); i++)
    {
      // Make it black text on white background
      bitwise_not(pipeline_data->thresholds[i], pipeline_data->thresholds[i]);
      tesseract.SetImage((uchar*) pipeline_data->thresholds[i].data,
                          pipeline_data->thresholds[i].size().width, pipeline_data->thresholds[i].size().height,
                          pipeline_data->thresholds[i].channels(), pipeline_data->thresholds[i].step1());

      int absolute_charpos = 0;
      for (unsigned int line_idx = 0; line_idx < pipeline_data->charRegions.size(); line_idx++)
      {
        for (unsigned int j = 0; j < pipeline_data->charRegions[line_idx].size(); j++)
        {
          Rect expandedRegion = expandRect( pipeline_data->charRegions[line_idx][j], 2, 2, pipeline_data->thresholds[i].cols, pipeline_data->thresholds[i].rows) ;

          tesseract.SetRectangle(expandedRegion.x, expandedRegion.y, expandedRegion.width, expandedRegion.height);
          tesseract.Recognize(NULL);

          tesseract::ResultIterator* ri = tesseract.GetIterator();
          tesseract::PageIteratorLevel level = tesseract::RIL_SYMBOL;
          do
          {
            const char* symbol = ri->GetUTF8Text(level);
            float conf = ri->Confidence(level);

            bool dontcare;
            int fontindex = 0;
            int pointsize = 0;
            const char* fontName = ri->WordFontAttributes(&dontcare, &dontcare, &dontcare, &dontcare, &dontcare, &dontcare, &pointsize, &fontindex);

            // Ignore NULL pointers, spaces, and characters that are way too small to be valid
            if(symbol != 0 && symbol[0] != SPACE_CHAR_CODE && pointsize >= config->ocrMinFontSize)
            {
              postProcessor.addLetter(string(symbol), line_idx, absolute_charpos, conf);

              if (this->config->debugOcr)
                printf("charpos%d line%d: threshold %d:  symbol %s, conf: %f font: %s (index %d) size %dpx\n", absolute_charpos, line_idx, i, symbol, conf, fontName, fontindex, pointsize);

              bool indent = false;
              tesseract::ChoiceIterator ci(*ri);
              do
              {
                const char* choice = ci.GetUTF8Text();
                //1/17/2016 adt adding check to avoid double adding same character if ci is same as symbol. Otherwise first choice will get doubled boost when choiceIterator run.
                if (string(symbol) != string(choice))
                  postProcessor.addLetter(string(choice), line_idx, absolute_charpos, ci.Confidence());

                if (this->config->debugOcr)
                {
                  if (indent) printf("\t\t ");
                  printf("\t- ");
                  printf("%s conf: %f\n", choice, ci.Confidence());
                }

                indent = true;
              }
              while(ci.Next());

            }

            if (this->config->debugOcr)
              printf("---------------------------------------------\n");

            delete[] symbol;
          }
          while((ri->Next(level)));

          delete ri;

          absolute_charpos++;
        }
      }
    }

    if (config->debugTiming)
    {
      timespec endTime;
      getTimeMonotonic(&endTime);
      cout << "OCR Time: " << diffclock(startTime, endTime) << "ms." << endl;
    }
  }
Exemple #4
0
  AlprFullDetails AlprImpl::recognizeFullDetails(cv::Mat img, std::vector<cv::Rect> regionsOfInterest)
  {
    timespec startTime;
    getTimeMonotonic(&startTime);


    AlprFullDetails response;

    response.results.epoch_time = getEpochTimeMs();
    response.results.img_width = img.cols;
    response.results.img_height = img.rows;

    // Fix regions of interest in case they extend beyond the bounds of the image
    for (unsigned int i = 0; i < regionsOfInterest.size(); i++)
      regionsOfInterest[i] = expandRect(regionsOfInterest[i], 0, 0, img.cols, img.rows);

    for (unsigned int i = 0; i < regionsOfInterest.size(); i++)
    {
      response.results.regionsOfInterest.push_back(AlprRegionOfInterest(regionsOfInterest[i].x, regionsOfInterest[i].y,
              regionsOfInterest[i].width, regionsOfInterest[i].height));
    }

    if (!img.data)
    {
      // Invalid image
      if (this->config->debugGeneral)
        std::cerr << "Invalid image" << std::endl;

      return response;
    }

    // Convert image to grayscale if required
    Mat grayImg = img;
    if (img.channels() > 2)
      cvtColor( img, grayImg, CV_BGR2GRAY );
    
    // Prewarp the image and ROIs if configured]
    std::vector<cv::Rect> warpedRegionsOfInterest = regionsOfInterest;
    // Warp the image if prewarp is provided
    grayImg = prewarp->warpImage(grayImg);
    warpedRegionsOfInterest = prewarp->projectRects(regionsOfInterest, grayImg.cols, grayImg.rows, false);
    
    vector<PlateRegion> warpedPlateRegions;
    // Find all the candidate regions
    if (config->skipDetection == false)
    {
      warpedPlateRegions = plateDetector->detect(grayImg, warpedRegionsOfInterest);
    }
    else
    {
      // They have elected to skip plate detection.  Instead, return a list of plate regions
      // based on their regions of interest
      for (unsigned int i = 0; i < warpedRegionsOfInterest.size(); i++)
      {
        PlateRegion pr;
        pr.rect = cv::Rect(warpedRegionsOfInterest[i]);
        warpedPlateRegions.push_back(pr);
      }
    }

    queue<PlateRegion> plateQueue;
    for (unsigned int i = 0; i < warpedPlateRegions.size(); i++)
      plateQueue.push(warpedPlateRegions[i]);

    int platecount = 0;
    while(!plateQueue.empty())
    {
      PlateRegion plateRegion = plateQueue.front();
      plateQueue.pop();

      PipelineData pipeline_data(img, grayImg, plateRegion.rect, config);
      pipeline_data.prewarp = prewarp;

      timespec platestarttime;
      getTimeMonotonic(&platestarttime);

      LicensePlateCandidate lp(&pipeline_data);

      lp.recognize();

      bool plateDetected = false;
      if (!pipeline_data.disqualified)
      {
        AlprPlateResult plateResult;
        plateResult.region = defaultRegion;
        plateResult.regionConfidence = 0;
        plateResult.plate_index = platecount++;

        // If using prewarp, remap the plate corners to the original image
        vector<Point2f> cornerPoints = pipeline_data.plate_corners;
        cornerPoints = prewarp->projectPoints(cornerPoints, true);
        
        for (int pointidx = 0; pointidx < 4; pointidx++)
        {
          plateResult.plate_points[pointidx].x = (int) cornerPoints[pointidx].x;
          plateResult.plate_points[pointidx].y = (int) cornerPoints[pointidx].y;
        }
        
        if (detectRegion)
        {
          std::vector<StateCandidate> state_candidates = stateDetector->detect(pipeline_data.color_deskewed.data,
                                                                               pipeline_data.color_deskewed.elemSize(),
                                                                               pipeline_data.color_deskewed.cols,
                                                                               pipeline_data.color_deskewed.rows);

          if (state_candidates.size() > 0)
          {
            plateResult.region = state_candidates[0].state_code;
            plateResult.regionConfidence = (int) state_candidates[0].confidence;
          }
        }

        if (plateResult.region.length() > 0 && ocr->postProcessor.regionIsValid(plateResult.region) == false)
        {
          std::cerr << "Invalid pattern provided: " << plateResult.region << std::endl;
          std::cerr << "Valid patterns are located in the " << config->country << ".patterns file" << std::endl;
        }

        ocr->performOCR(&pipeline_data);
        ocr->postProcessor.analyze(plateResult.region, topN);

        timespec resultsStartTime;
        getTimeMonotonic(&resultsStartTime);

        const vector<PPResult> ppResults = ocr->postProcessor.getResults();

        int bestPlateIndex = 0;

        cv::Mat charTransformMatrix = getCharacterTransformMatrix(&pipeline_data);
        for (unsigned int pp = 0; pp < ppResults.size(); pp++)
        {

          // Set our "best plate" match to either the first entry, or the first entry with a postprocessor template match
          if (bestPlateIndex == 0 && ppResults[pp].matchesTemplate)
            bestPlateIndex = plateResult.topNPlates.size();
            
          AlprPlate aplate;
          aplate.characters = ppResults[pp].letters;
          aplate.overall_confidence = ppResults[pp].totalscore;
          aplate.matches_template = ppResults[pp].matchesTemplate;
            
          // Grab detailed results for each character
          for (unsigned int c_idx = 0; c_idx < ppResults[pp].letter_details.size(); c_idx++)
          {
            AlprChar character_details;
            character_details.character = ppResults[pp].letter_details[c_idx].letter;
            character_details.confidence = ppResults[pp].letter_details[c_idx].totalscore;
            cv::Rect char_rect = pipeline_data.charRegions[ppResults[pp].letter_details[c_idx].charposition];
            std::vector<AlprCoordinate> charpoints = getCharacterPoints(char_rect, charTransformMatrix );
            for (int cpt = 0; cpt < 4; cpt++)
              character_details.corners[cpt] = charpoints[cpt];
            aplate.character_details.push_back(character_details);
          }
          plateResult.topNPlates.push_back(aplate);
        }

        if (plateResult.topNPlates.size() > bestPlateIndex)
        {
          AlprPlate bestPlate;
          bestPlate.characters = plateResult.topNPlates[bestPlateIndex].characters;
          bestPlate.matches_template = plateResult.topNPlates[bestPlateIndex].matches_template;
          bestPlate.overall_confidence = plateResult.topNPlates[bestPlateIndex].overall_confidence;
          bestPlate.character_details = plateResult.topNPlates[bestPlateIndex].character_details;
          
          plateResult.bestPlate = bestPlate;
        }

        timespec plateEndTime;
        getTimeMonotonic(&plateEndTime);
        plateResult.processing_time_ms = diffclock(platestarttime, plateEndTime);
        if (config->debugTiming)
        {
          cout << "Result Generation Time: " << diffclock(resultsStartTime, plateEndTime) << "ms." << endl;
        }

        if (plateResult.topNPlates.size() > 0)
        {
          plateDetected = true;
          response.results.plates.push_back(plateResult);
        }
      }

      if (!plateDetected)
      {
        // Not a valid plate
        // Check if this plate has any children, if so, send them back up for processing
        for (unsigned int childidx = 0; childidx < plateRegion.children.size(); childidx++)
        {
          plateQueue.push(plateRegion.children[childidx]);
        }
      }

    }

    // Unwarp plate regions if necessary
    prewarp->projectPlateRegions(warpedPlateRegions, grayImg.cols, grayImg.rows, true);
    response.plateRegions = warpedPlateRegions;
    
    timespec endTime;
    getTimeMonotonic(&endTime);
    response.results.total_processing_time_ms = diffclock(startTime, endTime);

    if (config->debugTiming)
    {
      cout << "Total Time to process image: " << diffclock(startTime, endTime) << "ms." << endl;
    }

    if (config->debugGeneral && config->debugShowImages)
    {
      for (unsigned int i = 0; i < regionsOfInterest.size(); i++)
      {
        rectangle(img, regionsOfInterest[i], Scalar(0,255,0), 2);
      }

      for (unsigned int i = 0; i < response.plateRegions.size(); i++)
      {
        rectangle(img, response.plateRegions[i].rect, Scalar(0, 0, 255), 2);
      }

      for (unsigned int i = 0; i < response.results.plates.size(); i++)
      {
        // Draw a box around the license plate 
        for (int z = 0; z < 4; z++)
        {
          AlprCoordinate* coords = response.results.plates[i].plate_points;
          Point p1(coords[z].x, coords[z].y);
          Point p2(coords[(z + 1) % 4].x, coords[(z + 1) % 4].y);
          line(img, p1, p2, Scalar(255,0,255), 2);
        }
        
        // Draw the individual character boxes
        for (int q = 0; q < response.results.plates[i].bestPlate.character_details.size(); q++)
        {
          AlprChar details = response.results.plates[i].bestPlate.character_details[q];
          line(img, Point(details.corners[0].x, details.corners[0].y), Point(details.corners[1].x, details.corners[1].y), Scalar(0,255,0), 1);
          line(img, Point(details.corners[1].x, details.corners[1].y), Point(details.corners[2].x, details.corners[2].y), Scalar(0,255,0), 1);
          line(img, Point(details.corners[2].x, details.corners[2].y), Point(details.corners[3].x, details.corners[3].y), Scalar(0,255,0), 1);
          line(img, Point(details.corners[3].x, details.corners[3].y), Point(details.corners[0].x, details.corners[0].y), Scalar(0,255,0), 1);
        }
      }


      displayImage(config, "Main Image", img);

      // Sleep 1ms
      sleep_ms(1);

    }


    if (config->debugPauseOnFrame)
    {
      // Pause indefinitely until they press a key
      while ((char) cv::waitKey(50) == -1)
      {}
    }

    return response;
  }
Exemple #5
0
  vector<PlateRegion> DetectorMorph::detect(Mat frame, std::vector<cv::Rect> regionsOfInterest) {

    Mat frame_gray,frame_gray_cp;

    if (frame.channels() > 2)
    {
      cvtColor( frame, frame_gray, CV_BGR2GRAY );
    }
    else
    {
      frame.copyTo(frame_gray);
    }

    frame_gray.copyTo(frame_gray_cp);
    blur(frame_gray, frame_gray, Size(5, 5));

    vector<PlateRegion> detectedRegions;
    for (int i = 0; i < regionsOfInterest.size(); i++) {
      Mat img_open, img_result;
      Mat element = getStructuringElement(MORPH_RECT, Size(30, 4));
      morphologyEx(frame_gray, img_open, CV_MOP_OPEN, element, cv::Point(-1, -1));

      img_result = frame_gray - img_open;

      if (config->debugDetector && config->debugShowImages) {
        imshow("Opening", img_result);
      }

      //threshold image using otsu thresholding
      Mat img_threshold, img_open2;
      threshold(img_result, img_threshold, 0, 255, CV_THRESH_OTSU + CV_THRESH_BINARY);

      if (config->debugDetector && config->debugShowImages) {
        imshow("Threshold Detector", img_threshold);
      }

      Mat diamond(5, 5, CV_8U, cv::Scalar(1));

	diamond.at<uchar>(0, 0) = 0;
	diamond.at<uchar>(0, 1) = 0;
	diamond.at<uchar>(1, 0) = 0;
	diamond.at<uchar>(4, 4) = 0;
	diamond.at<uchar>(3, 4) = 0;
	diamond.at<uchar>(4, 3) = 0;
	diamond.at<uchar>(4, 0) = 0;
	diamond.at<uchar>(4, 1) = 0;
	diamond.at<uchar>(3, 0) = 0;
	diamond.at<uchar>(0, 4) = 0;
	diamond.at<uchar>(0, 3) = 0;
	diamond.at<uchar>(1, 4) = 0;
			
      morphologyEx(img_threshold, img_open2, CV_MOP_OPEN, diamond, cv::Point(-1, -1));
      Mat rectElement = getStructuringElement(cv::MORPH_RECT, Size(13, 4));
      morphologyEx(img_open2, img_threshold, CV_MOP_CLOSE, rectElement, cv::Point(-1, -1));

      if (config->debugDetector && config->debugShowImages) {
        imshow("Close", img_threshold);
        waitKey(0);
      }

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

      //Start to iterate to each contour founded
      vector<vector<Point> >::iterator itc = contours.begin();
      vector<RotatedRect> rects;

      //Remove patch that are no inside limits of aspect ratio and area.    
      while (itc != contours.end()) {
        //Create bounding rect of object
        RotatedRect mr = minAreaRect(Mat(*itc));
        
        if (mr.angle < -45.) {
					mr.angle += 90.0;
					swap(mr.size.width, mr.size.height);
				}  
        
        if (!CheckSizes(mr))
          itc = contours.erase(itc);
        else {
          ++itc;
					rects.push_back(mr);
        }
      }

     //Now prunning based on checking all candidate plates for a min/max number of blobsc
Mat img_crop, img_crop_b, img_crop_th, img_crop_th_inv;
vector< vector< Point> > plateBlobs;
vector< vector< Point> > plateBlobsInv;
double thresholds[] = { 10, 40, 80, 120, 160, 200, 240 };
const int num_thresholds = 7;
int numValidChars = 0;
Mat rotated;
for (int i = 0; i < rects.size(); i++) {
	numValidChars = 0;
	RotatedRect PlateRect = rects[i];
	Size rect_size = PlateRect.size;

	// get the rotation matrix
	Mat M = getRotationMatrix2D(PlateRect.center, PlateRect.angle, 1.0);
	// perform the affine transformation
	warpAffine(frame_gray_cp, rotated, M, frame_gray_cp.size(), INTER_CUBIC);
	//Crop area around candidate plate
	getRectSubPix(rotated, rect_size, PlateRect.center, img_crop);

	 if (config->debugDetector && config->debugShowImages) {
		imshow("Tilt Correction", img_crop);
		waitKey(0);
	}

	for (int z = 0; z < num_thresholds; z++) {

		cv::threshold(img_crop, img_crop_th, thresholds[z], 255, cv::THRESH_BINARY);
		cv::threshold(img_crop, img_crop_th_inv, thresholds[z], 255, cv::THRESH_BINARY_INV);

		findContours(img_crop_th,
			plateBlobs, // a vector of contours
			CV_RETR_LIST, // retrieve the contour list
			CV_CHAIN_APPROX_NONE); // all pixels of each contours

		findContours(img_crop_th_inv,
			plateBlobsInv, // a vector of contours
			CV_RETR_LIST, // retrieve the contour list
			CV_CHAIN_APPROX_NONE); // all pixels of each contours

		int numBlobs = plateBlobs.size();
		int numBlobsInv = plateBlobsInv.size();
	
		float idealAspect = config->avgCharWidthMM / config->avgCharHeightMM;
		for (int j = 0; j < numBlobs; j++) {
			cv::Rect r0 = cv::boundingRect(cv::Mat(plateBlobs[j]));
			
			if (ValidateCharAspect(r0, idealAspect))
				numValidChars++;
		}

		for (int j = 0; j < numBlobsInv; j++) {
			cv::Rect r0 = cv::boundingRect(cv::Mat(plateBlobsInv[j]));
			if (ValidateCharAspect(r0, idealAspect))
				numValidChars++;
		}

	}
	//If too much or too lcittle might not be a true plate
	//if (numBlobs < 3 || numBlobs > 50) continue;
	if (numValidChars < 4  || numValidChars > 50) continue;

        PlateRegion PlateReg;

        // Ensure that the rectangle isn't < 0 or > maxWidth/Height
        Rect bounding_rect = PlateRect.boundingRect();
        PlateReg.rect = expandRect(bounding_rect, 0, 0, frame.cols, frame.rows);
        
        
        detectedRegions.push_back(PlateReg);

      }

    }
    
    return detectedRegions;
  }
  std::vector<OcrChar> TesseractOcr::recognize_line(int line_idx, PipelineData* pipeline_data) {

    const int SPACE_CHAR_CODE = 32;
    
    std::vector<OcrChar> recognized_chars;
    
    for (unsigned int i = 0; i < pipeline_data->thresholds.size(); i++)
    {
      // Make it black text on white background
      bitwise_not(pipeline_data->thresholds[i], pipeline_data->thresholds[i]);
      tesseract.SetImage((uchar*) pipeline_data->thresholds[i].data, 
                          pipeline_data->thresholds[i].size().width, pipeline_data->thresholds[i].size().height, 
                          pipeline_data->thresholds[i].channels(), pipeline_data->thresholds[i].step1());

 
      int absolute_charpos = 0;

      for (unsigned int j = 0; j < pipeline_data->charRegions[line_idx].size(); j++)
      {
        Rect expandedRegion = expandRect( pipeline_data->charRegions[line_idx][j], 2, 2, pipeline_data->thresholds[i].cols, pipeline_data->thresholds[i].rows) ;

        tesseract.SetRectangle(expandedRegion.x, expandedRegion.y, expandedRegion.width, expandedRegion.height);
        tesseract.Recognize(NULL);

        tesseract::ResultIterator* ri = tesseract.GetIterator();
        tesseract::PageIteratorLevel level = tesseract::RIL_SYMBOL;
        do
        {
          const char* symbol = ri->GetUTF8Text(level);
          float conf = ri->Confidence(level);

          bool dontcare;
          int fontindex = 0;
          int pointsize = 0;
          const char* fontName = ri->WordFontAttributes(&dontcare, &dontcare, &dontcare, &dontcare, &dontcare, &dontcare, &pointsize, &fontindex);

          // Ignore NULL pointers, spaces, and characters that are way too small to be valid
          if(symbol != 0 && symbol[0] != SPACE_CHAR_CODE && pointsize >= config->ocrMinFontSize)
          {
            OcrChar c;
            c.char_index = absolute_charpos;
            c.confidence = conf;
            c.letter = string(symbol);
            recognized_chars.push_back(c);

            if (this->config->debugOcr)
              printf("charpos%d line%d: threshold %d:  symbol %s, conf: %f font: %s (index %d) size %dpx", absolute_charpos, line_idx, i, symbol, conf, fontName, fontindex, pointsize);

            bool indent = false;
            tesseract::ChoiceIterator ci(*ri);
            do
            {
              const char* choice = ci.GetUTF8Text();
              
              OcrChar c2;
              c2.char_index = absolute_charpos;
              c2.confidence = ci.Confidence();
              c2.letter = string(choice);
              
              //1/17/2016 adt adding check to avoid double adding same character if ci is same as symbol. Otherwise first choice from ResultsIterator will get added twice when choiceIterator run.
              if (string(symbol) != string(choice))
                recognized_chars.push_back(c2);
              else
              {
                // Explictly double-adding the first character.  This leads to higher accuracy right now, likely because other sections of code
                // have expected it and compensated. 
                // TODO: Figure out how to remove this double-counting of the first letter without impacting accuracy
                recognized_chars.push_back(c2);
              }
              if (this->config->debugOcr)
              {
                if (indent) printf("\t\t ");
                printf("\t- ");
                printf("%s conf: %f\n", choice, ci.Confidence());
              }

              indent = true;
            }
            while(ci.Next());

          }

          if (this->config->debugOcr)
            printf("---------------------------------------------\n");

          delete[] symbol;
        }
        while((ri->Next(level)));

        delete ri;

        absolute_charpos++;
      }
      
    }
    
    return recognized_chars;
  }
Exemple #7
0
  vector<PlateRegion> Detector::detect(Mat frame, std::vector<cv::Rect> regionsOfInterest)
  {

    Mat frame_gray;
    
    if (frame.channels() > 2)
    {
      cvtColor( frame, frame_gray, CV_BGR2GRAY );
    }
    else
    {
      frame.copyTo(frame_gray);
    }

    // Apply the detection mask if it has been specified by the user
    if (detector_mask.mask_loaded)
      frame_gray = detector_mask.apply_mask(frame_gray);

    // Setup debug mask image
    Mat mask_debug_img;
    if (detector_mask.mask_loaded && config->debugDetector)
    {
      frame_gray.copyTo(mask_debug_img);
      cvtColor(frame_gray, mask_debug_img, CV_GRAY2BGR);
    }
    
    vector<PlateRegion> detectedRegions;   
    for (int i = 0; i < regionsOfInterest.size(); i++)
    {
      Rect roi = regionsOfInterest[i];
      
      // Adjust the ROI to be inside the detection mask (if it exists)
      if (detector_mask.mask_loaded)
        roi = detector_mask.getRoiInsideMask(roi);

      // Draw ROIs on debug mask image
      if (detector_mask.mask_loaded && config->debugDetector)
        rectangle(mask_debug_img, roi, Scalar(0,255,255), 3);
      
      // Sanity check.  If roi width or height is less than minimum possible plate size,
      // then skip it
      if ((roi.width < config->minPlateSizeWidthPx) || 
          (roi.height < config->minPlateSizeHeightPx))
        continue;
      
      Mat cropped = frame_gray(roi);

      int w = cropped.size().width;
      int h = cropped.size().height;
      int offset_x = roi.x;
      int offset_y = roi.y;
      float scale_factor = computeScaleFactor(w, h);

      if (scale_factor != 1.0)
        resize(cropped, cropped, Size(w * scale_factor, h * scale_factor));

    
      float maxWidth = ((float) w) * (config->maxPlateWidthPercent / 100.0f) * scale_factor;
      float maxHeight = ((float) h) * (config->maxPlateHeightPercent / 100.0f) * scale_factor;
      Size minPlateSize(config->minPlateSizeWidthPx, config->minPlateSizeHeightPx);
      Size maxPlateSize(maxWidth, maxHeight);
    
      vector<Rect> allRegions = find_plates(cropped, minPlateSize, maxPlateSize);
      
      // Aggregate the Rect regions into a hierarchical representation
      for( unsigned int i = 0; i < allRegions.size(); i++ )
      {
        allRegions[i].x = (allRegions[i].x / scale_factor);
        allRegions[i].y = (allRegions[i].y / scale_factor);
        allRegions[i].width = allRegions[i].width / scale_factor;
        allRegions[i].height = allRegions[i].height / scale_factor;

        // Ensure that the rectangle isn't < 0 or > maxWidth/Height
        allRegions[i] = expandRect(allRegions[i], 0, 0, w, h);

        allRegions[i].x = allRegions[i].x + offset_x;
        allRegions[i].y = allRegions[i].y + offset_y;
      }
      
      // Check the rectangles and make sure that they're definitely not masked
      vector<Rect> regions_not_masked;
      for (unsigned int i = 0; i < allRegions.size(); i++)
      {
        if (detector_mask.mask_loaded)
        {
          if (!detector_mask.region_is_masked(allRegions[i]))
            regions_not_masked.push_back(allRegions[i]);
        }
        else
          regions_not_masked.push_back(allRegions[i]);
      }
      
      vector<PlateRegion> orderedRegions = aggregateRegions(regions_not_masked);

      

      for (unsigned int j = 0; j < orderedRegions.size(); j++)
        detectedRegions.push_back(orderedRegions[j]);
    }

    // Show debug mask image
    if (detector_mask.mask_loaded && config->debugDetector && config->debugShowImages)
    {
      imshow("Detection Mask", mask_debug_img);
    }
    
    return detectedRegions;
  }
Exemple #8
0
void MainWindow::documentExport(void)
{
    Canvas *currCanvas = canvas();
    QString currFilename = currCanvas->filename();
    currFilename.chop(4);
    if (currFilename.isEmpty())
    {
        // Determine the working directory.
        QSettings settings;
        QString workingDir(QDir::homePath());
        QVariant workingDirSetting =
                settings.value("workingDirectory");
        if (workingDirSetting.isValid())
        {
            workingDir = workingDirSetting.toString();
        }

        currFilename = workingDir + "/untitled";
    }
    QString filename = QFileDialog::getSaveFileName(this, tr("Export Diagram"),
            currFilename, tr("SVG (*.svg);;PDF (*.pdf);;Postscript (*.ps)"));
    if (filename.isEmpty())
    {
        return;
    }

    QRectF pageRect = currCanvas->pageRect();
    if (pageRect.size().isEmpty())
    {
        // There is no page set, so use a page equal to diagram bounds
        double padding = 10;
        pageRect = expandRect(diagramBoundingRect(currCanvas->items()), padding);
    }

    QFileInfo file(filename);
    if (file.suffix() == "svg")
    {
        QSvgGenerator generator;
        generator.setFileName(filename);

        QRectF targetRect(QPointF(0, 0), currCanvas->sceneRect().size());

        QPointF topLeft = pageRect.topLeft() -
                currCanvas->sceneRect().topLeft();
        QRectF viewbox(topLeft, pageRect.size());

        generator.setSize(viewbox.size().toSize());
        generator.setViewBox(viewbox);

        generator.setTitle(QFileInfo(filename).fileName());
        generator.setDescription(tr("This file was exported from Dunnart.  "
                                    "http://www.dunnart.org/"));

        QPainter painter;
        if (painter.begin(&generator))
        {
            painter.setRenderHint(QPainter::Antialiasing);
            currCanvas->setRenderingForPrinting(true);
            currCanvas->render(&painter, targetRect,
                    currCanvas->sceneRect(),
                    Qt::IgnoreAspectRatio);
            currCanvas->setRenderingForPrinting(false);

            painter.end();
        }
        else
        {
            qDebug("Export SVG painter failed to begin.");
        }
    }
    else
    {
        // Use QPrinter for PDF and PS.
        QPrinter printer;
        printer.setOutputFileName(filename);
        printer.setPaperSize(pageRect.size(),
                QPrinter::Millimeter);
        QPainter painter;
        if (painter.begin(&printer))
        {
            painter.setRenderHint(QPainter::Antialiasing);
            currCanvas->setRenderingForPrinting(true);
            currCanvas->render(&painter, QRectF(),
                    expandRect(pageRect, -3),
                    Qt::IgnoreAspectRatio);
            currCanvas->setRenderingForPrinting(false);
        }
        else
        {
            qDebug("Export PDF/PS painter failed to begin.");
        }
    }
}