Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
siox.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 Copyright 2005, 2006 by Gerald Friedland, Kristian Jantz and Lars Knipping
4
5 Conversion to C++ for Inkscape by Bob Jamison
6
7 Released under GNU GPL v2+, read the file 'COPYING' for more information.
8 */
9#include <cmath>
10#include <cstdarg>
11#include <unordered_map>
12#include <algorithm>
13#include <cstdlib>
14#include <cassert>
15
16#include "siox.h"
17#include "async/progress.h"
18
19namespace Inkscape {
20namespace Trace {
21
22//########################################################################
23//# S I O X I M A G E
24//########################################################################
25
26SioxImage::SioxImage(Glib::RefPtr<Gdk::Pixbuf> const &buf)
27{
28 width = buf->get_width();
29 height = buf->get_height();
30
31 // Allocate data arrays.
32 int size = width * height;
33 pixdata.resize(size);
34 cmdata.resize(size);
35
36 int rowstride = buf->get_rowstride();
37 int nchannels = buf->get_n_channels();
38 auto data = buf->get_pixels();
39
40 // Copy pixel data.
41 for (int y = 0; y < height; y++) {
42 auto p = data + rowstride * y;
43 for (int x = 0; x < width; x++) {
44 uint32_t r = p[0];
45 uint32_t g = p[1];
46 uint32_t b = p[2];
47 uint32_t a = nchannels == 3 ? 255 : p[3];
48 pixdata[offset(x, y)] = (a << 24) | (r << 16) | (g << 8) | b;
49 p += nchannels;
50 }
51 }
52
53 // Zero confidence matrix.
54 std::fill(cmdata.begin(), cmdata.end(), 0.0f);
55}
56
57Glib::RefPtr<Gdk::Pixbuf> SioxImage::getGdkPixbuf() const
58{
59 auto buf = Gdk::Pixbuf::create(Gdk::Colorspace::RGB, true, 8, width, height);
60
61 int rowstride = buf->get_rowstride();
62 int nchannels = buf->get_n_channels();
63 auto data = buf->get_pixels();
64
65 for (int y = 0; y < height; y++) {
66 auto p = data + rowstride * y;
67 for (int x = 0; x < width; x++) {
68 uint32_t rgb = pixdata[offset(x, y)];
69 p[0] = (rgb >> 16) & 0xff; // r
70 p[1] = (rgb >> 8) & 0xff; // g
71 p[2] = (rgb ) & 0xff; // b
72 p[3] = (rgb >> 24) & 0xff; // a
73 p += nchannels;
74 }
75 }
76
77 return buf;
78}
79
80bool SioxImage::writePPM(char const *filename) const
81{
82 auto f = std::fopen(filename, "wb");
83 if (!f) {
84 return false;
85 }
86
87 std::fprintf(f, "P6 %u %u 255\n", width, height);
88
89 for (int y = 0; y < height; y++) {
90 for (int x = 0; x < width; x++) {
91 uint32_t rgb = pixdata[offset(x, y)];
92 uint8_t r = (rgb >> 16) & 0xff;
93 uint8_t g = (rgb >> 8) & 0xff;
94 uint8_t b = (rgb ) & 0xff;
95 std::fputc(r, f);
96 std::fputc(g, f);
97 std::fputc(b, f);
98 }
99 }
100
101 std::fclose(f);
102
103 return true;
104}
105
106unsigned SioxImage::hash() const
107{
108 unsigned result = width * height;
109
110 for (int i = 0; i < width * height; i++) {
111 result = 3 * result + (unsigned)pixdata[i] + (unsigned)((1 << 16) * cmdata[i]);
112 }
113
114 return result;
115}
116
117//########################################################################
118//# S I O X
119//########################################################################
120
121namespace {
122
126template <typename F>
127void apply_adjacent(float *cm, int xres, int yres, F f)
128{
129 for (int y = 0; y < yres; y++) {
130 for (int x = 0; x < xres - 1; x++) {
131 int idx = y * xres + x;
132 f(cm[idx], cm[idx + 1]);
133 }
134 }
135 for (int y = 0; y < yres; y++) {
136 for (int x = xres - 1; x >= 1; x--) {
137 int idx = y * xres + x;
138 f(cm[idx], cm[idx - 1]);
139 }
140 }
141 for (int y = 0; y < yres - 1; y++) {
142 for (int x = 0; x < xres; x++) {
143 int idx = y * xres + x;
144 f(cm[idx], cm[idx + xres]);
145 }
146 }
147 for (int y = yres - 1; y >= 1; y--) {
148 for (int x = 0; x < xres; x++) {
149 int idx = y * xres + x;
150 f(cm[idx], cm[idx - xres]);
151 }
152 }
153}
154
160void dilate(float *cm, int xres, int yres)
161{
162 apply_adjacent(cm, xres, yres, [] (float &a, float b) {
163 if (b > a) {
164 a = b;
165 }
166 });
167}
168
172void erode(float *cm, int xres, int yres)
173{
174 apply_adjacent(cm, xres, yres, [] (float &a, float b) {
175 if (b < a) {
176 a = b;
177 }
178 });
179}
180
184void premultiplyMatrix(float alpha, float *cm, int cmSize)
185{
186 for (int i = 0; i < cmSize; i++) {
187 cm[i] *= alpha;
188 }
189}
190
194void normalizeMatrix(float *cm, int cmSize)
195{
196 float max = 0.0f;
197 for (int i = 0; i < cmSize; i++) {
198 if (cm[i] > max) {
199 max = cm[i];
200 }
201 }
202
203 if (max <= 0.0f || max == 1.0f) {
204 return;
205 }
206
207 float alpha = 1.0f / max;
208 premultiplyMatrix(alpha, cm, cmSize);
209}
210
217void smooth(float *cm, int xres, int yres, float f1, float f2, float f3)
218{
219 for (int y = 0; y < yres; y++) {
220 for (int x = 0; x < xres - 2; x++) {
221 int idx = y * xres + x;
222 cm[idx] = f1 * cm[idx] + f2 * cm[idx + 1] + f3 * cm[idx + 2];
223 }
224 }
225 for (int y = 0; y < yres; y++) {
226 for (int x = xres - 1; x >= 2; x--) {
227 int idx = y * xres + x;
228 cm[idx] = f3 * cm[idx - 2] + f2 * cm[idx - 1] + f1 * cm[idx];
229 }
230 }
231 for (int y = 0; y < yres - 2; y++) {
232 for (int x = 0; x < xres; x++) {
233 int idx = y * xres + x;
234 cm[idx] = f1 * cm[idx] + f2 * cm[((y + 1) * xres) + x] + f3 * cm[((y + 2) * xres) + x];
235 }
236 }
237 for (int y = yres - 1; y >= 2; y--) {
238 for (int x = 0; x < xres; x++) {
239 int idx = y * xres + x;
240 cm[idx] = f3 * cm[((y - 2) * xres) + x] + f2 * cm[((y - 1) * xres) + x] + f1 * cm[idx];
241 }
242 }
243}
244
248float sqrEuclideanDist(float *p, int pSize, float *q)
249{
250 float sum = 0.0;
251 for (int i = 0; i < pSize; i++) {
252 float v = p[i] - q[i];
253 sum += v * v;
254 }
255 return sum;
256}
257
258} // namespace
259
261 : progress(&progress)
262 , width(0)
263 , height(0)
264 , pixelCount(0)
265 , image(nullptr)
266 , cm(nullptr) {}
267
268void Siox::error(std::string const &msg)
269{
270 g_warning("Siox error: %s\n", msg.c_str());
271}
272
273void Siox::trace(std::string const &msg)
274{
275 g_message("Siox: %s\n", msg.c_str());
276}
277
278SioxImage Siox::extractForeground(SioxImage const &originalImage, uint32_t backgroundFillColor)
279{
280 trace("### Start");
281
282 init();
283
284 SioxImage workImage = originalImage;
285
286 // Fetch some info from the image.
287 width = workImage.getWidth();
288 height = workImage.getHeight();
290 image = workImage.getImageData();
291 cm = workImage.getConfidenceData();
292
293 // Create labelField.
294 auto labelField_storage = std::make_unique<int[]>(pixelCount);
295 labelField = labelField_storage.get();
296
297 trace("### Creating signatures");
298
299 // Create color signatures.
300 std::vector<CieLab> knownBg, knownFg;
301 auto imageClab = std::make_unique<CieLab[]>(pixelCount);
302 for (int i = 0; i < pixelCount; i++) {
303 float conf = cm[i];
304 uint32_t pix = image[i];
305 CieLab lab = pix;
306 imageClab[i] = lab;
307 if (conf <= BACKGROUND_CONFIDENCE) {
308 knownBg.emplace_back(lab);
309 } else if (conf >= FOREGROUND_CONFIDENCE) {
310 knownFg.emplace_back(lab);
311 }
312 }
313
315
316 trace("knownBg:" + std::to_string(knownBg.size()) + " knownFg:" + std::to_string(knownFg.size()));
317
318 std::vector<CieLab> bgSignature;
319 colorSignature(knownBg, bgSignature, 3);
320
322
323 std::vector<CieLab> fgSignature;
324 colorSignature(knownFg, fgSignature, 3);
325
326 // trace("### bgSignature:" + std::to_string(bgSignature.size()));
327
328 if (bgSignature.empty()) {
329 // segmentation impossible
330 error("Signature size is < 1. Segmentation is impossible");
331 throw Exception();
332 }
333
335
336 // classify using color signatures,
337 // classification cached in hashmap for drb and speedup purposes
338 trace("### Analyzing image");
339
340 std::unordered_map<uint32_t, bool> hs;
341
342 int progressResolution = pixelCount / 10;
343
344 for (int i = 0; i < pixelCount; i++) {
345 if (i % progressResolution == 0) {
346 progress->report_or_throw(0.3 + 0.6 * i / pixelCount);
347 }
348
349 if (cm[i] >= FOREGROUND_CONFIDENCE) {
351 } else if (cm[i] <= BACKGROUND_CONFIDENCE) {
353 } else { // somewhere in between
354 auto [it, inserted] = hs.emplace(image[i], false);
355 if (inserted) {
356 auto const &lab = imageClab[i];
357
358 float minBg = std::numeric_limits<float>::max();
359 for (auto const &s : bgSignature) {
360 minBg = std::min(minBg, CieLab::diffSq(lab, s));
361 }
362
363 float minFg;
364 if (fgSignature.empty()) {
365 minFg = clusterSize;
366 } else {
367 minFg = std::numeric_limits<float>::max();
368 for (auto const &s : fgSignature) {
369 minFg = std::min(minFg, CieLab::diffSq(lab, s));
370 }
371 }
372
373 it->second = minBg < minFg;
374 }
375
376 bool isBackground = it->second;
378 }
379 }
380
381 hs.clear();
382 imageClab.reset();
383
384 trace("### postProcessing");
385
386 // Postprocessing
387 smooth(cm, width, height, 0.333f, 0.333f, 0.333f); // average
388 normalizeMatrix(cm, pixelCount);
389 erode(cm, width, height);
390 keepOnlyLargeComponents(UNKNOWN_REGION_CONFIDENCE, 1.0/*sizeFactorToKeep*/);
391
392 // for (int i = 0; i < 2/*smoothness*/; i++)
393 // smooth(cm, width, height, 0.333f, 0.333f, 0.333f); // average
394
395 normalizeMatrix(cm, pixelCount);
396
397 for (int i = 0; i < pixelCount; i++) {
401 }
402
403 keepOnlyLargeComponents(UNKNOWN_REGION_CONFIDENCE, 1.5/*sizeFactorToKeep*/);
405 dilate(cm, width, height);
406
408
409 // We are done. Now clear everything but the background.
410 for (int i = 0; i < pixelCount; i++) {
411 if (cm[i] < FOREGROUND_CONFIDENCE) {
412 image[i] = backgroundFillColor;
413 }
414 }
415
416 trace("### Done");
417 return workImage;
418}
419
421{
422 limits[0] = 0.64f;
423 limits[1] = 1.28f;
424 limits[2] = 2.56f;
425
426 float negLimits[3];
427 negLimits[0] = -limits[0];
428 negLimits[1] = -limits[1];
429 negLimits[2] = -limits[2];
430
431 clusterSize = sqrEuclideanDist(limits, 3, negLimits);
432}
433
435 unsigned leftBase,
436 unsigned rightBase,
437 unsigned recursionDepth,
438 unsigned *clusterCount,
439 unsigned dims)
440{
441 unsigned currentDim = recursionDepth % dims;
442 CieLab point = points[leftBase];
443 float min = point(currentDim);
444 float max = min;
445
446 for (unsigned i = leftBase + 1; i < rightBase; i++) {
447 point = points[i];
448 float curval = point(currentDim);
449 if (curval < min) min = curval;
450 if (curval > max) max = curval;
451 }
452
453 // Do the Rubner-rule split (sounds like a dance)
454 if (max - min > limits[currentDim]) {
455 float pivotPoint = (min + max) / 2.0; // average
456 unsigned left = leftBase;
457 unsigned right = rightBase - 1;
458
459 // partition points according to the dimension
460 while (true) {
461 while (true) {
462 point = points[left];
463 if (point(currentDim) > pivotPoint) {
464 break;
465 }
466 left++;
467 }
468 while (true) {
469 point = points[right];
470 if (point(currentDim) <= pivotPoint) {
471 break;
472 }
473 right--;
474 }
475
476 if (left > right) {
477 break;
478 }
479
480 point = points[left];
481 points[left] = points[right];
482 points[right] = point;
483
484 left++;
485 right--;
486 }
487
488 // Recurse and create sub-trees
489 colorSignatureStage1(points, leftBase, left, recursionDepth + 1, clusterCount, dims);
490 colorSignatureStage1(points, left, rightBase, recursionDepth + 1, clusterCount, dims);
491
492 } else {
493 // create a leaf
494 CieLab newpoint;
495
496 newpoint.C = rightBase - leftBase;
497
498 for (; leftBase < rightBase; leftBase++) {
499 newpoint.add(points[leftBase]);
500 }
501
502 // printf("clusters:%d\n", *clusters);
503
504 if (newpoint.C != 0) {
505 newpoint.mul(1.0f / newpoint.C);
506 }
507 points[*clusterCount] = newpoint;
508 (*clusterCount)++;
509 }
510}
511
513 unsigned leftBase,
514 unsigned rightBase,
515 unsigned recursionDepth,
516 unsigned *clusterCount,
517 float threshold,
518 unsigned dims)
519{
520 unsigned currentDim = recursionDepth % dims;
521 CieLab point = points[leftBase];
522 float min = point(currentDim);
523 float max = min;
524
525 for (unsigned i = leftBase+ 1; i < rightBase; i++) {
526 point = points[i];
527 float curval = point(currentDim);
528 if (curval < min) min = curval;
529 if (curval > max) max = curval;
530 }
531
532 // Do the Rubner-rule split (sounds like a dance)
533 if (max - min > limits[currentDim]) {
534 float pivotPoint = (min + max) / 2.0; //average
535 unsigned left = leftBase;
536 unsigned right = rightBase - 1;
537
538 // partition points according to the dimension
539 while (true) {
540 while (true) {
541 point = points[left];
542 if (point(currentDim) > pivotPoint) {
543 break;
544 }
545 left++;
546 }
547 while (true) {
548 point = points[right];
549 if (point(currentDim) <= pivotPoint) {
550 break;
551 }
552 right--;
553 }
554
555 if (left > right) {
556 break;
557 }
558
559 point = points[left];
560 points[left] = points[right];
561 points[right] = point;
562
563 left++;
564 right--;
565 }
566
567 //# Recurse and create sub-trees
568 colorSignatureStage2(points, leftBase, left, recursionDepth + 1, clusterCount, threshold, dims);
569 colorSignatureStage2(points, left, rightBase, recursionDepth + 1, clusterCount, threshold, dims);
570
571 } else {
572 //### Create a leaf
573 unsigned sum = 0;
574 for (unsigned i = leftBase; i < rightBase; i++) {
575 sum += points[i].C;
576 }
577
578 if (sum >= threshold) {
579 float scale = rightBase - leftBase;
580 CieLab newpoint;
581
582 for (; leftBase < rightBase; leftBase++) {
583 newpoint.add(points[leftBase]);
584 }
585
586 if (scale != 0.0) {
587 newpoint.mul(1.0 / scale);
588 }
589 points[*clusterCount] = newpoint;
590 (*clusterCount)++;
591 }
592 }
593}
594
595void Siox::colorSignature(std::vector<CieLab> const &inputVec,
596 std::vector<CieLab> &result,
597 unsigned dims)
598{
599 if (inputVec.empty()) { // no error. just don't do anything
600 return;
601 }
602
603 unsigned length = inputVec.size();
604 result = inputVec;
605
606 unsigned stage1length = 0;
607 colorSignatureStage1(result.data(), 0, length, 0, &stage1length, dims);
608
609 unsigned stage2length = 0;
610 colorSignatureStage2(result.data(), 0, stage1length, 0, &stage2length, length * 0.001, dims);
611
612 result.resize(stage2length);
613}
614
615void Siox::keepOnlyLargeComponents(float threshold, double sizeFactorToKeep)
616{
617 for (int idx = 0; idx < pixelCount; idx++) {
618 labelField[idx] = -1;
619 }
620
621 int curlabel = 0;
622 int maxregion = 0;
623 int maxblob = 0;
624
625 // slow but easy to understand:
626 std::vector<int> labelSizes;
627 for (int i = 0; i < pixelCount; i++) {
628 int regionCount = 0;
629 if (labelField[i] == -1 && cm[i] >= threshold) {
630 regionCount = depthFirstSearch(i, threshold, curlabel++);
631 labelSizes.emplace_back(regionCount);
632 }
633
634 if (regionCount > maxregion) {
635 maxregion = regionCount;
636 maxblob = curlabel-1;
637 }
638 }
639
640 for (int i = 0; i < pixelCount; i++) {
641 if (labelField[i] != -1) {
642 // remove if the component is to small
643 if (labelSizes[labelField[i]] * sizeFactorToKeep < maxregion) {
645 }
646
647 // add maxblob always to foreground
648 if (labelField[i] == maxblob) {
650 }
651 }
652 }
653}
654
655int Siox::depthFirstSearch(int startPos, float threshold, int curLabel)
656{
657 // stores positions of labeled pixels, where the neighbours
658 // should still be checked for processing:
659
660 // trace("startPos:%d threshold:%f curLabel:%d",
661 // startPos, threshold, curLabel);
662
663 std::vector<int> pixelsToVisit;
664 int componentSize = 0;
665
666 if (labelField[startPos] == -1 && cm[startPos] >= threshold) {
667 labelField[startPos] = curLabel;
668 componentSize++;
669 pixelsToVisit.emplace_back(startPos);
670 }
671
672 while (!pixelsToVisit.empty()) {
673 int pos = pixelsToVisit[pixelsToVisit.size() - 1];
674 pixelsToVisit.erase(pixelsToVisit.end() - 1);
675 int x = pos % width;
676 int y = pos / width;
677
678 // check all four neighbours
679 int left = pos - 1;
680 if (x - 1 >= 0 && labelField[left] == -1 && cm[left] >= threshold) {
681 labelField[left] = curLabel;
682 componentSize++;
683 pixelsToVisit.emplace_back(left);
684 }
685
686 int right = pos + 1;
687 if (x + 1 < width && labelField[right] == -1 && cm[right] >= threshold) {
688 labelField[right] = curLabel;
689 componentSize++;
690 pixelsToVisit.emplace_back(right);
691 }
692
693 int top = pos - width;
694 if (y - 1 >= 0 && labelField[top] == -1 && cm[top] >= threshold) {
695 labelField[top] = curLabel;
696 componentSize++;
697 pixelsToVisit.emplace_back(top);
698 }
699
700 int bottom = pos + width;
701 if (y + 1 < height && labelField[bottom] == -1 && cm[bottom] >= threshold) {
702 labelField[bottom] = curLabel;
703 componentSize++;
704 pixelsToVisit.emplace_back(bottom);
705 }
706 }
707
708 return componentSize;
709}
710
712{
713 for (int idx = 0; idx < pixelCount; idx++) {
714 labelField[idx] = -1;
715 }
716
717 std::vector<int> pixelsToVisit;
718 for (int i = 0; i < pixelCount; i++) { // for all pixels
719 if (labelField[i] != -1 || cm[i] < UNKNOWN_REGION_CONFIDENCE) {
720 continue; // already visited or bg
721 }
722
723 uint32_t origColor = image[i];
724 int curLabel = i+1;
725 labelField[i] = curLabel;
727
728 // int componentSize = 1;
729 pixelsToVisit.emplace_back(i);
730 // depth first search to fill region
731 while (!pixelsToVisit.empty()) {
732 int pos = pixelsToVisit[pixelsToVisit.size() - 1];
733 pixelsToVisit.erase(pixelsToVisit.end() - 1);
734 int x = pos % width;
735 int y = pos / width;
736 // check all four neighbours
737 int left = pos - 1;
738 if (x - 1 >= 0 && labelField[left] == -1 && CieLab::diff(image[left], origColor) < 1.0) {
739 labelField[left] = curLabel;
741 // ++componentSize;
742 pixelsToVisit.emplace_back(left);
743 }
744 int right = pos + 1;
745 if (x + 1 < width && labelField[right] == -1 && CieLab::diff(image[right], origColor) < 1.0) {
746 labelField[right] = curLabel;
748 // ++componentSize;
749 pixelsToVisit.emplace_back(right);
750 }
751 int top = pos - width;
752 if (y - 1 >= 0 && labelField[top] == -1 && CieLab::diff(image[top], origColor) < 1.0) {
753 labelField[top] = curLabel;
755 // ++componentSize;
756 pixelsToVisit.emplace_back(top);
757 }
758 int bottom = pos + width;
759 if (y + 1 < height && labelField[bottom] == -1 && CieLab::diff(image[bottom], origColor) < 1.0) {
760 labelField[bottom] = curLabel;
762 // ++componentSize;
763 pixelsToVisit.emplace_back(bottom);
764 }
765 }
766 }
767}
768
769} // namespace Trace
770} // namespace Inkscape
double scale
Definition aa.cpp:228
An interface for tasks to report progress and check for cancellation.
Definition progress.h:23
void report_or_throw(T const &... progress)
Report a progress value, throwing CancelledException if cancelled.
Definition progress.h:29
void add(CieLab const &other)
Definition cielab.h:67
void mul(float scale)
Definition cielab.h:75
static float diff(CieLab const &c1, CieLab const &c2)
Computes euclidean distance in CieLab space between two colors.
Definition cielab.cpp:210
static float diffSq(CieLab const &c1, CieLab const &c2)
Squared Euclidean distance between two colors in CieLab space.
Definition cielab.cpp:203
SioxImage is the input/output format of Siox.
Definition siox.h:38
SioxImage(Glib::RefPtr< Gdk::Pixbuf > const &buf)
Create an image from a Gdk::Pixbuf.
Definition siox.cpp:26
std::vector< float > cmdata
Confidence matrix data.
Definition siox.h:92
uint32_t * getImageData()
Return the image data buffer.
Definition siox.h:54
std::vector< uint32_t > pixdata
Pixel data.
Definition siox.h:91
float * getConfidenceData()
Return the confidence data buffer.
Definition siox.h:65
int getWidth() const
Return the width of this image.
Definition siox.h:71
bool writePPM(char const *filename) const
Save this image as a simple color PPM.
Definition siox.cpp:80
int getHeight() const
Return the height of this image.
Definition siox.h:76
int width
Width of the image.
Definition siox.h:89
int height
Height of the image.
Definition siox.h:90
Glib::RefPtr< Gdk::Pixbuf > getGdkPixbuf() const
Create a Gdk::Pixbuf from this image.
Definition siox.cpp:57
unsigned hash() const
Return an extremely naive but fast hash of the image/confidence map contents.
Definition siox.cpp:106
float * cm
Working image confidence matrix.
Definition siox.h:148
void trace(std::string const &str)
Trace logging.
Definition siox.cpp:273
Async::Progress< double > * progress
Definition siox.h:142
int * labelField
Markup for image editing.
Definition siox.h:153
int height
Height of the image.
Definition siox.h:145
static constexpr float UNKNOWN_REGION_CONFIDENCE
Confidence for foreground or background type being equally likely.
Definition siox.h:116
void error(std::string const &str)
Error logging.
Definition siox.cpp:268
SioxImage extractForeground(SioxImage const &originalImage, uint32_t backgroundFillColor)
Extract the foreground of the original image, according to the values in the confidence matrix.
Definition siox.cpp:278
int pixelCount
Number of pixels in the image.
Definition siox.h:146
float limits[3]
Our signature limits.
Definition siox.h:158
Siox(Async::Progress< double > &progress)
Definition siox.cpp:260
void colorSignatureStage2(CieLab *points, unsigned leftBase, unsigned rightBase, unsigned recursionDepth, unsigned *clusters, float threshold, unsigned dims)
Stage 2 of the color signature work.
Definition siox.cpp:512
float clusterSize
Maximum distance of two lab values.
Definition siox.h:163
static constexpr float FOREGROUND_CONFIDENCE
Confidence for a region likely being foreground.
Definition siox.h:111
static constexpr float BACKGROUND_CONFIDENCE
Confidence for a region likely being background.
Definition siox.h:121
int depthFirstSearch(int startPos, float threshold, int curLabel)
Definition siox.cpp:655
void colorSignatureStage1(CieLab *points, unsigned leftBase, unsigned rightBase, unsigned recursionDepth, unsigned *clusters, unsigned dims)
Stage 1 of the color signature work.
Definition siox.cpp:434
void keepOnlyLargeComponents(float threshold, double sizeFactorToKeep)
Definition siox.cpp:615
void init()
Initialize the Siox engine to its 'pristine' state.
Definition siox.cpp:420
static constexpr float CERTAIN_FOREGROUND_CONFIDENCE
Confidence corresponding to a certain foreground region (equals one).
Definition siox.h:106
static constexpr float CERTAIN_BACKGROUND_CONFIDENCE
Confidence corresponding to a certain background reagion (equals zero).
Definition siox.h:126
int width
Width of the image.
Definition siox.h:144
void colorSignature(std::vector< CieLab > const &inputVec, std::vector< CieLab > &result, unsigned dims)
Main color signature method.
Definition siox.cpp:595
uint32_t * image
Working image data.
Definition siox.h:147
void fillColorRegions()
Definition siox.cpp:711
Css & result
Glib::ustring msg
std::unique_ptr< Magick::Image > image
double offset
size_t v
MultiDegree< n > max(MultiDegree< n > const &p, MultiDegree< n > const &q)
Returns the maximal degree appearing in the two arguments for each variables.
Definition sbasisN.h:158
Helper class to stream background task notifications as a series of messages.
int buf
RGB rgb
Definition quantize.cpp:36
double sum(const double alpha[16], const double &x, const double &y)
static const Point data[]
double height
double width
Glib::RefPtr< Gtk::Adjustment > smooth