Skip to content

Commit

Permalink
1.2: header version
Browse files Browse the repository at this point in the history
  • Loading branch information
zvezdochiot committed Dec 25, 2024
1 parent a0000f9 commit a1e6c6e
Show file tree
Hide file tree
Showing 2 changed files with 159 additions and 91 deletions.
100 changes: 9 additions & 91 deletions src/gradsnip.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#include "stb/stb_image_write.h"
#define IIR_GAUSS_BLUR_IMPLEMENTATION
#include "iir_gauss_blur.h"
#define THRESHOLD_GRADSNIP_IMPLEMENTATION
#include "thresgradsnip.h"

void usage(char* progname)
{
Expand Down Expand Up @@ -43,10 +45,10 @@ void help(float sigma, float coef, float delta, unsigned char bound_lower, unsig
);
}

uint8_t* image_copy(unsigned int width, unsigned int height, unsigned char components, unsigned char* image)
unsigned char* image_copy(unsigned int width, unsigned int height, unsigned char components, unsigned char* image)
{
size_t image_size = height * width * components;
uint8_t* dest = (unsigned char*)malloc(image_size * sizeof(unsigned char));
unsigned char* dest = (unsigned char*)malloc(image_size * sizeof(unsigned char));
if (dest != NULL)
{
for (size_t i = 0; i < image_size; i++)
Expand All @@ -57,73 +59,6 @@ uint8_t* image_copy(unsigned int width, unsigned int height, unsigned char compo
return dest;
}

float image_threshold_grad_value(unsigned int width, unsigned int height, unsigned char components, unsigned char* image, unsigned char* blur, unsigned char* threshold_global)
{
float gradient = 0.0f;
if ((image != NULL) && (blur != NULL) && (threshold_global != NULL))
{
for (unsigned char c = 0; c < components; c++)
{
size_t i = c;
double sum_gi = 0.0, sum_g = 0.0;
for (unsigned int y = 0; y < height; y++)
{
double sum_gil = 0.0, sum_gl = 0.0;
for (unsigned int x = 0; x < width; x++)
{
float s = image[i];
float b = blur[i];
float g = (s < b) ? (b - s) : (s - b);
sum_gl += g;
sum_gil += (g * s);
i += components;
}
sum_g += sum_gl;
sum_gi += sum_gil;
}
float threshold = (sum_g > 0) ? (sum_gi / sum_g) : 127.5f;
threshold_global[c] = (threshold < 0.0f) ? 0 : ((threshold < 255.0f) ? (uint8_t)(threshold + 0.5f) : 255);
gradient += (sum_g / width / height);
}
}
gradient /= components;

return gradient;
}

float image_threshold_grad_apply(unsigned int width, unsigned int height, unsigned char components, float coef, float delta, unsigned char bound_lower, unsigned char bound_upper, unsigned char* image, unsigned char* blur, unsigned char* threshold_global)
{
float bwm = 0.0f;
if ((image != NULL) && (blur != NULL) && (threshold_global != NULL))
{
size_t count_black = 0;
for (unsigned char c = 0; c < components; c++)
{
size_t i = c;
float tg = threshold_global[c];
for (unsigned int y = 0; y < height; y++)
{
for (unsigned int x = 0; x < width; x++)
{
float s = image[i];
float b = blur[i];
float t = b * coef + tg * (1.0f - coef) + delta;
unsigned char retval = 255;
if ((s < bound_lower) || ((s <= bound_upper) && (s < t)))
{
retval = 0;
count_black++;
}
image[i] = retval;
i += components;
}
}
}
bwm = (double) count_black / (width * height * components);
}
return bwm;
}

int main(int argc, char** argv)
{
int info = 0;
Expand Down Expand Up @@ -165,12 +100,6 @@ int main(int argc, char** argv)
return 1;
}
}
if (bound_upper < bound_lower)
{
unsigned char bound = bound_lower;
bound_lower = bound_upper;
bound_upper = bound;
}

// Need at least two filenames after the last option
if (argc < optind + 2)
Expand All @@ -180,52 +109,41 @@ int main(int argc, char** argv)
}

