Img2Num C++ (Internal Developer Docs) dev
API Documentation
Loading...
Searching...
No Matches
img2num Namespace Reference

Classes

struct  ImageToSvgConfig
 Configuration options for image_to_svg. More...
 

Enumerations

enum class  Error {
  OK = 0 , BAD_ALLOC = 1 , INVALID_ARGUMENT = 2 , RUNTIME = 3 ,
  UNKNOWN = 4
}
 

Functions

void gaussian_blur_fft (uint8_t *image, size_t width, size_t height, double sigma)
 Apply a Gaussian blur to an image using FFT.
 
void invert_image (uint8_t *ptr, int width, int height)
 Invert the pixel values of an image.
 
void threshold_image (uint8_t *ptr, const int width, const int height, const int num_thresholds)
 Apply a thresholding operation to an image.
 
void black_threshold_image (uint8_t *ptr, const int width, const int height, const int num_thresholds)
 Apply black-thresholding to an image.
 
void kmeans (const uint8_t *data, uint8_t *out_data, int32_t *out_labels, const int32_t width, const int32_t height, const int32_t k, const int32_t max_iter, const uint8_t color_space)
 Perform k-means clustering on image data.
 
void bilateral_filter (uint8_t *image, size_t width, size_t height, double sigma_spatial, double sigma_range, uint8_t color_space)
 Apply bilateral filtering to an image.
 
std::string labels_to_svg (const uint8_t *data, const int32_t *labels, const int width, const int height, const int min_area, const int min_thickness)
 Convert labeled regions of an image into an SVG string.
 
std::string image_to_svg (const uint8_t *data, const int width, const int height, const ImageToSvgConfig &config)
 Convert labeled regions of an image into an SVG string.
 
Error get_last_error ()
 
const std::string get_last_error_message ()
 
void clear_last_error ()
 
void set_error (Error code, const std::string message)
 
template<typename Func , typename... Args>
void clear_last_error_and_catch (Func &&exception_prone_func, Args &&... args)
 

Variables

thread_local Error last_error {Error::OK}
 
thread_local std::string last_error_message {}
 

Detailed Description

Note
All image buffers are assumed to be stored in row-major order, unless otherwise noted.

Enumeration Type Documentation

◆ Error

enum class img2num::Error
strong

Definition at line 8 of file Error.h.

8{ OK = 0, BAD_ALLOC = 1, INVALID_ARGUMENT = 2, RUNTIME = 3, UNKNOWN = 4 };

Function Documentation

◆ bilateral_filter()

void img2num::bilateral_filter ( uint8_t *  image,
size_t  width,
size_t  height,
double  sigma_spatial,
double  sigma_range,
uint8_t  color_space 
)

Apply bilateral filtering to an image.

Parameters
imagePointer to RGBA pixel buffer.
widthWidth of the image in pixels.
heightHeight of the image in pixels.
sigma_spatialStandard deviation for spatial Gaussian (proximity weight).
sigma_rangeStandard deviation for range Gaussian (intensity similarity weight).
color_spaceColor space flag (0 = CIE LAB, 1 = RGB).
Note
The filter modifies the image buffer in-place.
Dox File: doxygen/img2num.h.dox

Definition at line 230 of file bilateral_filter.cpp.

233 {
234 GPU::getClassInstance().init_gpu();
235
236 if (GPU::getClassInstance().is_initialized()) {
237 bilateral_filter_gpu(image, width, height, sigma_spatial, sigma_range, color_space);
238 } else {
239 bilateral_filter_cpu(image, width, height, sigma_spatial, sigma_range, color_space);
240 }
241}

Referenced by image_to_svg().

+ Here is the caller graph for this function:

◆ black_threshold_image()

void img2num::black_threshold_image ( uint8_t *  ptr,
const int  width,
const int  height,
const int  num_thresholds 
)

Apply black-thresholding to an image.

Parameters
ptrPointer to the image buffer.
widthWidth of the image in pixels.
heightHeight of the image in pixels.
num_thresholdsNumber of thresholds to apply.
Note
Similar to threshold_image but prioritizes darker pixels.
Dox File: doxygen/img2num.h.dox

Definition at line 139 of file image_utils.cpp.

141 {
142 if (num_thresholds <= 0) {
143 return;
144 }
146 img.loadFromBuffer(ptr, width, height, ImageLib::RGBA_CONVERTER<uint8_t>);
147
148 const auto imgWidth {img.getWidth()}, imgHeight {img.getHeight()};
149 for (ImageLib::RGBAPixel<uint8_t>& p : img) {
150 const bool R {p.red < num_thresholds};
151 const bool G {p.green < num_thresholds};
152 const bool B {p.blue < num_thresholds};
153 if (R && B && G) {
154 p.setGray(0);
155 }
156 }
157
158 const auto& modified = img.getData();
159 std::memcpy(ptr, modified.data(), modified.size() * sizeof(ImageLib::RGBAPixel<uint8_t>));
160}

◆ clear_last_error()

void img2num::clear_last_error ( )

Definition at line 7 of file Error.cpp.

7 {
8 last_error = Error::OK;
9 last_error_message.clear();
10}

◆ clear_last_error_and_catch()

template<typename Func , typename... Args>
void img2num::clear_last_error_and_catch ( Func &&  exception_prone_func,
Args &&...  args 
)

Definition at line 25 of file Error.h.

25 {
26 clear_last_error(); // Clear any previous error state
27 try {
28 exception_prone_func(std::forward<Args>(args)...); // Call the passed function
29 } catch (const std::bad_alloc& e) {
30 set_error(Error::BAD_ALLOC, e.what());
31 } catch (const std::invalid_argument& e) {
32 set_error(Error::INVALID_ARGUMENT, e.what());
33 } catch (const std::runtime_error& e) {
34 set_error(Error::RUNTIME, e.what());
35 } catch (const std::exception& e) {
36 set_error(Error::UNKNOWN, e.what());
37 } catch (...) {
38 set_error(Error::UNKNOWN, "Unknown exception occurred");
39 }
40}

◆ gaussian_blur_fft()

void img2num::gaussian_blur_fft ( uint8_t *  image,
size_t  width,
size_t  height,
double  sigma 
)

Apply a Gaussian blur to an image using FFT.

Parameters
imagePointer to the image buffer (RGBA).
widthWidth of the image in pixels.
heightHeight of the image in pixels.
sigmaStandard deviation for Gaussian kernel.
Note
The operation modifies the image buffer in-place.
Dox File: doxygen/img2num.h.dox

Definition at line 48 of file image_utils.cpp.

48 {
49 if (!image || width == 0 || height == 0 || sigma_pixels <= 0)
50 return;
51
52 const size_t Npix = width * height;
53
54 // Compute padded dimensions (next power of two)
55 const size_t W = fft::next_power_of_two(width);
56 const size_t H = fft::next_power_of_two(height);
57 const size_t Npix_padded = W * H;
58
59 // Frequency coordinates helper (DC at corner)
60 auto freq_coord = [](int k, int dim) -> double {
61 return (k <= dim / 2) ? double(k) / dim : double(k - dim) / dim;
62 };
63
64 // Precompute Gaussian factor in frequency domain
65 const double two_pi2_sigma2 = 2.0 * M_PI * M_PI * sigma_pixels * sigma_pixels;
66
67 for (int channel = 0; channel < 3; channel++) {
68 // Allocate padded buffer
69 std::vector<fft::cd> data(Npix_padded, {0.0, 0.0});
70
71 // Copy original image channel into padded buffer
72 for (size_t y = 0; y < height; y++)
73 for (size_t x = 0; x < width; x++)
74 data[y * W + x] = fft::cd(image[(y * width + x) * 4 + channel], 0.0);
75
76 // Forward 2D FFT
77 fft::iterative_fft_2d(data, W, H, false);
78
79 // Apply Gaussian filter in frequency domain
80 for (size_t y = 0; y < H; y++) {
81 double fy2 = freq_coord(y, H) * freq_coord(y, H);
82 for (size_t x = 0; x < W; x++) {
83 double fx2 = freq_coord(x, W) * freq_coord(x, W);
84 double gain = std::exp(-two_pi2_sigma2 * (fx2 + fy2));
85 data[y * W + x] *= gain;
86 }
87 }
88
89 // Inverse 2D FFT
90 fft::iterative_fft_2d(data, W, H, true);
91
92 // Copy back only the original width/height and clamp
93 for (size_t y = 0; y < height; y++)
94 for (size_t x = 0; x < width; x++) {
95 double v = data[y * W + x].real();
96 v = std::clamp(v, 0.0, 255.0);
97 image[(y * width + x) * 4 + channel] = static_cast<uint8_t>(std::lrint(v));
98 }
99 }
100
101 // Alpha channel remains unchanged
102}

◆ get_last_error()

Error img2num::get_last_error ( )
inline

Definition at line 13 of file Error.h.

13 {
14 return last_error;
15}

◆ get_last_error_message()

const std::string img2num::get_last_error_message ( )
inline

Definition at line 16 of file Error.h.

16 {
17 return last_error_message;
18}

◆ image_to_svg()

std::string img2num::image_to_svg ( const uint8_t *  data,
const int  width,
const int  height,
const ImageToSvgConfig config 
)

Convert labeled regions of an image into an SVG string.

Parameters
dataPointer to image data buffer.
widthWidth of the image in pixels.
heightHeight of the image in pixels.
configimg2num_ImageToSvgConfig Configuration Struct.

‍See img2num::ImageToSvgConfig.

Returns
std::string An SVG string containing data roughly approximate to the input image.
Note
Dox File: doxygen/img2num.h.dox

Definition at line 7 of file image_to_svg.cpp.

9 {
10 // self deallocate
11 std::vector<uint8_t> img_data(static_cast<size_t>(width) * static_cast<size_t>(height) * 4);
12 std::vector<uint8_t> out_data(static_cast<size_t>(width) * static_cast<size_t>(height) * 4);
13 std::vector<int32_t> out_labels(static_cast<size_t>(width) * static_cast<size_t>(height));
14
15 std::memcpy(
16 img_data.data(), data, static_cast<size_t>(width) * static_cast<size_t>(height) * 4
17 );
19 img_data.data(), width, height, config.bilateral_filter.sigma_spatial,
20 config.bilateral_filter.sigma_range, config.color_space
21 );
22 kmeans(
23 img_data.data(), out_data.data(), out_labels.data(), width, height, config.kmeans.k,
24 config.kmeans.max_iter, config.color_space
25 );
26 std::string svg {labels_to_svg(
27 data, out_labels.data(), width, height, config.min_cluster_area, config.min_thickness
28 )};
29
30 return svg;
31}
void bilateral_filter(uint8_t *image, size_t width, size_t height, double sigma_spatial, double sigma_range, uint8_t color_space)
Apply bilateral filtering to an image.
std::string labels_to_svg(const uint8_t *data, const int32_t *labels, const int width, const int height, const int min_area, const int min_thickness)
Convert labeled regions of an image into an SVG string.
void kmeans(const uint8_t *data, uint8_t *out_data, int32_t *out_labels, const int32_t width, const int32_t height, const int32_t k, const int32_t max_iter, const uint8_t color_space)
Perform k-means clustering on image data.
Definition kmeans.cpp:241
int min_cluster_area
Minimum area (in pixels) for a region to be included in the SVG.
Definition img2num.h:42

References bilateral_filter(), img2num::ImageToSvgConfig::color_space, img2num::ImageToSvgConfig::KMeansConfig::k, kmeans(), labels_to_svg(), img2num::ImageToSvgConfig::KMeansConfig::max_iter, img2num::ImageToSvgConfig::min_cluster_area, img2num::ImageToSvgConfig::min_thickness, img2num::ImageToSvgConfig::BilateralFilterConfig::sigma_range, and img2num::ImageToSvgConfig::BilateralFilterConfig::sigma_spatial.

+ Here is the call graph for this function:

◆ invert_image()

void img2num::invert_image ( uint8_t *  ptr,
int  width,
int  height 
)

Invert the pixel values of an image.

Parameters
ptrPointer to the image buffer.
widthWidth of the image in pixels.
heightHeight of the image in pixels.
Note
Each pixel value is replaced by 255 - original_value.
Dox File: doxygen/img2num.h.dox

Definition at line 105 of file image_utils.cpp.

105 {
107 img.loadFromBuffer(ptr, width, height, ImageLib::RGBA_CONVERTER<uint8_t>);
108
109 for (ImageLib::RGBAPixel<uint8_t>& p : img) {
110 p.red = 255 - p.red;
111 p.blue = 255 - p.blue;
112 p.green = 255 - p.green;
113 }
114
115 const auto& modified = img.getData();
116 std::memcpy(ptr, modified.data(), modified.size() * sizeof(ImageLib::RGBAPixel<uint8_t>));
117}

◆ kmeans()

void img2num::kmeans ( const uint8_t *  data,
uint8_t *  out_data,
int32_t *  out_labels,
const int32_t  width,
const int32_t  height,
const int32_t  k,
const int32_t  max_iter,
const uint8_t  color_space 
)

Perform k-means clustering on image data.

Parameters
dataPointer to input image data buffer.
out_dataPointer to output buffer where clustered pixel values are stored.
out_labelsPointer to output buffer for cluster labels per pixel.
widthWidth of the image in pixels.
heightHeight of the image in pixels.
kNumber of clusters to compute.
max_iterMaximum number of iterations for the algorithm.
color_spaceColor space flag (0 = CIE LAB, 1 = RGB).
Note
The function does not modify the input buffer.
Dox File: doxygen/img2num.h.dox

Definition at line 241 of file kmeans.cpp.

244 {
245 GPU::getClassInstance().init_gpu();
246
247 if (GPU::getClassInstance().is_initialized()) {
248 kmeans_gpu(data, out_data, out_labels, width, height, k, max_iter, color_space);
249 } else {
250 kmeans_cpu(data, out_data, out_labels, width, height, k, max_iter, color_space);
251 }
252}

Referenced by image_to_svg().

+ Here is the caller graph for this function:

◆ labels_to_svg()

