1 #include "internal/image_utils.h"
11 #include "internal/Image.h"
12 #include "internal/PixelConverters.h"
13 #include "internal/RGBAPixel.h"
14 #include "internal/fft_iterative.h"
16 uint8_t quantize(uint8_t value, uint8_t region_size) {
17 if (region_size == 0) {
21 uint8_t bucket = value / region_size;
24 uint8_t bucket_boundary = (bucket * region_size);
25 uint8_t bucket_midpoint =
26 bucket_boundary + (region_size / 2);
30 bool overflow = bucket_midpoint < bucket_boundary;
32 bucket_midpoint = ((bucket - 1) * region_size) +
36 return bucket_midpoint;
44 if (!image || width == 0 || height == 0 || sigma_pixels <= 0)
return;
46 const size_t Npix = width * height;
49 const size_t W = fft::next_power_of_two(width);
50 const size_t H = fft::next_power_of_two(height);
51 const size_t Npix_padded = W * H;
54 auto freq_coord = [](
int k,
int dim) ->
double {
55 return (k <= dim / 2) ? double(k) / dim : double(k - dim) / dim;
59 const double two_pi2_sigma2 = 2.0 * M_PI * M_PI * sigma_pixels * sigma_pixels;
61 for (
int channel = 0; channel < 3; channel++) {
63 std::vector<fft::cd> data(Npix_padded, {0.0, 0.0});
66 for (
size_t y = 0; y < height; y++)
67 for (
size_t x = 0; x < width; x++)
68 data[y * W + x] = fft::cd(image[(y * width + x) * 4 + channel], 0.0);
71 fft::iterative_fft_2d(data, W, H,
false);
74 for (
size_t y = 0; y < H; y++) {
75 double fy2 = freq_coord(y, H) * freq_coord(y, H);
76 for (
size_t x = 0; x < W; x++) {
77 double fx2 = freq_coord(x, W) * freq_coord(x, W);
78 double gain = std::exp(-two_pi2_sigma2 * (fx2 + fy2));
79 data[y * W + x] *= gain;
84 fft::iterative_fft_2d(data, W, H,
true);
87 for (
size_t y = 0; y < height; y++)
88 for (
size_t x = 0; x < width; x++) {
89 double v = data[y * W + x].real();
90 v = std::clamp(v, 0.0, 255.0);
91 image[(y * width + x) * 4 + channel] =
static_cast<uint8_t
>(std::lrint(v));
101 img.loadFromBuffer(ptr, width, height, ImageLib::RGBA_CONVERTER<uint8_t>);
105 p.blue = 255 - p.blue;
106 p.green = 255 - p.green;
109 const auto &modified = img.getData();
113 void threshold_image(uint8_t *ptr,
const int width,
const int height,
const int num_thresholds) {
114 const uint8_t REGION_SIZE(255 / num_thresholds);
117 img.loadFromBuffer(ptr, width, height, ImageLib::RGBA_CONVERTER<uint8_t>);
119 const auto imgWidth{img.getWidth()}, imgHeight{img.getHeight()};
121 p.red = quantize(p.red, REGION_SIZE);
122 p.green = quantize(p.green, REGION_SIZE);
123 p.blue = quantize(p.blue, REGION_SIZE);
126 const auto &modified = img.getData();
131 const int num_thresholds) {
133 img.loadFromBuffer(ptr, width, height, ImageLib::RGBA_CONVERTER<uint8_t>);
135 const auto imgWidth{img.getWidth()}, imgHeight{img.getHeight()};
137 const bool R{p.red < num_thresholds};
138 const bool G{p.green < num_thresholds};
139 const bool B{p.blue < num_thresholds};
145 const auto &modified = img.getData();
Core image processing functions for img2num project.
void black_threshold_image(uint8_t *ptr, const int width, const int height, const int num_thresholds)
Apply black-thresholding to an image.
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 threshold_image(uint8_t *ptr, const int width, const int height, const int num_thresholds)
Apply a thresholding operation to an image.
void invert_image(uint8_t *ptr, int width, int height)
Invert the pixel values of an image.