Commit 1ed68d6d110c1d0befd8da1a4e4cf7b4bf129381

Authored by Scott Klum
2 parents 5e6b30e9 9d711fd6

Merge branch 'master' of https://github.com/biometrics/openbr

openbr/CMakeLists.txt
@@ -34,7 +34,7 @@ set(JANUS_BUILD_PP5_WRAPPER ${BR_WITH_PP5} CACHE BOOL "Build Janus implementatio @@ -34,7 +34,7 @@ set(JANUS_BUILD_PP5_WRAPPER ${BR_WITH_PP5} CACHE BOOL "Build Janus implementatio
34 set(JANUS_BUILD_DOCS ${BR_BUILD_DOCUMENTATION} CACHE BOOL "Build Janus HTML Doxygen documentation") 34 set(JANUS_BUILD_DOCS ${BR_BUILD_DOCUMENTATION} CACHE BOOL "Build Janus HTML Doxygen documentation")
35 mark_as_advanced(JANUS_BUILD_PP5_WRAPPER) 35 mark_as_advanced(JANUS_BUILD_PP5_WRAPPER)
36 mark_as_advanced(JANUS_BUILD_DOCS) 36 mark_as_advanced(JANUS_BUILD_DOCS)
37 -set(JANUS_TEST_IMPLEMENTATION openbr) 37 +set(JANUS_IMPLEMENTATION openbr)
38 add_subdirectory(janus) 38 add_subdirectory(janus)
39 39
40 # Install 40 # Install
openbr/core/bee.cpp
@@ -172,6 +172,8 @@ Mat BEE::readMat(const br::File &matrix, QString *targetSigset, QString *querySi @@ -172,6 +172,8 @@ Mat BEE::readMat(const br::File &matrix, QString *targetSigset, QString *querySi
172 qint64 read = file.read((char*)m.data, bytesExpected); 172 qint64 read = file.read((char*)m.data, bytesExpected);
173 if (read != bytesExpected) 173 if (read != bytesExpected)
174 qFatal("Invalid matrix size."); 174 qFatal("Invalid matrix size.");
  175 + if (!file.atEnd())
  176 + qFatal("Expected matrix end of file.");
175 file.close(); 177 file.close();
176 178
177 Mat result; 179 Mat result;
1 -Subproject commit 0eaa00f19256fee2f24033ff68b526ea6320624d 1 +Subproject commit 02fd545b2dbb8ea2ba10dbf67e429da598545d75
openbr/janus.cpp
@@ -3,140 +3,138 @@ @@ -3,140 +3,138 @@
3 #endif 3 #endif
4 4
5 #include "janus.h" 5 #include "janus.h"
  6 +#include "janus_io.h"
6 #include "openbr_plugin.h" 7 #include "openbr_plugin.h"
7 8
8 -// Use the provided default implementation of some functions  
9 -#include "janus/src/janus.cpp"  
10 -  
11 using namespace br; 9 using namespace br;
12 10
13 static QSharedPointer<Transform> transform; 11 static QSharedPointer<Transform> transform;
14 static QSharedPointer<Distance> distance; 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 janus_error janus_initialize(const char *sdk_path, const char *model_file) 19 janus_error janus_initialize(const char *sdk_path, const char *model_file)
17 { 20 {
18 int argc = 1; 21 int argc = 1;
19 const char *argv[1] = { "janus" }; 22 const char *argv[1] = { "janus" };
20 Context::initialize(argc, (char**)argv, sdk_path); 23 Context::initialize(argc, (char**)argv, sdk_path);
21 QString algorithm = model_file; 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 return JANUS_SUCCESS; 35 return JANUS_SUCCESS;
26 } 36 }
27 37
28 janus_error janus_finalize() 38 janus_error janus_finalize()
29 { 39 {
  40 + transform.reset();
  41 + distance.reset();
30 Context::finalize(); 42 Context::finalize();
31 return JANUS_SUCCESS; 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 return JANUS_SUCCESS; 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 Template t; 57 Template t;
48 t.append(cv::Mat(image.height, 58 t.append(cv::Mat(image.height,
49 image.width, 59 image.width,
50 - image.color_space == JANUS_GRAY8 ? CV_8UC1 : CV_8UC1, 60 + image.color_space == JANUS_GRAY8 ? CV_8UC1 : CV_8UC3,
51 image.data)); 61 image.data));
52 for (size_t i=0; i<attributes.size; i++) 62 for (size_t i=0; i<attributes.size; i++)
53 t.file.set(janus_attribute_to_string(attributes.attributes[i]), attributes.values[i]); 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 return JANUS_SUCCESS; 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 Template u; 73 Template u;
64 transform->project(t, u); 74 transform->project(t, u);
65 - incomplete_template->data.append(u); 75 + template_->append(u);
66 return JANUS_SUCCESS; 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 assert(m.isContinuous()); 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 break; 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 return JANUS_SUCCESS; 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 return JANUS_SUCCESS; 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 return JANUS_SUCCESS; 139 return JANUS_SUCCESS;
142 } 140 }
openbr/openbr.cpp
@@ -383,7 +383,9 @@ bool br_img_is_empty(br_template tmpl) @@ -383,7 +383,9 @@ bool br_img_is_empty(br_template tmpl)
383 const char* br_get_filename(br_template tmpl) 383 const char* br_get_filename(br_template tmpl)
384 { 384 {
385 Template *t = reinterpret_cast<Template*>(tmpl); 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 void br_set_filename(br_template tmpl, const char *filename) 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 &amp;inputGalleries, const QString &amp;outputGalle @@ -1374,7 +1374,7 @@ BR_EXPORT void Cat(const QStringList &amp;inputGalleries, const QString &amp;outputGalle
1374 1374
1375 /*! 1375 /*!
1376 * \brief Deduplicate a gallery. 1376 * \brief Deduplicate a gallery.
1377 - * \param inputGalleries Gallery to deduplicate. 1377 + * \param inputGallery Gallery to deduplicate.
1378 * \param outputGallery Gallery to store the deduplicated result. 1378 * \param outputGallery Gallery to store the deduplicated result.
1379 * \param threshold Match score threshold to determine duplicates. 1379 * \param threshold Match score threshold to determine duplicates.
1380 */ 1380 */
openbr/plugins/algorithms.cpp
@@ -52,6 +52,7 @@ class AlgorithmsInitializer : public Initializer @@ -52,6 +52,7 @@ class AlgorithmsInitializer : public Initializer
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)"); 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 Globals->abbreviations.insert("ShowOpticalFlowField", "Stream(SaveMat(original)+AggregateFrames(2)+OpticalFlow(useMagnitude=false)+Grid(100,100)+DrawOpticalFlow+FPSLimit(30)+Show(false)+Discard)"); 53 Globals->abbreviations.insert("ShowOpticalFlowField", "Stream(SaveMat(original)+AggregateFrames(2)+OpticalFlow(useMagnitude=false)+Grid(100,100)+DrawOpticalFlow+FPSLimit(30)+Show(false)+Discard)");
54 Globals->abbreviations.insert("ShowOpticalFlowMagnitude", "Stream(AggregateFrames(2)+OpticalFlow+Normalize(Range,false,0,255)+Cvt(Color)+Draw+FPSLimit(30)+Show(false)+Discard)"); 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 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 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 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)"); 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,7 +79,7 @@ class AlgorithmsInitializer : public Initializer
78 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 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 // Transforms 81 // Transforms
81 - Globals->abbreviations.insert("FaceDetection", "(Open+Cvt(Gray)+Cascade(FrontalFace))"); 82 + Globals->abbreviations.insert("FaceDetection", "Open+Cvt(Gray)+Cascade(FrontalFace)");
82 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 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 Globals->abbreviations.insert("DenseSIFT", "(Grid(10,10)+SIFTDescriptor(12)+ByRow)"); 84 Globals->abbreviations.insert("DenseSIFT", "(Grid(10,10)+SIFTDescriptor(12)+ByRow)");
84 Globals->abbreviations.insert("FaceRecognitionRegistration", "(ASEFEyes+Affine(88,88,0.25,0.35)+DownsampleTraining(FTE(DFFS),instances=1))"); 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,6 +374,56 @@ class DrawOpticalFlow : public UntrainableTransform
374 }; 374 };
375 BR_REGISTER(Transform, DrawOpticalFlow) 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 // TODO: re-implement EditTransform using Qt 427 // TODO: re-implement EditTransform using Qt
378 #if 0 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,10 +347,11 @@ public:
347 } 347 }
348 348
349 // first 4 bytes store 0xEDFE, next 24 store 'Norpix seq ' 349 // first 4 bytes store 0xEDFE, next 24 store 'Norpix seq '
350 - char *firstFour = new char[4], *nextTwentyFour; 350 + char firstFour[4];
351 seqFile.seekg(0, ios::beg); 351 seqFile.seekg(0, ios::beg);
352 seqFile.read(firstFour, 4); 352 seqFile.read(firstFour, 4);
353 - nextTwentyFour = readText(24); 353 + char nextTwentyFour[24];
  354 + readText(24, nextTwentyFour);
