#include <prodmarkEngine/prodmark.h>
#include <prodmark/prodmark.h>
#include <prodmark/prodmark_result.h>
#include <minimgapi/imgguard.hpp>
#include <se-utils/se-utils.h>
#include "prodmark_proxy.h"
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable: 4290)
#endif // _MSC_VER
/// Engine internal settings and initialization
struct ProdmarkEngineInternalSettingsImpl {
prodmark::EngineSettings config;
};
ProdmarkEngineInternalSettings *
ProdmarkEngineInternalSettings::createFromFilesystem(const std::string &configPath) throw (ProdmarkException) {
try {
std::auto_ptr<ProdmarkEngineInternalSettings> newObject(new ProdmarkEngineInternalSettings);
newObject->m_internalSettings.reset(new ProdmarkEngineInternalSettingsImpl);
// dir path
std::string::size_type pos = configPath.find_last_of("/\\");
std::string dirPath = (pos == std::string::npos) ? "." : configPath.substr(0, pos + 1);
// configure
int res = NO_ERRORS;
std::string error_message;
if (configPath.length() > 3 && "json" == configPath.substr(configPath.length() - 4, 4)) {
res = newObject->m_internalSettings->config.ConfigureFromJSON(configPath,
dirPath);
}
if (res != NO_ERRORS) {
throw ProdmarkException("Failed to read configuration: " + error_message);
}
return newObject.release();
}
catch (const ProdmarkException &e) {
throw e;
}
catch (...) {
throw ProdmarkException("Failed to read configuration: unknown error");
}
return NULL;
}
/// Stream Reporter Proxy
class ProdmarkStreamReporterProxy : public prodmark::SessionCallbacks {
ProdmarkStreamReporterInterface *real_reporter_;
ProdmarkStreamReporterProxy(const ProdmarkStreamReporterProxy &other);
const ProdmarkStreamReporterProxy& operator=(const ProdmarkStreamReporterProxy &other);
public:
ProdmarkStreamReporterProxy() : real_reporter_(NULL) {}
void ResetRealReporter(ProdmarkStreamReporterInterface *reporter = NULL) {
real_reporter_ = reporter;
}
void SnapshotRejected() {
real_reporter_->SnapshotRejected();
}
void SnapshotRejected(const std::string& reason) {
real_reporter_->SnapshotRejected(reason);
}
void SnapshotProcessed(const prodmark::Result &result, bool may_finish) {
ProdmarkResult proxy_result;
ProdmarkProxy::FillProdmarkResult(proxy_result, result);
real_reporter_->SnapshotProcessed(proxy_result, may_finish);
}
};
/// ProdmarkEngine
ProdmarkEngine::ProdmarkEngine(const ProdmarkEngineInternalSettings &internalSettings) throw(ProdmarkException)
: m_engineImpl(new prodmark::Engine()),
m_reporterProxy(new ProdmarkStreamReporterProxy()) {
try {
int ret = m_engineImpl->Configure(internalSettings.getInternalSettings()->config);
if(ret != NO_ERRORS) {
throw ProdmarkException("Failed to configure engine");
}
} catch (...) {
throw ProdmarkException("Failed to configure engine");
}
}
ProdmarkEngine::~ProdmarkEngine() {
// empty
}
void ProdmarkEngine::InitializeSession(ProdmarkStreamReporterInterface *reporter,
ProdmarkEngineSessionHelpers *out_helpers /* = NULL */,
const ProdmarkEngineSessionSettings *settings /* = NULL */) throw(ProdmarkException) {
m_reporterProxy->ResetRealReporter(reporter);
prodmark::SessionHelpers coreHelpers;
prodmark::SessionSettings coreSettings;
if(settings != 0) {
ProdmarkProxy::FillCoreSettings(coreSettings, *settings);
}
try {
int ret = m_engineImpl->InitializeSession(coreSettings, coreHelpers, m_reporterProxy.get());
if(ret != NO_ERRORS) {
throw ProdmarkException("Could not initialize session");
}
} catch (...) {
throw ProdmarkException("Could not initialize session");
}
if(out_helpers != 0) {
ProdmarkProxy::FillProdmarkHelpers(*out_helpers, coreHelpers);
}
}
void ProdmarkEngine::TerminateSession() throw(ProdmarkException) {
try {
int ret = m_engineImpl->TerminateSession();
if(ret != NO_ERRORS) {
throw ProdmarkException("Could not terminate session");
}
} catch (...) {
throw ProdmarkException("Could not terminate session");
}
}
/// Feed Image functions
static void FeedMinImage(const MinImg *pMinImage,
prodmark::Engine &recognizer,
ProdmarkRect &roi,
ProdmarkEngine::ImageOrientation orientation) {
if (orientation == ProdmarkEngine::Landscape) {
try {
int ret = recognizer.ProcessSnapshot(pMinImage, ProdmarkProxy::CoreRect(roi));
if (ret < 0) {
throw ProdmarkException("Failed to perform product marking recognition: non-zero error code");
}
} catch (const std::exception& e) {
throw ProdmarkException(
std::string("Failed to perform product marking recognition: (standard-derived) exception caught: ") + e.what());
} catch (const ProdmarkException& e) {
throw ProdmarkException(e.what());
} catch (...) {
throw ProdmarkException(
"Failed to perform product marking recognition: unknown exception caught");
}
} else {
DECLARE_GUARDED_MINIMG(rotated_image);
int ret = NO_ERRORS;
if (orientation == ProdmarkEngine::InvertedLandscape) {
ret = CloneMinImagePrototype(&rotated_image, pMinImage);
} else {
ret = CloneTransposedMinImagePrototype(&rotated_image, pMinImage);
}
if (ret < 0) {
throw ProdmarkException("Failed to allocate rotated image");
}
int num_of_rotations = 0;
if (orientation == ProdmarkEngine::Portrait) {
num_of_rotations = 1;
} else if (orientation == ProdmarkEngine::InvertedLandscape) {
num_of_rotations = 2;
} else if (orientation == ProdmarkEngine::InvertedPortrait) {
num_of_rotations = 3;
}
ret = RotateMinImageBy90(&rotated_image, pMinImage, num_of_rotations);
if (num_of_rotations == 1 || num_of_rotations == 3) {
int new_roi_x = roi.getY();
int new_roi_y = roi.getX();
roi.setX(new_roi_x);
roi.setY(new_roi_y);
}
if (ret < 0) {
throw ProdmarkException("Failed to rotate image");
}
try {
ret = recognizer.ProcessSnapshot(&rotated_image, ProdmarkProxy::CoreRect(roi));
if (ret < 0) {
throw ProdmarkException("Failed to perform product marking recognition: non-zero error code");
}
} catch (const std::exception& e) {
throw ProdmarkException(
std::string("Failed to perform product marking recognition: (standard-derived) exception caught: ") + e.what());
} catch (const ProdmarkException& e) {
throw ProdmarkException(e.what());
} catch (...) {
throw ProdmarkException(
"Failed to perform product marking recognition: unknown exception caught");
}
}
}
void ProdmarkEngine::FeedImageFile(const std::string &a_filename,
ImageOrientation orientation) throw (ProdmarkException)
{
if (!m_engineImpl.get()) {
throw ProdmarkException("Recognizer is not initialized.");
}
DECLARE_GUARDED_MINIMG(sourceImage);
int ret = se::utils::LoadImage(&sourceImage, a_filename.c_str());
if (ret != NO_ERRORS) {
throw ProdmarkException("Failed to read image file.");
}
int X = std::max(0, sourceImage.width - sourceImage.height) / 2;
int Y = std::max(0, sourceImage.height - sourceImage.width) / 2;
ProdmarkRect full_roi = ProdmarkRect(X, Y, sourceImage.width - 2 * X, sourceImage.height - 2 * Y);
if (orientation == ProdmarkEngine::Portrait || orientation == ProdmarkEngine::InvertedPortrait) {
full_roi.setWidth(sourceImage.height - 2 * Y);
full_roi.setHeight(sourceImage.width - 2 * X);
full_roi.setX(Y);
full_roi.setY(X);
}
FeedMinImage(&sourceImage, *m_engineImpl, full_roi, orientation);
}
void ProdmarkEngine::FeedUncompressedYUVImageData(char *a_data,
size_t a_len,
int width,
int height,
int stride,
ProdmarkRect roi,
ImageOrientation orientation) throw(ProdmarkException) {
if (height & 1 || width & 1 || stride < width || a_len != stride * height * 1.5) {
throw ProdmarkException("Failed (0) to process image");
}
/// Wrap MinImg around the image buffer
MinImg image_0 = {0};
image_0.pScan0 = reinterpret_cast<uint8_t *>(a_data);
image_0.width = width;
image_0.height = height;
image_0.stride = stride;
image_0.channels = 1;
image_0.channelDepth = 1;
image_0.format = FMT_UINT;
MinImg image_1 = {0};
image_1.pScan0 = reinterpret_cast<uint8_t *>(a_data) + height * stride;
image_1.width = width / 2;
image_1.height = height / 2;
image_1.stride = stride;
image_1.channels = 2;
image_1.channelDepth = 1;
image_1.format = FMT_UINT;
DECLARE_GUARDED_MINIMG(image_rgb);
if (NewMinImagePrototype(&image_rgb, width, height, 3, TYP_UINT8) != NO_ERRORS) {
throw ProdmarkException("Failed (1) to process image");
}
if (YUV2RGB(&image_rgb, &image_0, &image_1) != NO_ERRORS) {
throw ProdmarkException("Failed (2) to process image");
}
FeedMinImage(&image_rgb, *m_engineImpl, roi, orientation);
}
#ifdef _MSC_VER
# pragma warning(pop)
#endif // _MSC_VER