Skip to content

Instantly share code, notes, and snippets.

@studiosi
Last active December 26, 2023 00:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save studiosi/981353f8b05892a0fb3cc006e0a3148a to your computer and use it in GitHub Desktop.
Save studiosi/981353f8b05892a0fb3cc006e0a3148a to your computer and use it in GitHub Desktop.
Single file library to extend stb_image and apply differents types of thresholds to grayscale images
#ifndef SIL_INCLUDE_THRESHOLD_H
#define SIL_INCLUDE_THRESHOLD_H
// No need to include the implementation, or double include the definitions
#ifndef STBI_INCLUDE_STB_IMAGE_H
#include "stb_image.h"
#endif
// API definition
typedef enum T_SIL_THRESHOLD_TYPE {
// Half of the pixels go to maximum value, half go to minimum
SIL_THRESHOLD_BINARY = 0,
SIL_THRESHOLD_BINARY_INVERTED = 1
} SIL_THRESHOLD_TYPE;
// The threshold happens in-place
void sil_threshold(SIL_THRESHOLD_TYPE type, stbi_uc **img_data, int size_x, int size_y, int n_channels);
#ifdef SIL_THRESHOLD_IMPLEMENTATION
static inline stbi__uint32 sil_threshold_get_max_value() {
// Obtain maximum value of the stbi_uc type
return ((stbi_uc)~(stbi_uc)0);
}
static inline stbi__uint32 *sil_threshold_get_empty_histogram() {
stbi__uint32 n_values = sil_threshold_get_max_value() + 1;
// Dynamically allocate the array
stbi__uint32 *histogram = STBI_MALLOC(n_values * sizeof(stbi__uint32));
// Set all values on the array to zero
memset((void *)histogram, 0, n_values * sizeof(stbi__uint32));
return histogram;
}
static inline void sil_threshold_fill_histogram(stbi__uint32 **histogram, const stbi_uc *img_data, const int size_x, const int size_y) {
for(int y = 0; y < size_y; y++)
for(int x = 0; x < size_x; x++) {
stbi_uc value = img_data[y * size_y + x];
(*histogram)[value]++;
}
}
static void sil_threshold_binary(const SIL_THRESHOLD_TYPE type, const stbi__uint32 *histogram, stbi_uc **img_data, int size_x, int size_y) {
stbi__uint32 pixel_count = (stbi__uint32) round((double) size_x * (double) size_y / 2.0);
stbi__uint32 n_pixels = 0;
stbi_uc n_values = (stbi_uc) sil_threshold_get_max_value();
stbi_uc threshold = 0;
for(stbi_uc i = 0; i <= n_values; i++) {
n_pixels += histogram[i];
if(n_pixels >= pixel_count) {
threshold = i;
break;
}
}
for(int y = 0; y < size_y; y++)
for(int x = 0; x < size_x; x++) {
stbi_uc value = (*img_data)[y * size_y + x];
switch(type) {
case SIL_THRESHOLD_BINARY_INVERTED:
if(value > threshold) {
(*img_data)[y * size_y + x] = 0;
} else {
(*img_data)[y * size_y + x] = n_values;
}
break;
case SIL_THRESHOLD_BINARY:
default:
if(value > threshold) {
(*img_data)[y * size_y + x] = n_values;
} else {
(*img_data)[y * size_y + x] = 0;
}
break;
}
}
}
void sil_threshold(const SIL_THRESHOLD_TYPE type, stbi_uc **img_data, int size_x, int size_y, int n_channels) {
assert(n_channels == STBI_grey);
// Create histogram
stbi__uint32 *histogram = sil_threshold_get_empty_histogram();
sil_threshold_fill_histogram(&histogram, *img_data, size_x, size_y);
// Execute the right type of thresholding
switch(type) {
case SIL_THRESHOLD_BINARY:
case SIL_THRESHOLD_BINARY_INVERTED:
default:
sil_threshold_binary(type, histogram, img_data, size_x, size_y);
break;
}
// Free the histogram after executing the change
STBI_FREE(histogram);
}
#endif // SIL_THRESHOLD_IMPLEMENTATION
#endif // SIL_INCLUDE_THRESHOLD_H
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment