/*
* 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 .
*/
#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(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(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^ PlatePoints {
List^ get() {
return m_plate_points;
}
}
property List^ TopNPlates {
List^ 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^ m_topNPlates;
List^ 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(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(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^ RegionsOfInterest {
List^ get() {
return m_regionsOfInterest;
}
}
property List^ Plates {
List^ 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^ m_regionsOfInterest;
List^ 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(country), marshal_as(configFile), marshal_as(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(region));
}
}
event EventHandler^ FrameProcessed;
void RecognizeFromVideo(System::String^ videoPath) {
if (System::IO::File::Exists(videoPath)) {
int framenum = 0;
cv::VideoCapture cap = cv::VideoCapture();
cap.open(marshal_as(videoPath));
cv::Mat frame;
while (cap.read(frame))
{
std::vector 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);
}
}
///
/// Recognize from an image on disk
///
AlprResultsNet^ Recognize(System::String^ filepath) {
return Recognize(filepath, gcnew List());
}
///
/// Recognize from an image on disk
///
AlprResultsNet^ Recognize(System::String^ filepath, List^ regionsOfInterest) {
array^ byteArray = File::ReadAllBytes(filepath);
return Recognize(byteArray, regionsOfInterest);
}
///
/// Recognize from a bitmap
///
AlprResultsNet^ Recognize(Bitmap^ bitmap)
{
return Recognize(bitmap, gcnew List());
}
///
/// Recognize from a bitmap
///
AlprResultsNet^ Recognize(Bitmap^ bitmap, List^ regionsOfInterest)
{
BitmapMat^ wrapper = gcnew BitmapMat(bitmap);
cv::Mat frame = wrapper->Value;
std::vector rois = AlprHelper::ToVector(regionsOfInterest);
AlprResults results = m_Impl->recognize(frame.data, frame.elemSize(), frame.cols, frame.rows, rois);
delete wrapper;
return gcnew AlprResultsNet(results);
}
///
/// Recognize from MemoryStream representing an encoded image (e.g., BMP, PNG, JPG, GIF etc).
///
AlprResultsNet^ Recognize(MemoryStream^ memoryStream)
{
return Recognize(memoryStream, gcnew List());
}
///
/// Recognize from MemoryStream representing an encoded image (e.g., BMP, PNG, JPG, GIF etc).
///
AlprResultsNet^ Recognize(MemoryStream^ memoryStream, List^ regionsOfInterest)
{
return Recognize(memoryStream->ToArray(), regionsOfInterest);
}
///
/// Recognize from byte data representing an encoded image (e.g., BMP, PNG, JPG, GIF etc).
///
/// Bytes representing image data
AlprResultsNet^ Recognize(array^ imageBuffer) {
return Recognize(imageBuffer, gcnew List());
}
///
/// Recognize from byte data representing an encoded image (e.g., BMP, PNG, JPG, GIF etc).
///
/// Bytes representing image data
AlprResultsNet^ Recognize(array^ imageBuffer, List^ regionsOfInterest) {
std::vector buffer = AlprHelper::ToVector(imageBuffer);
std::vector rois = AlprHelper::ToVector(regionsOfInterest);
AlprResults results = m_Impl->recognize(buffer, rois);
return gcnew AlprResultsNet(results);
}
///
/// Recognize from raw pixel data
///
AlprResultsNet^ Recognize(array^ imageBuffer, int bytesPerPixel, int imgWidth, int imgHeight) {
return Recognize(imageBuffer, bytesPerPixel, imgWidth, imgHeight, gcnew List());
}
///
/// Recognize from raw pixel data
///
AlprResultsNet^ Recognize(array^ imageBuffer, int bytesPerPixel, int imgWidth, int imgHeight, List^ regionsOfInterest) {
unsigned char* p = AlprHelper::ToCharPtr(imageBuffer);
std::vector rois = AlprHelper::ToVector(regionsOfInterest);
AlprResults results = m_Impl->recognize(p, bytesPerPixel, imgWidth, imgHeight, rois);
free(p); // ?? memory leak?
return gcnew AlprResultsNet(results);
}
///
/// Pre-warp from raw pixel data.
///
array^ PreWarp(array^ imageBuffer)
{
std::vector 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 warpedImageVector;
cv::imencode(".jpg", warpedImage, warpedImageVector);
const size_t warpedImageSize = warpedImageVector.size();
array^ warpedImageByteArray = gcnew array(warpedImageSize);
pin_ptr 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;
};
}