Last active
December 26, 2023 00:34
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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