Commit 1ed68d6d110c1d0befd8da1a4e4cf7b4bf129381
Merge branch 'master' of https://github.com/biometrics/openbr
Showing
10 changed files
with
199 additions
and
92 deletions
openbr/CMakeLists.txt
| ... | ... | @@ -34,7 +34,7 @@ set(JANUS_BUILD_PP5_WRAPPER ${BR_WITH_PP5} CACHE BOOL "Build Janus implementatio |
| 34 | 34 | set(JANUS_BUILD_DOCS ${BR_BUILD_DOCUMENTATION} CACHE BOOL "Build Janus HTML Doxygen documentation") |
| 35 | 35 | mark_as_advanced(JANUS_BUILD_PP5_WRAPPER) |
| 36 | 36 | mark_as_advanced(JANUS_BUILD_DOCS) |
| 37 | -set(JANUS_TEST_IMPLEMENTATION openbr) | |
| 37 | +set(JANUS_IMPLEMENTATION openbr) | |
| 38 | 38 | add_subdirectory(janus) |
| 39 | 39 | |
| 40 | 40 | # Install | ... | ... |
openbr/core/bee.cpp
| ... | ... | @@ -172,6 +172,8 @@ Mat BEE::readMat(const br::File &matrix, QString *targetSigset, QString *querySi |
| 172 | 172 | qint64 read = file.read((char*)m.data, bytesExpected); |
| 173 | 173 | if (read != bytesExpected) |
| 174 | 174 | qFatal("Invalid matrix size."); |
| 175 | + if (!file.atEnd()) | |
| 176 | + qFatal("Expected matrix end of file."); | |
| 175 | 177 | file.close(); |
| 176 | 178 | |
| 177 | 179 | Mat result; | ... | ... |
openbr/janus.cpp
| ... | ... | @@ -3,140 +3,138 @@ |
| 3 | 3 | #endif |
| 4 | 4 | |
| 5 | 5 | #include "janus.h" |
| 6 | +#include "janus_io.h" | |
| 6 | 7 | #include "openbr_plugin.h" |
| 7 | 8 | |
| 8 | -// Use the provided default implementation of some functions | |
| 9 | -#include "janus/src/janus.cpp" | |
| 10 | - | |
| 11 | 9 | using namespace br; |
| 12 | 10 | |
| 13 | 11 | static QSharedPointer<Transform> transform; |
| 14 | 12 | static QSharedPointer<Distance> distance; |
| 15 | 13 | |
| 14 | +size_t janus_max_template_size() | |
| 15 | +{ | |
| 16 | + return JANUS_MAX_TEMPLATE_SIZE_LIMIT; | |
| 17 | +} | |
| 18 | + | |
| 16 | 19 | janus_error janus_initialize(const char *sdk_path, const char *model_file) |
| 17 | 20 | { |
| 18 | 21 | int argc = 1; |
| 19 | 22 | const char *argv[1] = { "janus" }; |
| 20 | 23 | Context::initialize(argc, (char**)argv, sdk_path); |
| 21 | 24 | QString algorithm = model_file; |
| 22 | - if (algorithm.isEmpty()) algorithm = "Cvt(Gray)+Affine(88,88,0.25,0.35)+<FaceRecognitionExtraction>+<FaceRecognitionEmbedding>+<FaceRecognitionQuantization>:ByteL1"; | |
| 23 | - transform = Transform::fromAlgorithm(algorithm, false); | |
| 24 | - distance = Distance::fromAlgorithm(algorithm); | |
| 25 | + if (algorithm.isEmpty()) { | |
| 26 | + transform = Transform::fromAlgorithm("Cvt(Gray)+Affine(88,88,0.25,0.35)+<FaceRecognitionExtraction>+<FaceRecognitionEmbedding>+<FaceRecognitionQuantization>", false); | |
| 27 | + distance = Distance::fromAlgorithm("FaceRecognition"); | |
| 28 | + } else if (algorithm == "PP5") { | |
| 29 | + transform.reset(Transform::make("PP5Enroll", NULL)); | |
| 30 | + distance.reset(Distance::make("PP5Compare", NULL)); | |
| 31 | + } else { | |
| 32 | + transform = Transform::fromAlgorithm(algorithm, false); | |
| 33 | + distance = Distance::fromAlgorithm(algorithm); | |
| 34 | + } | |
| 25 | 35 | return JANUS_SUCCESS; |
| 26 | 36 | } |
| 27 | 37 | |
| 28 | 38 | janus_error janus_finalize() |
| 29 | 39 | { |
| 40 | + transform.reset(); | |
| 41 | + distance.reset(); | |
| 30 | 42 | Context::finalize(); |
| 31 | 43 | return JANUS_SUCCESS; |
| 32 | 44 | } |
| 33 | 45 | |
| 34 | -struct janus_incomplete_template_type | |
| 35 | -{ | |
| 36 | - QList<cv::Mat> data; | |
| 37 | -}; | |
| 46 | +struct janus_template_type : public Template | |
| 47 | +{}; | |
| 38 | 48 | |
| 39 | -janus_error janus_initialize_template(janus_incomplete_template *incomplete_template) | |
| 49 | +janus_error janus_initialize_template(janus_template *template_) | |
| 40 | 50 | { |
| 41 | - *incomplete_template = new janus_incomplete_template_type(); | |
| 51 | + *template_ = new janus_template_type(); | |
| 42 | 52 | return JANUS_SUCCESS; |
| 43 | 53 | } |
| 44 | 54 | |
| 45 | -janus_error janus_add_image(const janus_image image, const janus_attribute_list attributes, janus_incomplete_template incomplete_template) | |
| 55 | +janus_error janus_augment(const janus_image image, const janus_attribute_list attributes, janus_template template_) | |
| 46 | 56 | { |
| 47 | 57 | Template t; |
| 48 | 58 | t.append(cv::Mat(image.height, |
| 49 | 59 | image.width, |
| 50 | - image.color_space == JANUS_GRAY8 ? CV_8UC1 : CV_8UC1, | |
| 60 | + image.color_space == JANUS_GRAY8 ? CV_8UC1 : CV_8UC3, | |
| 51 | 61 | image.data)); |
| 52 | 62 | for (size_t i=0; i<attributes.size; i++) |
| 53 | 63 | t.file.set(janus_attribute_to_string(attributes.attributes[i]), attributes.values[i]); |
| 54 | 64 | |
| 55 | - if (!t.file.contains("JANUS_RIGHT_EYE_X") || | |
| 56 | - !t.file.contains("JANUS_RIGHT_EYE_Y") || | |
| 57 | - !t.file.contains("JANUS_LEFT_EYE_X") || | |
| 58 | - !t.file.contains("JANUS_LEFT_EYE_Y")) | |
| 65 | + if (!t.file.contains("RIGHT_EYE_X") || | |
| 66 | + !t.file.contains("RIGHT_EYE_Y") || | |
| 67 | + !t.file.contains("LEFT_EYE_X") || | |
| 68 | + !t.file.contains("LEFT_EYE_Y")) | |
| 59 | 69 | return JANUS_SUCCESS; |
| 60 | 70 | |
| 61 | - t.file.set("Affine_0", QPointF(t.file.get<float>("JANUS_RIGHT_EYE_X"), t.file.get<float>("JANUS_RIGHT_EYE_Y"))); | |
| 62 | - t.file.set("Affine_1", QPointF(t.file.get<float>("JANUS_LEFT_EYE_X"), t.file.get<float>("JANUS_LEFT_EYE_Y"))); | |
| 71 | + t.file.set("Affine_0", QPointF(t.file.get<float>("RIGHT_EYE_X"), t.file.get<float>("RIGHT_EYE_Y"))); | |
| 72 | + t.file.set("Affine_1", QPointF(t.file.get<float>("LEFT_EYE_X"), t.file.get<float>("LEFT_EYE_Y"))); | |
| 63 | 73 | Template u; |
| 64 | 74 | transform->project(t, u); |
| 65 | - incomplete_template->data.append(u); | |
| 75 | + template_->append(u); | |
| 66 | 76 | return JANUS_SUCCESS; |
| 67 | 77 | } |
| 68 | 78 | |
| 69 | -janus_error janus_finalize_template(janus_incomplete_template incomplete_template, janus_template template_, size_t *bytes) | |
| 79 | +janus_error janus_finalize_template(janus_template template_, janus_flat_template flat_template, size_t *bytes) | |
| 70 | 80 | { |
| 71 | - size_t templateBytes = 0; | |
| 72 | - size_t numTemplates = 0; | |
| 73 | - *bytes = sizeof(templateBytes) + sizeof(numTemplates); | |
| 74 | - janus_template pos = template_ + *bytes; | |
| 75 | - | |
| 76 | - foreach (const cv::Mat &m, incomplete_template->data) { | |
| 81 | + foreach (const cv::Mat &m, *template_) { | |
| 77 | 82 | assert(m.isContinuous()); |
| 78 | - const size_t currentTemplateBytes = m.rows * m.cols * m.elemSize(); | |
| 79 | - if (templateBytes == 0) | |
| 80 | - templateBytes = currentTemplateBytes; | |
| 81 | - if (templateBytes != currentTemplateBytes) | |
| 82 | - return JANUS_UNKNOWN_ERROR; | |
| 83 | - if (*bytes + templateBytes > janus_max_template_size()) | |
| 83 | + const size_t templateBytes = m.rows * m.cols * m.elemSize(); | |
| 84 | + if (*bytes + sizeof(size_t) + templateBytes > janus_max_template_size()) | |
| 84 | 85 | break; |
| 85 | - memcpy(pos, m.data, templateBytes); | |
| 86 | - *bytes += templateBytes; | |
| 87 | - pos = pos + templateBytes; | |
| 88 | - numTemplates++; | |
| 86 | + memcpy(flat_template, &templateBytes, sizeof(templateBytes)); | |
| 87 | + flat_template += sizeof(templateBytes); | |
| 88 | + memcpy(flat_template, m.data, templateBytes); | |
| 89 | + flat_template += templateBytes; | |
| 90 | + *bytes += sizeof(size_t) + templateBytes; | |
| 89 | 91 | } |
| 90 | 92 | |
| 91 | - *(reinterpret_cast<size_t*>(template_)+0) = templateBytes; | |
| 92 | - *(reinterpret_cast<size_t*>(template_)+1) = numTemplates; | |
| 93 | - delete incomplete_template; | |
| 93 | + delete template_; | |
| 94 | 94 | return JANUS_SUCCESS; |
| 95 | 95 | } |
| 96 | 96 | |
| 97 | -janus_error janus_verify(const janus_template a, const size_t a_bytes, const janus_template b, const size_t b_bytes, double *similarity) | |
| 97 | +janus_error janus_verify(const janus_flat_template a, const size_t a_bytes, const janus_flat_template b, const size_t b_bytes, double *similarity) | |
| 98 | 98 | { |
| 99 | - (void) a_bytes; | |
| 100 | - (void) b_bytes; | |
| 101 | - | |
| 102 | - size_t a_template_bytes, a_templates, b_template_bytes, b_templates; | |
| 103 | - a_template_bytes = *(reinterpret_cast<size_t*>(a)+0); | |
| 104 | - a_templates = *(reinterpret_cast<size_t*>(a)+1); | |
| 105 | - b_template_bytes = *(reinterpret_cast<size_t*>(b)+0); | |
| 106 | - b_templates = *(reinterpret_cast<size_t*>(b)+1); | |
| 107 | - if (a_template_bytes != b_template_bytes) | |
| 108 | - return JANUS_UNKNOWN_ERROR; | |
| 99 | + *similarity = 0; | |
| 109 | 100 | |
| 110 | - float dist = 0; | |
| 111 | - for (size_t i=0; i<a_templates; i++) | |
| 112 | - for (size_t j=0; j<b_templates; j++) | |
| 113 | - dist += distance->compare(cv::Mat(1, a_template_bytes, CV_8UC1, a+2*sizeof(size_t)+i*a_template_bytes), | |
| 114 | - cv::Mat(1, b_template_bytes, CV_8UC1, b+2*sizeof(size_t)+i*b_template_bytes)); | |
| 115 | - *similarity = a_templates * b_templates / dist; | |
| 116 | - return JANUS_SUCCESS; | |
| 117 | -} | |
| 101 | + int comparisons = 0; | |
| 102 | + janus_flat_template a_template = a; | |
| 103 | + while (a_template < a + a_bytes) { | |
| 104 | + const size_t a_template_bytes = *reinterpret_cast<size_t*>(a_template); | |
| 105 | + a_template += sizeof(a_template_bytes); | |
| 118 | 106 | |
| 119 | -struct janus_incomplete_gallery_type | |
| 120 | -{ | |
| 121 | - QList< QPair<janus_template, janus_template_id> > templates; | |
| 122 | -}; | |
| 107 | + janus_flat_template b_template = b; | |
| 108 | + while (b_template < b + b_bytes) { | |
| 109 | + const size_t b_template_bytes = *reinterpret_cast<size_t*>(b_template); | |
| 110 | + b_template += sizeof(b_template_bytes); | |
| 123 | 111 | |
| 124 | -janus_error janus_initialize_gallery(janus_incomplete_gallery *incomplete_gallery) | |
| 125 | -{ | |
| 126 | - *incomplete_gallery = new janus_incomplete_gallery_type(); | |
| 127 | - return JANUS_SUCCESS; | |
| 128 | -} | |
| 112 | + *similarity += distance->compare(cv::Mat(1, a_template_bytes, CV_8UC1, a_template), | |
| 113 | + cv::Mat(1, b_template_bytes, CV_8UC1, b_template)); | |
| 114 | + comparisons++; | |
| 129 | 115 | |
| 130 | -janus_error janus_add_template(const janus_template template_, const size_t bytes, const janus_template_id template_id, janus_incomplete_gallery incomplete_gallery) | |
| 131 | -{ | |
| 132 | - (void) bytes; | |
| 133 | - incomplete_gallery->templates.append(QPair<janus_template, janus_template_id>(template_, template_id)); | |
| 116 | + b_template += b_template_bytes; | |
| 117 | + } | |
| 118 | + | |
| 119 | + a_template += a_template_bytes; | |
| 120 | + } | |
| 121 | + | |
| 122 | + if (*similarity != *similarity) // True for NaN | |
| 123 | + return JANUS_UNKNOWN_ERROR; | |
| 124 | + | |
| 125 | + *similarity /= comparisons; | |
| 134 | 126 | return JANUS_SUCCESS; |
| 135 | 127 | } |
| 136 | 128 | |
| 137 | -janus_error janus_finalize_gallery(janus_incomplete_gallery incomplete_gallery, const char *gallery_file) | |
| 129 | +janus_error janus_enroll(const janus_template template_, const janus_template_id template_id, janus_gallery gallery) | |
| 138 | 130 | { |
| 139 | - (void) incomplete_gallery; | |
| 140 | - (void) gallery_file; | |
| 131 | + template_->file.set("TEMPLATE_ID", template_id); | |
| 132 | + QFile file(gallery); | |
| 133 | + if (!file.open(QFile::WriteOnly | QFile::Append)) | |
| 134 | + return JANUS_WRITE_ERROR; | |
| 135 | + QDataStream stream(&file); | |
| 136 | + stream << *template_; | |
| 137 | + file.close(); | |
| 138 | + delete template_; | |
| 141 | 139 | return JANUS_SUCCESS; |
| 142 | 140 | } | ... | ... |
openbr/openbr.cpp
| ... | ... | @@ -383,7 +383,9 @@ bool br_img_is_empty(br_template tmpl) |
| 383 | 383 | const char* br_get_filename(br_template tmpl) |
| 384 | 384 | { |
| 385 | 385 | Template *t = reinterpret_cast<Template*>(tmpl); |
| 386 | - return t->file.name.toStdString().c_str(); | |
| 386 | + QByteArray s = t->file.name.toLocal8Bit(); | |
| 387 | + char *buffer = s.data(); | |
| 388 | + return buffer; | |
| 387 | 389 | } |
| 388 | 390 | |
| 389 | 391 | void br_set_filename(br_template tmpl, const char *filename) | ... | ... |
openbr/openbr_plugin.h
| ... | ... | @@ -1374,7 +1374,7 @@ BR_EXPORT void Cat(const QStringList &inputGalleries, const QString &outputGalle |
| 1374 | 1374 | |
| 1375 | 1375 | /*! |
| 1376 | 1376 | * \brief Deduplicate a gallery. |
| 1377 | - * \param inputGalleries Gallery to deduplicate. | |
| 1377 | + * \param inputGallery Gallery to deduplicate. | |
| 1378 | 1378 | * \param outputGallery Gallery to store the deduplicated result. |
| 1379 | 1379 | * \param threshold Match score threshold to determine duplicates. |
| 1380 | 1380 | */ | ... | ... |
openbr/plugins/algorithms.cpp
| ... | ... | @@ -52,6 +52,7 @@ class AlgorithmsInitializer : public Initializer |
| 52 | 52 | Globals->abbreviations.insert("AgeGenderDemo", "Stream(SaveMat(original)+Cvt(Gray)+Cascade(FrontalFace)+Expand+<FaceClassificationRegistration>+<FaceClassificationExtraction>+<AgeRegressor>/<GenderClassifier>+Discard+RestoreMat(original)+Draw(inPlace=true)+DrawPropertiesPoint([Age,Gender],Affine_0,inPlace=true)+SaveMat(original)+Discard+Contract+RestoreMat(original)+FPSCalc+Show(false,[AvgFPS,Age,Gender])+Discard)"); |
| 53 | 53 | Globals->abbreviations.insert("ShowOpticalFlowField", "Stream(SaveMat(original)+AggregateFrames(2)+OpticalFlow(useMagnitude=false)+Grid(100,100)+DrawOpticalFlow+FPSLimit(30)+Show(false)+Discard)"); |
| 54 | 54 | Globals->abbreviations.insert("ShowOpticalFlowMagnitude", "Stream(AggregateFrames(2)+OpticalFlow+Normalize(Range,false,0,255)+Cvt(Color)+Draw+FPSLimit(30)+Show(false)+Discard)"); |
| 55 | + Globals->abbreviations.insert("ShowMotionSegmentation", "Stream(DropFrames(5)+SaveMat(original)+AggregateFrames(2)+OpticalFlow+CvtUChar+Segmentation+DrawSegmentation+Draw+FPSLimit(30)+Show(false)+Discard)"); | |
| 55 | 56 | |
| 56 | 57 | Globals->abbreviations.insert("HOG", "Stream(DropFrames(5)+Cvt(Gray)+Grid(5,5)+ROIFromPts(32,24)+Expand+Resize(32,32)+Gradient+RectRegions+Bin(0,360,8)+Hist(8)+Cat)+Contract+CatRows+KMeans(500)+Hist(500)+SVM"); |
| 57 | 58 | Globals->abbreviations.insert("HOF", "Stream(DropFrames(5)+Grid(5,5)+AggregateFrames(2)+OpticalFlow+ROIFromPts(32,24)+Expand+Resize(32,32)+Gradient+RectRegions+Bin(0,360,8)+Hist(8)+Cat)+Contract+CatRows+KMeans(500)+Hist(500)"); |
| ... | ... | @@ -78,7 +79,7 @@ class AlgorithmsInitializer : public Initializer |
| 78 | 79 | Globals->abbreviations.insert("ColoredLBP", "Open+Affine(128,128,0.37,0.45)+Cvt(Gray)+Blur(1.1)+Gamma(0.2)+DoG(1,2)+ContrastEq(0.1,10)+LBP(1,2)+ColoredU2"); |
| 79 | 80 | |
| 80 | 81 | // Transforms |
| 81 | - Globals->abbreviations.insert("FaceDetection", "(Open+Cvt(Gray)+Cascade(FrontalFace))"); | |
| 82 | + Globals->abbreviations.insert("FaceDetection", "Open+Cvt(Gray)+Cascade(FrontalFace)"); | |
| 82 | 83 | Globals->abbreviations.insert("DenseLBP", "(Blur(1.1)+Gamma(0.2)+DoG(1,2)+ContrastEq(0.1,10)+LBP(1,2)+RectRegions(8,8,6,6)+Hist(59))"); |
| 83 | 84 | Globals->abbreviations.insert("DenseSIFT", "(Grid(10,10)+SIFTDescriptor(12)+ByRow)"); |
| 84 | 85 | Globals->abbreviations.insert("FaceRecognitionRegistration", "(ASEFEyes+Affine(88,88,0.25,0.35)+DownsampleTraining(FTE(DFFS),instances=1))"); | ... | ... |
openbr/plugins/draw.cpp
| ... | ... | @@ -374,6 +374,56 @@ class DrawOpticalFlow : public UntrainableTransform |
| 374 | 374 | }; |
| 375 | 375 | BR_REGISTER(Transform, DrawOpticalFlow) |
| 376 | 376 | |
| 377 | +/*! | |
| 378 | + * \ingroup transforms | |
| 379 | + * \brief Fill in the segmentations or draw a line between intersecting segments. | |
| 380 | + * \author Austin Blanton \cite imaus10 | |
| 381 | + */ | |
| 382 | +class DrawSegmentation : public UntrainableTransform | |
| 383 | +{ | |
| 384 | + Q_OBJECT | |
| 385 | + Q_PROPERTY(bool fillSegment READ get_fillSegment WRITE set_fillSegment RESET reset_fillSegment STORED false) | |
| 386 | + BR_PROPERTY(bool, fillSegment, true) | |
| 387 | + Q_PROPERTY(QString original READ get_original WRITE set_original RESET reset_original STORED false) | |
| 388 | + BR_PROPERTY(QString, original, "original") | |
| 389 | + | |
| 390 | + void project(const Template &src, Template &dst) const | |
| 391 | + { | |
| 392 | + if (!src.file.contains("SegmentsMask") || !src.file.contains("NumSegments")) qFatal("Must supply a Contours object in the metadata to drawContours."); | |
| 393 | + Mat segments = src.file.get<Mat>("SegmentsMask"); | |
| 394 | + int numSegments = src.file.get<int>("NumSegments"); | |
| 395 | + | |
| 396 | + dst.file = src.file; | |
| 397 | + Mat drawn; | |
| 398 | + if (fillSegment) { | |
| 399 | + drawn = Mat(segments.size(), CV_8UC3, Scalar::all(0)); | |
| 400 | + } else { | |
| 401 | + if (!dst.file.contains(original)) qFatal("You must store the original image in the metadata with SaveMat."); | |
| 402 | + drawn = dst.file.get<Mat>(original); | |
| 403 | + dst.file.remove(original); | |
| 404 | + } | |
| 405 | + | |
| 406 | + for (int i=1; i<numSegments+1; i++) { | |
| 407 | + Mat mask = segments == i; | |
| 408 | + if (fillSegment) { // color the whole segment | |
| 409 | + // set to a random color - get ready for a craaaazy acid trip | |
| 410 | + int b = theRNG().uniform(0, 255); | |
| 411 | + int g = theRNG().uniform(0, 255); | |
| 412 | + int r = theRNG().uniform(0, 255); | |
| 413 | + drawn.setTo(Scalar(r,g,b), mask); | |
| 414 | + } else { // draw lines where there's a color change | |
| 415 | + vector<vector<Point> > contours; | |
| 416 | + Scalar color(0,255,0); | |
| 417 | + findContours(mask, contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE); | |
| 418 | + drawContours(drawn, contours, -1, color); | |
| 419 | + } | |
| 420 | + } | |
| 421 | + | |
| 422 | + dst.m() = drawn; | |
| 423 | + } | |
| 424 | +}; | |
| 425 | +BR_REGISTER(Transform, DrawSegmentation) | |
| 426 | + | |
| 377 | 427 | // TODO: re-implement EditTransform using Qt |
| 378 | 428 | #if 0 |
| 379 | 429 | /*! | ... | ... |
openbr/plugins/segmentation.cpp
0 โ 100644
| 1 | +#include <opencv2/imgproc/imgproc.hpp> | |
| 2 | +#include "openbr_internal.h" | |
| 3 | +#include "openbr/core/opencvutils.h" | |
| 4 | + | |
| 5 | +using namespace cv; | |
| 6 | + | |
| 7 | +namespace br | |
| 8 | +{ | |
| 9 | + | |
| 10 | +/*! | |
| 11 | + * \ingroup transforms | |
| 12 | + * \brief Applies watershed segmentation. | |
| 13 | + * \author Austin Blanton \cite imaus10 | |
| 14 | + */ | |
| 15 | +class WatershedSegmentationTransform : public UntrainableTransform | |
| 16 | +{ | |
| 17 | + Q_OBJECT | |
| 18 | + void project(const Template &src, Template &dst) const | |
| 19 | + { | |
| 20 | + dst = src; | |
| 21 | + | |
| 22 | + Mat mod; | |
| 23 | +// adaptiveThreshold(src.m(), src.m(), 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 33, 5); | |
| 24 | + threshold(src.m(), mod, 0, 255, THRESH_BINARY+THRESH_OTSU); | |
| 25 | + | |
| 26 | + // findContours requires an 8-bit 1-channel image | |
| 27 | + // and modifies its source image | |
| 28 | + if (mod.depth() != CV_8U) OpenCVUtils::cvtUChar(mod, mod); | |
| 29 | + if (mod.channels() != 1) OpenCVUtils::cvtGray(mod, mod); | |
| 30 | + vector<vector<Point> > contours; | |
| 31 | + vector<Vec4i> hierarchy; | |
| 32 | + findContours(mod, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE); | |
| 33 | + | |
| 34 | + // draw the contour delineations as 1,2,3... for input to watershed | |
| 35 | + Mat markers = Mat::zeros(mod.size(), CV_32S); | |
| 36 | + int compCount=0; | |
| 37 | + for (int idx=0; idx>=0; idx=hierarchy[idx][0], compCount++) { | |
| 38 | + drawContours(markers, contours, idx, Scalar::all(compCount+1), -1, 8, hierarchy, INT_MAX); | |
| 39 | + } | |
| 40 | + | |
| 41 | + Mat orig = src.m(); | |
| 42 | + // watershed requires a 3-channel 8-bit image | |
| 43 | + if (orig.channels() == 1) cvtColor(orig, orig, CV_GRAY2BGR); | |
| 44 | + watershed(orig, markers); | |
| 45 | + dst.file.set("SegmentsMask", QVariant::fromValue(markers)); | |
| 46 | + dst.file.set("NumSegments", compCount); | |
| 47 | + } | |
| 48 | +}; | |
| 49 | +BR_REGISTER(Transform, WatershedSegmentationTransform) | |
| 50 | + | |
| 51 | +} // namespace br | |
| 52 | + | |
| 53 | +#include "segmentation.moc" | ... | ... |
openbr/plugins/stream.cpp
| ... | ... | @@ -347,10 +347,11 @@ public: |
| 347 | 347 | } |
| 348 | 348 | |
| 349 | 349 | // first 4 bytes store 0xEDFE, next 24 store 'Norpix seq ' |
| 350 | - char *firstFour = new char[4], *nextTwentyFour; | |
| 350 | + char firstFour[4]; | |
| 351 | 351 | seqFile.seekg(0, ios::beg); |
| 352 | 352 | seqFile.read(firstFour, 4); |
| 353 | - nextTwentyFour = readText(24); | |
| 353 | + char nextTwentyFour[24]; | |
| 354 | + readText(24, nextTwentyFour); | |
| 354 | 355 | if (firstFour[0] != (char)0xED || firstFour[1] != (char)0xFE || strncmp(nextTwentyFour, "Norpix seq", 10) != 0) { |
| 355 | 356 | qDebug("Invalid header in seq file"); |
| 356 | 357 | return false; |
| ... | ... | @@ -363,7 +364,8 @@ public: |
| 363 | 364 | qDebug("Invalid header size"); |
| 364 | 365 | return false; |
| 365 | 366 | } |
| 366 | - char *desc = readText(512); | |
| 367 | + char desc[512]; | |
| 368 | + readText(512, desc); | |
| 367 | 369 | basis.file.set("Description", QString(desc)); |
| 368 | 370 | |
| 369 | 371 | width = readInt(); |
| ... | ... | @@ -414,9 +416,9 @@ public: |
| 414 | 416 | // but there might be 16 extra bytes instead of 8... |
| 415 | 417 | if (i == 1) { |
| 416 | 418 | seqFile.seekg(s, ios::beg); |
| 417 | - char *zero = new char[1]; | |
| 418 | - seqFile.read(zero, 1); | |
| 419 | - if (zero[0] == 0) { | |
| 419 | + char zero; | |
| 420 | + seqFile.read(&zero, 1); | |
| 421 | + if (zero == 0) { | |
| 420 | 422 | s += 8; |
| 421 | 423 | extra += 8; |
| 422 | 424 | } |
| ... | ... | @@ -498,14 +500,13 @@ private: |
| 498 | 500 | // apparently the text in seq files is 16 bit characters (UTF-16?) |
| 499 | 501 | // since we don't really need the last byte, snad since it gets interpreted as |
| 500 | 502 | // a terminating char, let's just grab the first byte for storage |
| 501 | - char* readText(int bytes) | |
| 503 | + void readText(int bytes, char * buffer) | |
| 502 | 504 | { |
| 503 | - char *text = new char[bytes], *ret = new char[bytes/2]; | |
| 504 | - seqFile.read(text, bytes); | |
| 505 | + seqFile.read(buffer, bytes); | |
| 505 | 506 | for (int i=0; i<bytes; i+=2) { |
| 506 | - ret[i/2] = text[i]; | |
| 507 | + buffer[i/2] = buffer[i]; | |
| 507 | 508 | } |
| 508 | - return ret; | |
| 509 | + buffer[bytes/2] = '\0'; | |
| 509 | 510 | } |
| 510 | 511 | |
| 511 | 512 | protected: | ... | ... |