summaryrefslogtreecommitdiffstats
path: root/src/trace/siox.h
blob: 55d0ce422cb4e65c9ef4e51f641a16446585a65e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
// SPDX-License-Identifier: GPL-2.0-or-later
#ifndef INKSCAPE_TRACE_SIOX_H
#define INKSCAPE_TRACE_SIOX_H
/*
 *  Copyright 2005, 2006 by Gerald Friedland, Kristian Jantz and Lars Knipping
 *
 *  Conversion to C++ for Inkscape by Bob Jamison
 *
 *  Released under GNU GPL v2+, read the file 'COPYING' for more information.
 */

/*
 * Note by Bob Jamison:
 * After translating the siox.org Java API to C++ and receiving an
 * education into this wonderful code, I began again,
 * and started this version using lessons learned. This version is
 * an attempt to provide an dependency-free SIOX engine that anyone
 * can use in their project with minimal effort.
 *
 * Many thanks to the fine people at siox.org.
 */

#include <string>
#include <vector>
#include <gdkmm/pixbuf.h>
#include <glib.h>
#include "cielab.h"

namespace Inkscape {
namespace Async { template <typename... T> class Progress; }
namespace Trace {

/**
 * SioxImage is the input/output format of Siox.
 * It pairs a 32-bit image with an equally-sized matrix of floats representing foreground confidence values.
 */
class SioxImage
{
public:
    /**
     * Create an image from a Gdk::Pixbuf.
     * A copy of the pixbuf is set as the pixel data, while the confidence matrix is initialized to zero.
     */
    SioxImage(Glib::RefPtr<Gdk::Pixbuf> const &buf);

    /**
     * Create a Gdk::Pixbuf from this image.
     */
    Glib::RefPtr<Gdk::Pixbuf> getGdkPixbuf() const;

    /**
     * Return the image data buffer.
     */
    uint32_t *getImageData() { return pixdata.data(); }
    uint32_t const *getImageData() const { return pixdata.data(); }

    /**
     * Set a confidence value at the x, y coordinates to the given value.
     */
    void setConfidence(int x, int y, float conf) { cmdata[offset(x, y)] = conf; }

    /**
     * Return the confidence data buffer.
     */
    float *getConfidenceData() { return cmdata.data(); }
    float const *getConfidenceData() const { return cmdata.data(); }

    /**
     * Return the width of this image
     */
    int getWidth() const { return width; }

    /**
     * Return the height of this image
     */
    int getHeight() const { return height; }

    /**
     * Save this image as a simple color PPM
     */
    bool writePPM(char const *filename) const;

    /**
     * Return an extremely naive but fast hash of the image/confidence map contents.
     */
    unsigned hash() const;

private:
    int width;                     ///< Width of the image
    int height;                    ///< Height of the image
    std::vector<uint32_t> pixdata; ///< Pixel data
    std::vector<float> cmdata;     ///< Confidence matrix data

    /**
     * Return the offset of a given pixel within both data arrays.
     */
    int constexpr offset(int x, int y) const { return width * y + x; }
};

class Siox
{
public:
    /**
     * Confidence corresponding to a certain foreground region (equals one).
     */
    static constexpr float CERTAIN_FOREGROUND_CONFIDENCE = 1.0f;

    /**
     * Confidence for a region likely being foreground.
     */
    static constexpr float FOREGROUND_CONFIDENCE = 0.8f;

    /**
     * Confidence for foreground or background type being equally likely.
     */
    static constexpr float UNKNOWN_REGION_CONFIDENCE = 0.5f;

    /**
     * Confidence for a region likely being background.
     */
    static constexpr float BACKGROUND_CONFIDENCE = 0.1f;

    /**
     * Confidence corresponding to a certain background reagion (equals zero).
     */
    static constexpr float CERTAIN_BACKGROUND_CONFIDENCE = 0.0f;

    Siox(Async::Progress<double> &progress);

    /**
     * Extract the foreground of the original image, according to the values in the confidence matrix.
     * If the operation fails or is aborted, an exception is thrown.
     * \param backgroundFillColor Any ARGB color, such as 0xffffff (white) or 0x000000 (black).
     * \throws Siox::Exception on error.
     * \throws Async::CancelledException on cancellation.
     */
    SioxImage extractForeground(SioxImage const &originalImage, uint32_t backgroundFillColor);

    class Exception {};

private:
    Async::Progress<double> *progress;

    int width;       ///< Width of the image
    int height;      ///< Height of the image
    int pixelCount;  ///< Number of pixels in the image
    uint32_t *image; ///< Working image data
    float *cm;       ///< Working image confidence matrix

    /**
     * Markup for image editing
     */
    int *labelField;

    /**
     * Our signature limits
     */
    float limits[3];

    /**
     * Maximum distance of two lab values.
     */
    float clusterSize;

    /**
     * Initialize the Siox engine to its 'pristine' state.
     * Performed at the beginning of extractForeground().
     */
    void init();

    /**
     * Error logging
     */
    void error(std::string const &str);

    /**
     * Trace logging
     */
    void trace(std::string const &str);

    /**
     * Stage 1 of the color signature work. 'dims' will be either 2 for grays, or 3 for colors.
     */
    void colorSignatureStage1(CieLab *points,
                              unsigned leftBase,
                              unsigned rightBase,
                              unsigned recursionDepth,
                              unsigned *clusters,
                              unsigned dims);

    /**
     * Stage 2 of the color signature work
     */
    void colorSignatureStage2(CieLab *points,
                              unsigned leftBase,
                              unsigned rightBase,
                              unsigned recursionDepth,
                              unsigned *clusters,
                              float    threshold,
                              unsigned dims);

    /**
     * Main color signature method
     */
    void colorSignature(std::vector<CieLab> const &inputVec,
                        std::vector<CieLab> &result,
                        unsigned dims);

    void keepOnlyLargeComponents(float threshold, double sizeFactorToKeep);

    int depthFirstSearch(int startPos, float threshold, int curLabel);

    void fillColorRegions();
};

} // namespace Trace
} // namespace Inkscape

#endif // INKSCAPE_TRACE_SIOX_H