int width = 0, height = 0, components = 1;
uint8_t* image = stbi_load(argv[optind], &width, &height, &components, 0);
unsigned char* image = stbi_load(argv[optind], &width, &height, &components, 0);
if (image == NULL)
{
fprintf(stderr, "Failed to load %s: %s.\n", argv[optind], stbi_failure_reason());
return 2;
}

uint8_t* blur = image_copy(width, height, components, image);
unsigned char* blur = image_copy(width, height, components, image);
if (blur == NULL)
{
fprintf(stderr, "ERROR: not use memmory\n");
return 3;
}

uint8_t* threshold_global = (unsigned char*)malloc(components * sizeof(unsigned char));;
unsigned char* threshold_global = (unsigned char*)malloc(components * sizeof(unsigned char));
if (threshold_global == NULL)
{
fprintf(stderr, "ERROR: not use memmory\n");
return 3;
}

iir_gauss_blur(width, height, components, blur, sigma);

float gradient = image_threshold_grad_value(width, height, components, image, blur, threshold_global);
float bwm = image_threshold_grad_apply(width, height, components, coef, delta, bound_lower, bound_upper, image, blur, threshold_global);
if (info > 0)
{
fprintf(stderr, "INFO: image %s\n", argv[optind]);
fprintf(stderr, "INFO: width %d\n", width);
fprintf(stderr, "INFO: height %d\n", height);
fprintf(stderr, "INFO: components %d\n", components);
fprintf(stderr, "INFO: sigma %f\n", sigma);
fprintf(stderr, "INFO: gradient %f\n", gradient);
if ((image != NULL) && (blur != NULL) && (threshold_global != NULL))
{
for (unsigned char c = 0; c < components; c++)
{
fprintf(stderr, "INFO: component %d : threshold %d\n", c, threshold_global[c]);
}
}
fprintf(stderr, "INFO: coeff. %f\n", coef);
fprintf(stderr, "INFO: delta %f\n", delta);
fprintf(stderr, "INFO: bound lower %d\n", bound_lower);
fprintf(stderr, "INFO: bound upper %d\n", bound_upper);
fprintf(stderr, "INFO: BW metric %f\n", bwm);
}
iir_gauss_blur(width, height, components, blur, sigma);
image_threshold_gradsnip(width, height, components, coef, delta, bound_lower, bound_upper, info, image, blur, threshold_global);