std::string img2num::labels_to_svg ( const uint8_t *  data,
const int32_t *  labels,
const int  width,
const int  height,
const int  min_area,
const int  min_thickness = 0 
)

Convert labeled regions of an image into an SVG string.

Parameters
dataPointer to image data buffer.
labelsPointer to label buffer, indicating region for each pixel.
widthWidth of the image in pixels.
heightHeight of the image in pixels.
min_areaMinimum area (in pixels) for a region to be included in the SVG.
Returns
std::string A valid SVG string containing the data.
Note
Dox File: doxygen/img2num.h.dox

Definition at line 203 of file labels_to_svg.cpp.

206 {
207 const int32_t num_pixels {width * height};
208 std::vector<int32_t> labels_vector {labels, labels + num_pixels};
209 std::vector<int32_t> region_labels;
210
211 // 1. enumerate regions and convert to Nodes
212 std::vector<Node_ptr> nodes;
213 region_labeling(data, labels_vector, region_labels, width, height, nodes);
214
215 // 2. initialize Graph from all Nodes
216 std::unique_ptr<std::vector<Node_ptr>> node_ptr =
217 std::make_unique<std::vector<Node_ptr>>(std::move(nodes));
218 Graph G(node_ptr, width, height);
219
220 // 3. Discover node adjacencies - add edges to Graph
221 G.discover_edges(region_labels, width, height);
222
223 // 4. Merge small area nodes until all nodes are minArea or larger
224 G.merge_small_area_nodes(min_area, min_thickness);
225
226 // 5. recolor image on new regions
227 ImageLib::Image<ImageLib::RGBAPixel<uint8_t>> results {width, height};
228 for (auto& n : G.get_nodes()) {
229 if (n->area() == 0)
230 continue;
231
232 auto [r, g, b] = n->color();
233 for (auto& [_, p] : n->get_pixels()) {
234 results(p.x, p.y) = {r, g, b};
235 }
236 }
237
238 // 6. Contours
239 // graph will manage computing contours
240 G.compute_contours();
241
242 // accumulate all contours for svg export
243 ColoredContours all_contours;
244 for (auto& n : G.get_nodes()) {
245 if (n->area() == 0)
246 continue;
247 ColoredContours node_contours = n->get_contours();
248 for (auto& c : node_contours.contours) {
249 all_contours.contours.push_back(c);
250 }
251 for (auto& c : node_contours.hierarchy) {
252 all_contours.hierarchy.push_back(c);
253 }
254 for (bool b : node_contours.is_hole) {
255 all_contours.is_hole.push_back(b);
256 }
257 for (auto& c : node_contours.colors) {
258 all_contours.colors.push_back(c);
259 }
260 for (auto& c : node_contours.curves) {
261 all_contours.curves.push_back(c);
262 }
263 }
264
265 // 7. Return SVG
266 return contoursResultToSVG(all_contours, width, height);
267}
Definition graph.h:33

Referenced by image_to_svg().

+ Here is the caller graph for this function:

◆ set_error()

void img2num::set_error ( Error  code,
const std::string  message 
)

Definition at line 12 of file Error.cpp.

12 {
13 last_error = code;
14 last_error_message = message;
15}

◆ threshold_image()

void img2num::threshold_image ( uint8_t *  ptr,
const int  width,
const int  height,
const int  num_thresholds 
)

Apply a thresholding operation to an image.

Parameters
ptrPointer to the image buffer.
widthWidth of the image in pixels.
heightHeight of the image in pixels.
num_thresholdsNumber of thresholds to apply.
Note
Thresholds split pixel intensity ranges into discrete levels.
Dox File: doxygen/img2num.h.dox

Definition at line 119 of file image_utils.cpp.

119 {
120 if (num_thresholds <= 0) {
121 return;
122 }
123 const uint8_t REGION_SIZE(255 / num_thresholds); // Size of buckets per colour
124
126 img.loadFromBuffer(ptr, width, height, ImageLib::RGBA_CONVERTER<uint8_t>);
127
128 const auto imgWidth {img.getWidth()}, imgHeight {img.getHeight()};
129 for (ImageLib::RGBAPixel<uint8_t>& p : img) {
130 p.red = quantize(p.red, REGION_SIZE);
131 p.green = quantize(p.green, REGION_SIZE);
132 p.blue = quantize(p.blue, REGION_SIZE);
133 }
134
135 const auto& modified = img.getData();
136 std::memcpy(ptr, modified.data(), modified.size() * sizeof(ImageLib::RGBAPixel<uint8_t>));
137}

Variable Documentation

◆ last_error

thread_local Error img2num::last_error {Error::OK}

Definition at line 4 of file Error.cpp.

4{Error::OK};

◆ last_error_message

thread_local std::string img2num::last_error_message {}

Definition at line 5 of file Error.cpp.

5{};