AlprResults Alpr::recognize(std::string filepath) { std::ifstream ifs(filepath.c_str(), std::ios::binary|std::ios::ate); if (ifs) { std::ifstream::pos_type pos = ifs.tellg(); std::vector<char> buffer(pos); ifs.seekg(0, std::ios::beg); ifs.read(&buffer[0], pos); return this->recognize( buffer ); } else { std::cerr << "file does not exist: " << filepath << std::endl; AlprResults emptyResults; emptyResults.epoch_time = getEpochTimeMs(); emptyResults.img_width = 0; emptyResults.img_height = 0; emptyResults.total_processing_time_ms = 0; return emptyResults; } }
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; }