354 if (firstFour[0] != (char)0xED || firstFour[1] != (char)0xFE || strncmp(nextTwentyFour, "Norpix seq", 10) != 0) { 355 if (firstFour[0] != (char)0xED || firstFour[1] != (char)0xFE || strncmp(nextTwentyFour, "Norpix seq", 10) != 0) {
355 qDebug("Invalid header in seq file"); 356 qDebug("Invalid header in seq file");
356 return false; 357 return false;
@@ -363,7 +364,8 @@ public: @@ -363,7 +364,8 @@ public:
363 qDebug("Invalid header size"); 364 qDebug("Invalid header size");
364 return false; 365 return false;
365 } 366 }
366 - char *desc = readText(512); 367 + char desc[512];
  368 + readText(512, desc);
367 basis.file.set("Description", QString(desc)); 369 basis.file.set("Description", QString(desc));
368 370
369 width = readInt(); 371 width = readInt();
@@ -414,9 +416,9 @@ public: @@ -414,9 +416,9 @@ public:
414 // but there might be 16 extra bytes instead of 8... 416 // but there might be 16 extra bytes instead of 8...
415 if (i == 1) { 417 if (i == 1) {
416 seqFile.seekg(s, ios::beg); 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 s += 8; 422 s += 8;
421 extra += 8; 423 extra += 8;
422 } 424 }
@@ -498,14 +500,13 @@ private: @@ -498,14 +500,13 @@ private:
498 // apparently the text in seq files is 16 bit characters (UTF-16?) 500 // apparently the text in seq files is 16 bit characters (UTF-16?)
499 // since we don't really need the last byte, snad since it gets interpreted as 501 // since we don't really need the last byte, snad since it gets interpreted as
500 // a terminating char, let's just grab the first byte for storage 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 for (int i=0; i<bytes; i+=2) { 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 protected: 512 protected: