mirror of
https://github.com/kerberos-io/openalpr-base.git
synced 2025-10-06 13:26:50 +08:00
499 lines
13 KiB
C++
499 lines
13 KiB
C++
/*
|
|
* Copyright (c) 2015 OpenALPR Technology, Inc.
|
|
*
|
|
* 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 "stdafx.h"
|
|
#include "openalpr-net.h"
|
|
|
|
using namespace System;
|
|
using namespace alpr;
|
|
|
|
namespace openalprnet {
|
|
|
|
public ref class AlprPlateNet sealed
|
|
{
|
|
public:
|
|
AlprPlateNet(AlprPlate plate){
|
|
m_characters = AlprHelper::ToManagedString(plate.characters);
|
|
m_overall_confidence=plate.overall_confidence;
|
|
m_matches_template=plate.matches_template;
|
|
}
|
|
|
|
property System::String^ Characters {
|
|
System::String^ get() {
|
|
return m_characters;
|
|
}
|
|
}
|
|
|
|
property float OverallConfidence {
|
|
float get() {
|
|
return m_overall_confidence;
|
|
}
|
|
}
|
|
|
|
property bool MatchesTemplate {
|
|
bool get() {
|
|
return m_matches_template;
|
|
}
|
|
}
|
|
|
|
private:
|
|
System::String^ m_characters;
|
|
float m_overall_confidence;
|
|
bool m_matches_template;
|
|
};
|
|
|
|
public ref class AlprPlateResultNet sealed
|
|
{
|
|
public:
|
|
AlprPlateResultNet(AlprPlateResult result) {
|
|
m_plate_index = result.plate_index;
|
|
m_processing_time_ms = result.processing_time_ms;
|
|
m_regionConfidence = result.regionConfidence;
|
|
m_region = AlprHelper::ToManagedString(result.region);
|
|
m_bestPlate = gcnew AlprPlateNet(result.bestPlate);
|
|
|
|
m_plate_points = gcnew List<System::Drawing::Point>(4);
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
m_plate_points->Add(System::Drawing::Point(result.plate_points[i].x, result.plate_points[i].y));
|
|
}
|
|
|
|
int num = result.topNPlates.size();
|
|
m_topNPlates = gcnew List<AlprPlateNet^>(num);
|
|
for (int i = 0; i < num; i++)
|
|
{
|
|
m_topNPlates->Add(gcnew AlprPlateNet(result.topNPlates[i]));
|
|
}
|
|
}
|
|
|
|
property int RequestedTopN {
|
|
int get() {
|
|
return m_requested_topn;
|
|
}
|
|
}
|
|
|
|
property int RegionConfidence {
|
|
int get() {
|
|
return m_regionConfidence;
|
|
}
|
|
}
|
|
|
|
property int PlateIndex {
|
|
int get() {
|
|
return m_plate_index;
|
|
}
|
|
}
|
|
|
|
property System::String^ Region {
|
|
System::String^ get() {
|
|
return m_region;
|
|
}
|
|
}
|
|
|
|
property AlprPlateNet^ BestPlate {
|
|
AlprPlateNet^ get() {
|
|
return m_bestPlate;
|
|
}
|
|
}
|
|
|
|
property List<System::Drawing::Point>^ PlatePoints {
|
|
List<System::Drawing::Point>^ get() {
|
|
return m_plate_points;
|
|
}
|
|
}
|
|
|
|
property List<AlprPlateNet^>^ TopNPlates {
|
|
List<AlprPlateNet^>^ get() {
|
|
return m_topNPlates;
|
|
}
|
|
}
|
|
|
|
property float ProcessingTimeMs {
|
|
float get() {
|
|
return m_processing_time_ms;
|
|
}
|
|
}
|
|
|
|
private:
|
|
int m_requested_topn;
|
|
int m_regionConfidence;
|
|
int m_plate_index;
|
|
System::String^ m_region;
|
|
float m_processing_time_ms;
|
|
List<AlprPlateNet^>^ m_topNPlates;
|
|
List<System::Drawing::Point>^ m_plate_points;
|
|
AlprPlateNet^ m_bestPlate;
|
|
};
|
|
|
|
|
|
public ref class AlprResultsNet sealed
|
|
{
|
|
public:
|
|
AlprResultsNet(AlprResults results) {
|
|
m_epoch_time = results.epoch_time;
|
|
m_img_width = results.img_width;
|
|
m_img_height = results.img_height;
|
|
m_total_processing_time_ms = results.total_processing_time_ms;
|
|
|
|
int num_rois = results.regionsOfInterest.size();
|
|
m_regionsOfInterest = gcnew List<System::Drawing::Rectangle>(num_rois);
|
|
for (int i = 0; i < num_rois; i++)
|
|
{
|
|
m_regionsOfInterest->Add(System::Drawing::Rectangle(
|
|
results.regionsOfInterest[i].x,
|
|
results.regionsOfInterest[i].y,
|
|
results.regionsOfInterest[i].width,
|
|
results.regionsOfInterest[i].height));
|
|
}
|
|
|
|
int num_plates = results.plates.size();
|
|
m_plates = gcnew List<AlprPlateResultNet^>(num_plates);
|
|
for (int i = 0; i < num_plates; i++)
|
|
{
|
|
m_plates->Add(gcnew AlprPlateResultNet(results.plates[i]));
|
|
}
|
|
|
|
std::string json = Alpr::toJson(results);
|
|
m_json = AlprHelper::ToManagedString(json);
|
|
}
|
|
|
|
property long EpochTime {
|
|
long get() {
|
|
return m_epoch_time;
|
|
}
|
|
}
|
|
|
|
property int ImageWidth {
|
|
int get() {
|
|
return m_img_width;
|
|
}
|
|
}
|
|
|
|
property int ImageHeight {
|
|
int get() {
|
|
return m_img_height;
|
|
}
|
|
}
|
|
|
|
property float TotalProcessingTimeMs {
|
|
float get() {
|
|
return m_total_processing_time_ms;
|
|
}
|
|
}
|
|
|
|
property List<System::Drawing::Rectangle>^ RegionsOfInterest {
|
|
List<System::Drawing::Rectangle>^ get() {
|
|
return m_regionsOfInterest;
|
|
}
|
|
}
|
|
|
|
property List<AlprPlateResultNet^>^ Plates {
|
|
List<AlprPlateResultNet^>^ get() {
|
|
return m_plates;
|
|
}
|
|
}
|
|
|
|
property System::String^ Json {
|
|
System::String^ get() {
|
|
return m_json;
|
|
}
|
|
}
|
|
|
|
private:
|
|
long m_epoch_time;
|
|
int m_img_width;
|
|
int m_img_height;
|
|
float m_total_processing_time_ms;
|
|
List<System::Drawing::Rectangle>^ m_regionsOfInterest;
|
|
List<AlprPlateResultNet^>^ m_plates;
|
|
System::String^ m_json;
|
|
};
|
|
|
|
|
|
public ref class AlprFrameEventArgs : public EventArgs
|
|
{
|
|
public:
|
|
AlprFrameEventArgs(int frameNumber, System::Drawing::Image^ frame, AlprResultsNet^ results) {
|
|
m_frameNumber = frameNumber;
|
|
m_frame = frame;
|
|
m_results = results;
|
|
m_cancel = false;
|
|
}
|
|
|
|
property int FrameNumber {
|
|
int get() {
|
|
return m_frameNumber;
|
|
}
|
|
}
|
|
|
|
property System::Drawing::Image^ Frame {
|
|
System::Drawing::Image^ get() {
|
|
return m_frame;
|
|
}
|
|
}
|
|
|
|
property AlprResultsNet^ Results {
|
|
AlprResultsNet^ get() {
|
|
return m_results;
|
|
}
|
|
}
|
|
|
|
property bool Cancel {
|
|
bool get() {
|
|
return m_cancel;
|
|
}
|
|
void set( bool cancel ) {
|
|
m_cancel = cancel;
|
|
}
|
|
}
|
|
private:
|
|
int m_frameNumber;
|
|
System::Drawing::Image^ m_frame;
|
|
AlprResultsNet^ m_results;
|
|
bool m_cancel;
|
|
};
|
|
|
|
public ref class AlprNet sealed : IDisposable
|
|
{
|
|
public:
|
|
// Allocate the native object on the C++ Heap via a constructor
|
|
AlprNet(System::String^ country, System::String^ configFile, System::String^ runtimeDir) : m_Impl( new Alpr(marshal_as<std::string>(country), marshal_as<std::string>(configFile), marshal_as<std::string>(runtimeDir)) )
|
|
{
|
|
this->m_config = gcnew AlprConfigNet(this->m_Impl->getConfig());
|
|
}
|
|
|
|
~AlprNet() {
|
|
if(this->m_disposed)
|
|
{
|
|
return;
|
|
}
|
|
|
|
this->!AlprNet();
|
|
this->m_disposed = true;
|
|
}
|
|
|
|
property AlprConfigNet^ Configuration {
|
|
AlprConfigNet^ get()
|
|
{
|
|
return this->m_config;
|
|
}
|
|
}
|
|
|
|
property int TopN {
|
|
int get() {
|
|
return m_topN;
|
|
}
|
|
void set( int topn ){
|
|
m_topN = topn;
|
|
m_Impl->setTopN(topn);
|
|
}
|
|
}
|
|
|
|
property bool DetectRegion {
|
|
bool get() {
|
|
return m_detectRegion;
|
|
}
|
|
void set( bool detectRegion ) {
|
|
m_detectRegion = detectRegion;
|
|
m_Impl->setDetectRegion(detectRegion);
|
|
}
|
|
}
|
|
|
|
property System::String^ DefaultRegion {
|
|
System::String^ get() {
|
|
return m_defaultRegion;
|
|
}
|
|
void set( System::String^ region ){
|
|
m_defaultRegion = region;
|
|
m_Impl->setDefaultRegion(marshal_as<std::string>(region));
|
|
}
|
|
}
|
|
|
|
event EventHandler<AlprFrameEventArgs^>^ FrameProcessed;
|
|
|
|
void RecognizeFromVideo(System::String^ videoPath) {
|
|
if (System::IO::File::Exists(videoPath)) {
|
|
int framenum = 0;
|
|
cv::VideoCapture cap = cv::VideoCapture();
|
|
cap.open(marshal_as<std::string>(videoPath));
|
|
|
|
cv::Mat frame;
|
|
|
|
while (cap.read(frame))
|
|
{
|
|
std::vector<AlprRegionOfInterest> regionsOfInterest;
|
|
regionsOfInterest.push_back(AlprRegionOfInterest(0, 0, frame.cols, frame.rows));
|
|
|
|
AlprResults results = m_Impl->recognize(frame.data, frame.elemSize(), frame.cols, frame.rows, regionsOfInterest);
|
|
int framecolsorig = frame.cols;
|
|
if (framecolsorig % 4 != 0) copyMakeBorder(frame, frame, 0, 0, 0, 4 - (framecolsorig % 4), IPL_BORDER_REPLICATE); //Stride has to be multiple of 4
|
|
Image^ frameImage = gcnew Bitmap(framecolsorig, frame.rows, frame.step, Imaging::PixelFormat::Format24bppRgb, IntPtr(frame.data));
|
|
AlprFrameEventArgs^ alprFrameEventArgs = gcnew AlprFrameEventArgs(framenum, frameImage, gcnew AlprResultsNet(results));
|
|
FrameProcessed(this, alprFrameEventArgs);
|
|
delete frameImage;
|
|
if (alprFrameEventArgs->Cancel) {
|
|
break;
|
|
}
|
|
framenum++;
|
|
}
|
|
}
|
|
else {
|
|
throw gcnew System::IO::FileNotFoundException("No video was not found at " + videoPath, videoPath);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Recognize from an image on disk
|
|
/// </summary>
|
|
AlprResultsNet^ Recognize(System::String^ filepath) {
|
|
return Recognize(filepath, gcnew List<System::Drawing::Rectangle>());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Recognize from an image on disk
|
|
/// </summary>
|
|
AlprResultsNet^ Recognize(System::String^ filepath, List<System::Drawing::Rectangle>^ regionsOfInterest) {
|
|
array<Byte>^ byteArray = File::ReadAllBytes(filepath);
|
|
return Recognize(byteArray, regionsOfInterest);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Recognize from a bitmap
|
|
/// </summary>
|
|
AlprResultsNet^ Recognize(Bitmap^ bitmap)
|
|
{
|
|
return Recognize(bitmap, gcnew List<System::Drawing::Rectangle>());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Recognize from a bitmap
|
|
/// </summary>
|
|
AlprResultsNet^ Recognize(Bitmap^ bitmap, List<System::Drawing::Rectangle>^ regionsOfInterest)
|
|
{
|
|
BitmapMat^ wrapper = gcnew BitmapMat(bitmap);
|
|
cv::Mat frame = wrapper->Value;
|
|
std::vector<AlprRegionOfInterest> rois = AlprHelper::ToVector(regionsOfInterest);
|
|
AlprResults results = m_Impl->recognize(frame.data, frame.elemSize(), frame.cols, frame.rows, rois);
|
|
delete wrapper;
|
|
return gcnew AlprResultsNet(results);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Recognize from MemoryStream representing an encoded image (e.g., BMP, PNG, JPG, GIF etc).
|
|
/// </summary>
|
|
AlprResultsNet^ Recognize(MemoryStream^ memoryStream)
|
|
{
|
|
return Recognize(memoryStream, gcnew List<System::Drawing::Rectangle>());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Recognize from MemoryStream representing an encoded image (e.g., BMP, PNG, JPG, GIF etc).
|
|
/// </summary>
|
|
AlprResultsNet^ Recognize(MemoryStream^ memoryStream, List<System::Drawing::Rectangle>^ regionsOfInterest)
|
|
{
|
|
return Recognize(memoryStream->ToArray(), regionsOfInterest);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Recognize from byte data representing an encoded image (e.g., BMP, PNG, JPG, GIF etc).
|
|
/// </summary>
|
|
/// <param name="imageBuffer">Bytes representing image data</param>
|
|
AlprResultsNet^ Recognize(array<Byte>^ imageBuffer) {
|
|
return Recognize(imageBuffer, gcnew List<System::Drawing::Rectangle>());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Recognize from byte data representing an encoded image (e.g., BMP, PNG, JPG, GIF etc).
|
|
/// </summary>
|
|
/// <param name="imageBuffer">Bytes representing image data</param>
|
|
AlprResultsNet^ Recognize(array<Byte>^ imageBuffer, List<System::Drawing::Rectangle>^ regionsOfInterest) {
|
|
std::vector<char> buffer = AlprHelper::ToVector(imageBuffer);
|
|
std::vector<AlprRegionOfInterest> rois = AlprHelper::ToVector(regionsOfInterest);
|
|
AlprResults results = m_Impl->recognize(buffer, rois);
|
|
return gcnew AlprResultsNet(results);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Recognize from raw pixel data
|
|
/// </summary>
|
|
AlprResultsNet^ Recognize(array<Byte>^ imageBuffer, int bytesPerPixel, int imgWidth, int imgHeight) {
|
|
return Recognize(imageBuffer, bytesPerPixel, imgWidth, imgHeight, gcnew List<System::Drawing::Rectangle>());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Recognize from raw pixel data
|
|
/// </summary>
|
|
AlprResultsNet^ Recognize(array<Byte>^ imageBuffer, int bytesPerPixel, int imgWidth, int imgHeight, List<System::Drawing::Rectangle>^ regionsOfInterest) {
|
|
unsigned char* p = AlprHelper::ToCharPtr(imageBuffer);
|
|
std::vector<AlprRegionOfInterest> rois = AlprHelper::ToVector(regionsOfInterest);
|
|
AlprResults results = m_Impl->recognize(p, bytesPerPixel, imgWidth, imgHeight, rois);
|
|
free(p); // ?? memory leak?
|
|
return gcnew AlprResultsNet(results);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Pre-warp from raw pixel data.
|
|
/// </summary>
|
|
array<Byte>^ PreWarp(array<Byte>^ imageBuffer)
|
|
{
|
|
std::vector<char> buffer = AlprHelper::ToVector(imageBuffer);
|
|
cv::Mat src = cv::imdecode(buffer, CV_LOAD_IMAGE_COLOR);
|
|
|
|
alpr::PreWarp *preWarp = new alpr::PreWarp(m_Impl->getConfig());
|
|
cv::Mat warpedImage = preWarp->warpImage(src);
|
|
|
|
std::vector<uchar> warpedImageVector;
|
|
cv::imencode(".jpg", warpedImage, warpedImageVector);
|
|
|
|
const size_t warpedImageSize = warpedImageVector.size();
|
|
|
|
array<Byte>^ warpedImageByteArray = gcnew array<Byte>(warpedImageSize);
|
|
pin_ptr<Byte> pin(&warpedImageByteArray[0]);
|
|
|
|
std::memcpy(pin, &warpedImageVector[0], warpedImageSize);
|
|
|
|
delete preWarp;
|
|
|
|
return warpedImageByteArray;
|
|
}
|
|
|
|
bool IsLoaded() {
|
|
return m_Impl->isLoaded();
|
|
}
|
|
|
|
static System::String^ GetVersion() {
|
|
return AlprHelper::ToManagedString(Alpr::getVersion());
|
|
}
|
|
|
|
protected:
|
|
// Deallocate the native object on the finalizer just in case no destructor is called
|
|
!AlprNet() {
|
|
delete m_Impl;
|
|
delete m_config;
|
|
}
|
|
|
|
private:
|
|
Alpr * m_Impl;
|
|
AlprConfigNet^ m_config;
|
|
int m_topN;
|
|
bool m_detectRegion;
|
|
System::String^ m_defaultRegion;
|
|
bool m_disposed;
|
|
};
|
|
}
|