<commit_before>/*
 * Copyright (c) 2013 New Designs Unlimited, LLC
 * Opensource Automated License Plate Recognition [http://www.openalpr.com]
 * 
 * This file is part of OpenAlpr.
 * 
 * OpenAlpr is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License 
 * version 3 as published by the Free Software Foundation 
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "alpr_impl.h"

void plateAnalysisThread(void* arg);

AlprImpl::AlprImpl(const std::string country, const std::string configFile, const std::string runtimeDir)
{
  config = new Config(country, configFile, runtimeDir);
  
  // Config file or runtime dir not found.  Don't process any further.
  if (config->loaded == false)
  {
    plateDetector = ALPR_NULL_PTR;
    stateIdentifier = ALPR_NULL_PTR;
    ocr = ALPR_NULL_PTR;
    return;
  }
  
  plateDetector = new RegionDetector(config);
  stateIdentifier = new StateIdentifier(config);
  ocr = new OCR(config);
  setNumThreads(0);
  
  this->detectRegion = DEFAULT_DETECT_REGION;
  this->topN = DEFAULT_TOPN;
  this->defaultRegion = "";
  
}
AlprImpl::~AlprImpl()
{
  delete config;
  
  if (plateDetector != ALPR_NULL_PTR)
    delete plateDetector;
  
  if (stateIdentifier != ALPR_NULL_PTR)
    delete stateIdentifier;
  
  if (ocr != ALPR_NULL_PTR)
    delete ocr;
}

bool AlprImpl::isLoaded()
{
  return config->loaded;
}


std::vector<AlprResult> AlprImpl::recognize(cv::Mat img)
{
  timespec startTime;
  getTime(&startTime);
  

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

  // Find all the candidate regions
  vector<PlateRegion> plateRegions = plateDetector->detect(img);

  // Get the number of threads specified and make sure the value is sane (cannot be greater than CPU cores or less than 1)
  int numThreads = config->multithreading_cores;
  if (numThreads > tthread::thread::hardware_concurrency())
    numThreads = tthread::thread::hardware_concurrency();
  if (numThreads <= 0)
    numThreads = 1;


  PlateDispatcher dispatcher(plateRegions, &img, 
			     config, stateIdentifier, ocr, 
			     topN, detectRegion, defaultRegion);
    
  // Spawn n threads to process all of the candidate regions and recognize
  list<tthread::thread*> threads;
  for (int i = 0; i < numThreads; i++)
  {
    tthread::thread * t = new tthread::thread(plateAnalysisThread, (void *) &dispatcher);
    threads.push_back(t);
  }
  
  // Wait for all threads to finish
  for(list<tthread::thread *>::iterator i = threads.begin(); i != threads.end(); ++ i)
  {
    tthread::thread* t = *i;
    t->join();
    delete t;
  }

  if (config->debugTiming)
  {
    timespec endTime;
    getTime(&endTime);
    cout << "Total Time to process image: " << diffclock(startTime, endTime) << "ms." << endl;
  }
  
  if (config->debugGeneral && config->debugShowImages)
  {
    for (int i = 0; i < plateRegions.size(); i++)
    {
      rectangle(img, plateRegions[i].rect, Scalar(0, 0, 255), 2);
    }
    
    for (int i = 0; i < dispatcher.getRecognitionResults().size(); i++)
    {
      for (int z = 0; z < 4; z++)
      {
	AlprCoordinate* coords = dispatcher.getRecognitionResults()[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);
      }
    }

    
    displayImage(config, "Main Image", img);
    cv::waitKey(1);
    
  }
  
  if (config->debugPauseOnFrame)
  {
    // Pause indefinitely until they press a key
    while ((char) cv::waitKey(50) == -1)
    {}
  }
  
  return dispatcher.getRecognitionResults();
}

void plateAnalysisThread(void* arg)
{
  PlateDispatcher* dispatcher = (PlateDispatcher*) arg;
  
  if (dispatcher->config->debugGeneral)
    cout << "Thread: " << tthread::this_thread::get_id() << " Initialized" << endl;
  <commit_msg>Process image first before stopping to display image (debug mode)<commit_after>/*
 * Copyright (c) 2013 New Designs Unlimited, LLC
 * Opensource Automated License Plate Recognition [http://www.openalpr.com]
 * 
 * This file is part of OpenAlpr.
 * 
 * OpenAlpr is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License 
 * version 3 as published by the Free Software Foundation 
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "alpr_impl.h"

void plateAnalysisThread(void* arg);

AlprImpl::AlprImpl(const std::string country, const std::string configFile, const std::string runtimeDir)
{
  config = new Config(country, configFile, runtimeDir);
  
  // Config file or runtime dir not found.  Don't process any further.
  if (config->loaded == false)
  {
    plateDetector = ALPR_NULL_PTR;
    stateIdentifier = ALPR_NULL_PTR;
    ocr = ALPR_NULL_PTR;
    return;
  }
  
  plateDetector = new RegionDetector(config);
  stateIdentifier = new StateIdentifier(config);
  ocr = new OCR(config);
  setNumThreads(0);
  
  this->detectRegion = DEFAULT_DETECT_REGION;
  this->topN = DEFAULT_TOPN;
  this->defaultRegion = "";
  
}
AlprImpl::~AlprImpl()
{
  delete config;
  
  if (plateDetector != ALPR_NULL_PTR)
    delete plateDetector;
  
  if (stateIdentifier != ALPR_NULL_PTR)
    delete stateIdentifier;
  
  if (ocr != ALPR_NULL_PTR)
    delete ocr;
}

bool AlprImpl::isLoaded()
{
  return config->loaded;
}


std::vector<AlprResult> AlprImpl::recognize(cv::Mat img)
{
  timespec startTime;
  getTime(&startTime);
  

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

  // Find all the candidate regions
  vector<PlateRegion> plateRegions = plateDetector->detect(img);

  // Get the number of threads specified and make sure the value is sane (cannot be greater than CPU cores or less than 1)
  int numThreads = config->multithreading_cores;
  if (numThreads > tthread::thread::hardware_concurrency())
    numThreads = tthread::thread::hardware_concurrency();
  if (numThreads <= 0)
    numThreads = 1;


  PlateDispatcher dispatcher(plateRegions, &img, 
			     config, stateIdentifier, ocr, 
			     topN, detectRegion, defaultRegion);
    
  // Spawn n threads to process all of the candidate regions and recognize
  list<tthread::thread*> threads;
  for (int i = 0; i < numThreads; i++)
  {
    tthread::thread * t = new tthread::thread(plateAnalysisThread, (void *) &dispatcher);
    threads.push_back(t);
  }
  
  // Wait for all threads to finish
  for(list<tthread::thread *>::iterator i = threads.begin(); i != threads.end(); ++ i)
  {
    tthread::thread* t = *i;
    t->join();
    delete t;
  }

  if (config->debugTiming)
  {
    timespec endTime;
    getTime(&endTime);
    cout << "Total Time to process image: " << diffclock(startTime, endTime) << "ms." << endl;
  }
  
  if (config->debugGeneral && config->debugShowImages)
  {
    for (int i = 0; i < plateRegions.size(); i++)
    {
      rectangle(img, plateRegions[i].rect, Scalar(0, 0, 255), 2);
    }
    
    for (int i = 0; i < dispatcher.getRecognitionResults().size(); i++)
    {
      for (int z = 0; z < 4; z++)
      {
	AlprCoordinate* coords = dispatcher.getRecognitionResults()[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);
      }
    }

    
    displayImage(config, "Main Image", img);
    cv::waitKey(1);
    
  }
  
  
  vector<AlprResult> results = dispatcher.getRecognitionResults();
  
  if (config->debugPauseOnFrame)
  {
    // Pause indefinitely until they press a key
    while ((char) cv::waitKey(50) == -1)
    {}
  }
  
  return results;
}

void plateAnalysisThread(void* arg)
{
  PlateDispatcher* dispatcher = (PlateDispatcher*) arg;
  
  if (dispatcher->config->debugGeneral)
    cout << "Thread: " << tthread::this_thread::get_id() << " Initialized" << endl;
  
{'fraction_non_alphanumeric': 0.12465878070973613, 'fraction_numerical': 0.009099181073703366, 'mean_word_length': 3.4770875763747453, 'pattern_counts': {'":': 0, '<': 66, '<?xml version=': 0, '>': 50, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2982163', 'n_tokens_mistral': 2986, 'n_tokens_neox': 2848, 'n_words': 822}