diff --git a/app/br/br.cpp b/app/br/br.cpp index abeeab1..e78c71d 100644 --- a/app/br/br.cpp +++ b/app/br/br.cpp @@ -171,7 +171,11 @@ public: // Do nothing because we checked for this flag prior to initialization } else if (!strcmp(fun, "objects")) { check(parc <= 2, "Incorrect parameter count for 'objects'."); - printf("%s\n", br_objects(parc >= 1 ? parv[0] : ".*", parc >= 2 ? parv[1] : ".*")); + int size = br_objects(NULL, 0, parc >= 1 ? parv[0] : ".*", parc >= 2 ? parv[1] : ".*"); + char * temp = new char[size]; + br_objects(temp, size, parc >= 1 ? parv[0] : ".*", parc >= 2 ? parv[1] : ".*"); + printf("%s\n", temp); + delete [] temp; } else if (!strcmp(fun, "about")) { check(parc == 0, "No parameters expected for 'about'."); printf("%s\n", br_about()); diff --git a/openbr/gui/algorithm.cpp b/openbr/gui/algorithm.cpp index 39fe742..dbce8dd 100644 --- a/openbr/gui/algorithm.cpp +++ b/openbr/gui/algorithm.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "algorithm.h" @@ -18,7 +19,7 @@ bool br::Algorithm::addAlgorithm(const QString &algorithm, const QString &displa { static QStringList availableAlgorithms; if (availableAlgorithms.isEmpty()) - availableAlgorithms = QString(br_objects("Abbreviation", ".*", false)).split("\n"); + availableAlgorithms = br::Context::objects("Abbreviation", ".*", false); if (!availableAlgorithms.contains(algorithm)) return false; diff --git a/openbr/gui/gallerytoolbar.cpp b/openbr/gui/gallerytoolbar.cpp index 7b6dde4..673e60f 100644 --- a/openbr/gui/gallerytoolbar.cpp +++ b/openbr/gui/gallerytoolbar.cpp @@ -84,7 +84,7 @@ void br::GalleryToolBar::_enroll(const br::File &input) galleryLock.lock(); this->input = input; if (input.suffix() == "gal") gallery = input.name + ".mem"; - else gallery = QString("%1/galleries/%2.gal[cache]").arg(br_scratch_path(), qPrintable(input.baseName()+input.hash())); + else gallery = QString("%1/galleries/%2.gal[cache]").arg(br::Globals->scratchPath(), qPrintable(input.baseName()+input.hash())); files = br::Enroll(input.flat(), gallery.flat()); galleryLock.unlock(); } @@ -148,7 +148,7 @@ void br::GalleryToolBar::home() void br::GalleryToolBar::mean() { - const QString file = QString("%1/mean/%2.png").arg(br_scratch_path(), input.baseName()+input.hash()); + const QString file = QString("%1/mean/%2.png").arg(br::Globals->scratchPath(), input.baseName()+input.hash()); br_set_property("CENTER_TRAIN_B", qPrintable(file)); br::File trainingFile = input; br_train(qPrintable(trainingFile.flat()), "[algorithm=MedianFace]"); diff --git a/openbr/gui/progress.cpp b/openbr/gui/progress.cpp index c162b5d..482367b 100644 --- a/openbr/gui/progress.cpp +++ b/openbr/gui/progress.cpp @@ -1,4 +1,5 @@ #include +#include #include "progress.h" @@ -29,7 +30,7 @@ void br::Progress::checkProgress() const bool visible = progress >= 0 && progress < 100; if (visible) { - showMessage(br_most_recent_message()); + showMessage(Globals->mostRecentMessage); pbProgress.setValue(progress); if (progress > 100) pbProgress.setMaximum(0); else pbProgress.setMaximum(100); diff --git a/openbr/gui/templateviewer.cpp b/openbr/gui/templateviewer.cpp index a811cb2..56ab028 100644 --- a/openbr/gui/templateviewer.cpp +++ b/openbr/gui/templateviewer.cpp @@ -72,7 +72,7 @@ void TemplateViewer::refreshImage() if (file.isNull() || (format == "Photo")) { setImage(file, true); } else { - const QString path = QString(br_scratch_path()) + "/thumbnails"; + const QString path = QString(br::Globals->scratchPath()) + "/thumbnails"; const QString hash = file.hash()+format; const QString processedFile = path+"/"+file.baseName()+hash+".png"; if (!QFileInfo(processedFile).exists()) { diff --git a/openbr/gui/transformeditor.cpp b/openbr/gui/transformeditor.cpp index 4f2752a..c679e4e 100644 --- a/openbr/gui/transformeditor.cpp +++ b/openbr/gui/transformeditor.cpp @@ -24,7 +24,7 @@ using namespace br; br::TransformEditor::TransformEditor(Transform *transform, QWidget *parent) : QWidget(parent) { - name.addItems(QString(br_objects("Transform", ".*", false)).split('\n')); + name.addItems(br::Context::objects("Transform", ".*", false)); layout.addWidget(&name); setLayout(&layout); diff --git a/openbr/openbr.cpp b/openbr/openbr.cpp index 5582f8d..e1d67fe 100644 --- a/openbr/openbr.cpp +++ b/openbr/openbr.cpp @@ -28,9 +28,27 @@ using namespace br; +static int partialCopy(const QString & string, char * buffer, int buffer_length) +{ + + QByteArray byteArray = string.toLocal8Bit(); + + int copyLength = std::min(buffer_length-1, byteArray.size()); + if (copyLength < 0) + return byteArray.size() + 1; + + memcpy(buffer, byteArray.data(), copyLength); + buffer[copyLength] = '\0'; + + return byteArray.size() + 1; +} + const char *br_about() { + static QMutex aboutLock; + QMutexLocker lock(&aboutLock); static QByteArray about = Context::about().toLocal8Bit(); + return about.data(); } @@ -150,53 +168,14 @@ void br_make_pairwise_mask(const char *target_input, const char *query_input, co BEE::makePairwiseMask(target_input, query_input, mask); } -const char *br_most_recent_message() +int br_most_recent_message(char * buffer, int buffer_length) { - static QByteArray byteArray; - byteArray = Globals->mostRecentMessage.toLocal8Bit(); - return byteArray.data(); + return partialCopy(Globals->mostRecentMessage, buffer, buffer_length); } -const char *br_objects(const char *abstractions, const char *implementations, bool parameters) +int br_objects(char * buffer, int buffer_length, const char *abstractions, const char *implementations, bool parameters) { - static QByteArray objects; - - QStringList objectList; - QRegExp abstractionsRegExp(abstractions); - QRegExp implementationsRegExp(implementations); - - if (abstractionsRegExp.exactMatch("Abbreviation")) - foreach (const QString &name, Globals->abbreviations.keys()) - if (implementationsRegExp.exactMatch(name)) - objectList.append(name + (parameters ? "\t" + Globals->abbreviations[name] : "")); - - if (abstractionsRegExp.exactMatch("Distance")) - foreach (const QString &name, Factory::names()) - if (implementationsRegExp.exactMatch(name)) - objectList.append(name + (parameters ? "\t" + Factory::parameters(name) : "")); - - if (abstractionsRegExp.exactMatch("Format")) - foreach (const QString &name, Factory::names()) - if (implementationsRegExp.exactMatch(name)) - objectList.append(name + (parameters ? "\t" + Factory::parameters(name) : "")); - - if (abstractionsRegExp.exactMatch("Initializer")) - foreach (const QString &name, Factory::names()) - if (implementationsRegExp.exactMatch(name)) - objectList.append(name + (parameters ? "\t" + Factory::parameters(name) : "")); - - if (abstractionsRegExp.exactMatch("Output")) - foreach (const QString &name, Factory::names()) - if (implementationsRegExp.exactMatch(name)) - objectList.append(name + (parameters ? "\t" + Factory::parameters(name) : "")); - - if (abstractionsRegExp.exactMatch("Transform")) - foreach (const QString &name, Factory::names()) - if (implementationsRegExp.exactMatch(name)) - objectList.append(name + (parameters ? "\t" + Factory::parameters(name) : "")); - - objects = objectList.join("\n").toLocal8Bit(); - return objects.data(); + return partialCopy(br::Context::objects(abstractions, implementations, parameters).join('\n'), buffer, buffer_length); } bool br_plot(int num_files, const char *files[], const char *destination, bool show) @@ -251,15 +230,15 @@ void br_read_pipe(const char *pipe, int *argc, char ***argv) *argv = rawCharArrayList.data(); } -const char *br_scratch_path() +int br_scratch_path(char * buffer, int buffer_length) { - static QByteArray byteArray; - byteArray = Context::scratchPath().toLocal8Bit(); - return byteArray.data(); + return partialCopy(Context::scratchPath(), buffer, buffer_length); } const char *br_sdk_path() { + static QMutex sdkLock; + QMutexLocker lock(&sdkLock); static QByteArray sdkPath = QDir(Globals->sdkPath).absolutePath().toLocal8Bit(); return sdkPath.data(); } @@ -303,6 +282,8 @@ void br_train_n(int num_inputs, const char *inputs[], const char *model) const char *br_version() { + static QMutex versionLock; + QMutexLocker lock(&versionLock); static QByteArray version = Context::version().toLocal8Bit(); return version.data(); } @@ -380,11 +361,9 @@ bool br_img_is_empty(br_template tmpl) return t->m().empty(); } -const char* br_get_filename(br_template tmpl) +int br_get_filename(char * buffer, int buffer_length, br_template tmpl) { - static QByteArray buffer; - buffer = reinterpret_cast(tmpl)->file.name.toLocal8Bit(); - return buffer.data(); + return partialCopy(reinterpret_cast(tmpl)->file.name, buffer, buffer_length); } void br_set_filename(br_template tmpl, const char *filename) @@ -393,15 +372,11 @@ void br_set_filename(br_template tmpl, const char *filename) t->file.name = filename; } -const char* br_get_metadata_string(br_template tmpl, const char *key) +int br_get_metadata_string(char * buffer, int buffer_length, br_template tmpl, const char *key) { Template *t = reinterpret_cast(tmpl); - // need an object outside of this scope - // so the char pointer is valid - static QByteArray result; QVariant qvar = t->file.value(key); - result = QtUtils::toString(qvar).toUtf8(); - return result.data(); + return partialCopy(QtUtils::toString(qvar), buffer, buffer_length); } br_template_list br_enroll_template(br_template tmpl) diff --git a/openbr/openbr.h b/openbr/openbr.h index d1bd2c2..f2cce16 100644 --- a/openbr/openbr.h +++ b/openbr/openbr.h @@ -41,6 +41,10 @@ extern "C" { * \section managed_return_value Managed Return Value * Memory for const char* return values is managed internally and guaranteed until the next call to the function. * + * \section input_string_buffer Input String Buffer + * Users should input a char * buffer and the size of that buffer. String data will be copied into the buffer, if the buffer is too + * small, only part of the string will be copied. Returns the buffer size required to contain the complete string. + * * \section examples Examples * - \ref c_face_recognition_evaluation * @@ -56,7 +60,6 @@ extern "C" { /*! * \brief Wraps br::Context::about() - * \note \ref managed_return_value * \see br_version */ BR_EXPORT const char *br_about(); @@ -256,10 +259,10 @@ BR_EXPORT void br_make_pairwise_mask(const char *target_input, const char *query /*! * \brief Returns the most recent line sent to stderr. - * \note \ref managed_return_value + * \note \ref input_string_buffer * \see br_progress br_time_remaining */ -BR_EXPORT const char *br_most_recent_message(); +BR_EXPORT int br_most_recent_message(char * buffer, int buffer_length); /*! * \brief Returns names and parameters for the requested objects. @@ -268,10 +271,10 @@ BR_EXPORT const char *br_most_recent_message(); * \param abstractions Regular expression of the abstractions to search. * \param implementations Regular expression of the implementations to search. * \param parameters Include parameters after object name. - * \note \ref managed_return_value + * \note \ref input_string_buffer * \note This function uses Qt's QRegExp syntax. */ -BR_EXPORT const char *br_objects(const char *abstractions = ".*", const char *implementations = ".*", bool parameters = true); +BR_EXPORT int br_objects(char * buffer, int buffer_length, const char *abstractions = ".*", const char *implementations = ".*", bool parameters = true); /*! * \brief Renders recognition performance figures for a set of .csv files created by \ref br_eval. @@ -376,14 +379,14 @@ BR_EXPORT void br_read_pipe(const char *pipe, int *argc, char ***argv); /*! * \brief Wraps br::Context::scratchPath() - * \note \ref managed_return_value + * \note \ref input_string_buffer * \see br_version */ -BR_EXPORT const char *br_scratch_path(); +BR_EXPORT int br_scratch_path(char * buffer, int buffer_length); + /*! * \brief Returns the full path to the root of the SDK. - * \note \ref managed_return_value * \see br_initialize */ BR_EXPORT const char *br_sdk_path(); @@ -436,7 +439,6 @@ BR_EXPORT void br_train_n(int num_inputs, const char *inputs[], const char *mode /*! * \brief Wraps br::Context::version() - * \note \ref managed_return_value * \see br_about br_scratch_path */ BR_EXPORT const char *br_version(); @@ -508,16 +510,18 @@ BR_EXPORT int br_img_channels(br_template tmpl); BR_EXPORT bool br_img_is_empty(br_template tmpl); /*! * \brief Get the filename for a br::Template + * \note \ref input_string_buffer */ -BR_EXPORT const char* br_get_filename(br_template tmpl); +BR_EXPORT int br_get_filename(char * buffer, int buffer_length, br_template tmpl); /*! * \brief Set the filename for a br::Template. */ BR_EXPORT void br_set_filename(br_template tmpl, const char *filename); /*! * \brief Get metadata as a string for the given key in the given template. + * \note \ref input_string_buffer */ -BR_EXPORT const char* br_get_metadata_string(br_template, const char *key); +BR_EXPORT int br_get_metadata_string(char * buffer, int buffer_length, br_template tmpl, const char *key); /*! * \brief Enroll a br::Template from the C API! Returns a pointer to a br::TemplateList * \param tmpl Pointer to a br::Template. diff --git a/openbr/openbr_plugin.cpp b/openbr/openbr_plugin.cpp index 283ec09..1740bde 100644 --- a/openbr/openbr_plugin.cpp +++ b/openbr/openbr_plugin.cpp @@ -203,6 +203,13 @@ QList File::namedRects() const const QVariant &variant = m_metadata[key]; if (variant.canConvert()) rects.append(variant.value()); + else if(variant.canConvert >()) { + QList list = variant.value >(); + for (int i=0;i < list.size();i++) + { + rects.append(list[i]); + } + } } return rects; } @@ -1009,6 +1016,47 @@ QString br::Context::scratchPath() return QString("%1/%2-%3.%4").arg(QDir::homePath(), PRODUCT_NAME, QString::number(PRODUCT_VERSION_MAJOR), QString::number(PRODUCT_VERSION_MINOR)); } + +QStringList br::Context::objects(const char *abstractions, const char *implementations, bool parameters) +{ + QStringList objectList; + QRegExp abstractionsRegExp(abstractions); + QRegExp implementationsRegExp(implementations); + + if (abstractionsRegExp.exactMatch("Abbreviation")) + foreach (const QString &name, Globals->abbreviations.keys()) + if (implementationsRegExp.exactMatch(name)) + objectList.append(name + (parameters ? "\t" + Globals->abbreviations[name] : "")); + + if (abstractionsRegExp.exactMatch("Distance")) + foreach (const QString &name, Factory::names()) + if (implementationsRegExp.exactMatch(name)) + objectList.append(name + (parameters ? "\t" + Factory::parameters(name) : "")); + + if (abstractionsRegExp.exactMatch("Format")) + foreach (const QString &name, Factory::names()) + if (implementationsRegExp.exactMatch(name)) + objectList.append(name + (parameters ? "\t" + Factory::parameters(name) : "")); + + if (abstractionsRegExp.exactMatch("Initializer")) + foreach (const QString &name, Factory::names()) + if (implementationsRegExp.exactMatch(name)) + objectList.append(name + (parameters ? "\t" + Factory::parameters(name) : "")); + + if (abstractionsRegExp.exactMatch("Output")) + foreach (const QString &name, Factory::names()) + if (implementationsRegExp.exactMatch(name)) + objectList.append(name + (parameters ? "\t" + Factory::parameters(name) : "")); + + if (abstractionsRegExp.exactMatch("Transform")) + foreach (const QString &name, Factory::names()) + if (implementationsRegExp.exactMatch(name)) + objectList.append(name + (parameters ? "\t" + Factory::parameters(name) : "")); + + + return objectList; +} + void br::Context::messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) { // Something about this method is not thread safe, and will lead to crashes if qDebug diff --git a/openbr/openbr_plugin.h b/openbr/openbr_plugin.h index e6f2850..3f84d7e 100644 --- a/openbr/openbr_plugin.h +++ b/openbr/openbr_plugin.h @@ -830,6 +830,18 @@ public: */ static QString scratchPath(); + /*! + * \brief Returns names and parameters for the requested objects. + * + * Each object is \c \\n seperated. Arguments are seperated from the object name with a \c \\t. + * \param abstractions Regular expression of the abstractions to search. + * \param implementations Regular expression of the implementations to search. + * \param parameters Include parameters after object name. + * \note \ref managed_return_value + * \note This function uses Qt's QRegExp syntax. + */ + static QStringList objects(const char *abstractions = ".*", const char *implementations = ".*", bool parameters = true); + private: static void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg); }; diff --git a/scripts/brpy/__init__.py b/scripts/brpy/__init__.py index bd9a37d..4060fbc 100644 --- a/scripts/brpy/__init__.py +++ b/scripts/brpy/__init__.py @@ -12,6 +12,14 @@ def _var_string_args(n): s.extend(_string_args(n)) return s +def _handle_string_func(func): + def call_func(*args): + howlong = func('', 0, *args) + msg = 'x'*(howlong-1) + func(msg, howlong, *args) + return msg + return call_func + def init_brpy(br_loc='/usr/local/lib'): """Takes the ctypes lib object for br and initializes all function inputs and outputs""" br_loc += '/libopenbr.%s' @@ -48,9 +56,14 @@ def init_brpy(br_loc='/usr/local/lib'): br.br_is_classifier.restype = c_bool br.br_make_mask.argtypes = _string_args(3) br.br_make_pairwise_mask.argtypes = _string_args(3) - br.br_most_recent_message.restype = c_char_p - br.br_objects.argtypes = _string_args(2) + [c_bool] - br.br_objects.restype = c_char_p + br.br_most_recent_message.argtypes = [c_char_p, c_int] + br.br_most_recent_message.restype = c_int + func = br.br_most_recent_message.__call__ + br.br_most_recent_message = _handle_string_func(func) + br.br_objects.argtypes = [c_char_p, c_int] + _string_args(2) + [c_bool] + br.br_objects.restype = c_int + func2 = br.br_objects.__call__ + br.br_objects = _handle_string_func(func2) br.br_plot.argtypes = plot_args br.br_plot.restype = c_bool br.br_plot_detection.argtypes = plot_args @@ -61,7 +74,10 @@ def init_brpy(br_loc='/usr/local/lib'): br.br_plot_metadata.restype = c_bool br.br_progress.restype = c_float br.br_read_pipe.argtypes = [c_char_p, POINTER(c_int), POINTER(POINTER(c_char_p))] - br.br_scratch_path.restype = c_char_p + br.br_scratch_path.argtypes = [c_char_p, c_int] + br.br_scratch_path.restype = c_int + func3 = br.br_scratch_path.__call__ + br.br_scratch_path = _handle_string_func(func3) br.br_sdk_path.restype = c_char_p br.br_get_header.argtypes = [c_char_p, POINTER(c_char_p), POINTER(c_char_p)] br.br_set_header.argtypes = _string_args(3) @@ -88,11 +104,15 @@ def init_brpy(br_loc='/usr/local/lib'): br.br_img_channels.restype = c_int br.br_img_is_empty.argtypes = [c_void_p] br.br_img_is_empty.restype = c_bool - br.br_get_filename.argtypes = [c_void_p] - br.br_get_filename.restype = c_char_p + br.br_get_filename.argtypes = [c_char_p, c_int, c_void_p] + br.br_get_filename.restype = c_int + func4 = br.br_get_filename.__call__ + br.br_get_filename = _handle_string_func(func4) br.br_set_filename.argtypes = [c_void_p, c_char_p] - br.br_get_metadata_string.argtypes = [c_void_p, c_char_p] - br.br_get_metadata_string.restype = c_char_p + br.br_get_metadata_string.argtypes = [c_char_p, c_int, c_void_p, c_char_p] + br.br_get_metadata_string.restype = c_int + func5 = br.br_get_metadata_string.__call__ + br.br_get_metadata_string = _handle_string_func(func5) br.br_enroll_template.argtypes = [c_void_p] br.br_enroll_template.restype = c_void_p br.br_enroll_template_list.argtypes = [c_void_p]