if ( stbi_write_png(argv[optind+1], width, height, components, image, 0) == 0 )
{
Expand Down
150 changes: 150 additions & 0 deletions src/thresgradsnip.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
/**
Grad (aka "Gradient Snip") threshold v1.2
By zvezdochiot <mykaralw@yandex.ru>
This is free and unencumbered software released into the public domain.
QUICK START
#include ...
#include ...
#define THRESHOLD_GRADSNIP_IMPLEMENTATION
#include "thresgradsnip.h"
...
unsigned int width = 0, height = 0;
unsigned int widthb = 0, heightb = 0;
unsigned char components = 1, componentsb = 1;
float coef = 0.75f, delta = 0.0f;
unsigned char bound_lower = 0, bound_upper = 255;
int info = 1;
unsigned char* image = stbi_load("foo.png", &width, &height, &components, 0);
unsigned char* blur = stbi_load("foo_blur.png", &widthb, &heightb, &componentsb, 0);
unsigned char* threshold_global = (unsigned char*)malloc(components * sizeof(unsigned char));
if ((width == widthb) && (height == heightb) && (components == componentsb) && (threshold_global != NULL))
{
image_threshold_gradsnip(width, height, components, coef, delta, bound_lower, bound_upper, info, image, blur, threshold_global);
stbi_write_png("foo.thresgrad.png", width, height, components, image, 0);
}
VERSION HISTORY
1.2 2024-12-25 "head" Header release.
1.1 2024-12-17 "regulator" Add regulator: delta and bounds: lower and upper.
1.0 2024-12-16 "init" Initial release.
**/

#ifndef THRESHOLD_GRADSNIP_H
#define THRESHOLD_GRADSNIP_H
#ifdef __cplusplus
extern "C" {
#endif

float image_threshold_gradsnip_value(unsigned int width, unsigned int height, unsigned char components, unsigned char* image, unsigned char* blur, unsigned char* threshold_global);
float image_threshold_gradsnip_apply(unsigned int width, unsigned int height, unsigned char components, float coef, float delta, unsigned char bound_lower, unsigned char bound_upper, unsigned char* image, unsigned char* blur, unsigned char* threshold_global);
void image_threshold_gradsnip(unsigned int width, unsigned int height, unsigned char components, float coef, float delta, unsigned char bound_lower, unsigned char bound_upper, int info, unsigned char* image, unsigned char* blur, unsigned char* threshold_global);

#ifdef __cplusplus
}
#endif
#endif /* THRESHOLD_GRADSNIP_H */

#ifdef THRESHOLD_GRADSNIP_IMPLEMENTATION
#include <stdlib.h>
#include <math.h>

float image_threshold_gradsnip_value(unsigned int width, unsigned int height, unsigned char components, unsigned char* image, unsigned char* blur, unsigned char* threshold_global)
{
float gradient = 0.0f;
if ((image != NULL) && (blur != NULL) && (threshold_global != NULL))
{
for (unsigned char c = 0; c < components; c++)
{
size_t i = c;
double sum_gi = 0.0, sum_g = 0.0;
for (unsigned int y = 0; y < height; y++)
{
double sum_gil = 0.0, sum_gl = 0.0;
for (unsigned int x = 0; x < width; x++)
{
float s = image[i];
float b = blur[i];
float g = (s < b) ? (b - s) : (s - b);
sum_gl += g;
sum_gil += (g * s);
i += components;
}
sum_g += sum_gl;
sum_gi += sum_gil;
}
float threshold = (sum_g > 0) ? (sum_gi / sum_g) : 127.5f;
threshold_global[c] = (threshold < 0.0f) ? 0 : ((threshold < 255.0f) ? (unsigned char)(threshold + 0.5f) : 255);
gradient += (sum_g / width / height);
}
}
gradient /= components;

return gradient;
}

float image_threshold_gradsnip_apply(unsigned int width, unsigned int height, unsigned char components, float coef, float delta, unsigned char bound_lower, unsigned char bound_upper, unsigned char* image, unsigned char* blur, unsigned char* threshold_global)
{
float bwm = 0.0f;
if ((image != NULL) && (blur != NULL) && (threshold_global != NULL))
{
size_t count_black = 0;
for (unsigned char c = 0; c < components; c++)
{
size_t i = c;
float tg = threshold_global[c];
for (unsigned int y = 0; y < height; y++)
{
for (unsigned int x = 0; x < width; x++)
{
float s = image[i];
float b = blur[i];
float t = b * coef + tg * (1.0f - coef) + delta;
unsigned char retval = 255;
if ((s < bound_lower) || ((s <= bound_upper) && (s < t)))
{
retval = 0;
count_black++;
}
image[i] = retval;
i += components;
}
}
}
bwm = (double) count_black / (width * height * components);
}
return bwm;
}

void image_threshold_gradsnip(unsigned int width, unsigned int height, unsigned char components, float coef, float delta, unsigned char bound_lower, unsigned char bound_upper, int info, unsigned char* image, unsigned char* blur, unsigned char* threshold_global)
{
if (bound_upper < bound_lower)
{
unsigned char bound = bound_lower;
bound_lower = bound_upper;
bound_upper = bound;
}

float gradient = image_threshold_gradsnip_value(width, height, components, image, blur, threshold_global);
float bwm = image_threshold_gradsnip_apply(width, height, components, coef, delta, bound_lower, bound_upper, image, blur, threshold_global);
if (info > 0)
{
fprintf(stderr, "INFO: gradient %f\n", gradient);
if ((image != NULL) && (blur != NULL) && (threshold_global != NULL))
{
for (unsigned char c = 0; c < components; c++)
{
fprintf(stderr, "INFO: component %d : threshold %d\n", c, threshold_global[c]);
}
}
fprintf(stderr, "INFO: BW metric %f\n", bwm);
}
}

#endif /* THRESHOLD_GRADSNIP_IMPLEMENTATION */

0 comments on commit a1e6c6e

Please sign in to comment.