Skip to content

Instantly share code, notes, and snippets.

@Vinetos
Created October 24, 2020 19:28
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 Vinetos/87c5a63ccc68cb519ff80d2aba9817f5 to your computer and use it in GitHub Desktop.
Save Vinetos/87c5a63ccc68cb519ff80d2aba9817f5 to your computer and use it in GitHub Desktop.
Otsu algorithm usin SDL in C
#include <err.h>
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
static inline
Uint8* pixel_ref(SDL_Surface *surf, unsigned x, unsigned y)
{
int bpp = surf->format->BytesPerPixel;
return (Uint8*)surf->pixels + y * surf->pitch + x * bpp;
}
Uint32 get_pixel(SDL_Surface *surface, unsigned x, unsigned y)
{
Uint8 *p = pixel_ref(surface, x, y);
switch (surface->format->BytesPerPixel)
{
case 1:
return *p;
case 2:
return *(Uint16 *)p;
case 3:
if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
return p[0] << 16 | p[1] << 8 | p[2];
else
return p[0] | p[1] << 8 | p[2] << 16;
case 4:
return *(Uint32 *)p;
}
return 0;
}
void put_pixel(SDL_Surface *surface, unsigned x, unsigned y, Uint32 pixel)
{
Uint8 *p = pixel_ref(surface, x, y);
switch(surface->format->BytesPerPixel)
{
case 1:
*p = pixel;
break;
case 2:
*(Uint16 *)p = pixel;
break;
case 3:
if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
{
p[0] = (pixel >> 16) & 0xff;
p[1] = (pixel >> 8) & 0xff;
p[2] = pixel & 0xff;
}
else
{
p[0] = pixel & 0xff;
p[1] = (pixel >> 8) & 0xff;
p[2] = (pixel >> 16) & 0xff;
}
break;
case 4:
*(Uint32 *)p = pixel;
break;
}
}
void update_surface(SDL_Surface* screen, SDL_Surface* image)
{
if (SDL_BlitSurface(image, NULL, screen, NULL) < 0)
warnx("BlitSurface error: %s\n", SDL_GetError());
SDL_UpdateRect(screen, 0, 0, image->w, image->h);
}
int mean(unsigned int *histo, int start, int end) {
return histo[end - start];
}
int sum(unsigned int *histo, int start, int end) {
int sum = 0;
for (int i = start; i < end; i++)
sum += (int) histo[i];
return sum;
}
void histo(unsigned int histo[256], unsigned w,
unsigned h, unsigned int image[w][h]) {
for (unsigned int i = 0; i < w; i++)
for (unsigned int j = 0; j < h; j++)
histo[image[i][j]] += 1;
}
int otsu(unsigned int histo[256],
unsigned w,
unsigned h) {
double final_thresh = -1.0;
int final_t = -1;
double mean_weight = 1.0 / (w * h);
for (int t = 1; t < 255; t++) {
double wb = (double) sum(histo, 0, t) * mean_weight;
double wf = (double) sum(histo, t, 255) * mean_weight;
int mub = mean(histo, 0, t);
int muf = mean(histo, t, 255);
double value = wb * wf * (mub - muf);
value *= value;
if (value > final_thresh) {
final_thresh = value;
final_t = t;
}
}
return final_t;
}
void init_sdl() {
// Init only the video part.
// If it fails, die with an error message.
if (SDL_Init(SDL_INIT_VIDEO) == -1)
errx(1, "Could not initialize SDL: %s.\n", SDL_GetError());
}
SDL_Surface *load_image(char *path) {
SDL_Surface *img;
// Load an image using SDL_image with format detection.
// If it fails, die with an error message.
img = IMG_Load(path);
if (!img)
errx(3, "can't load %s: %s", path, IMG_GetError());
return img;
}
SDL_Surface *display_image(SDL_Surface *img) {
SDL_Surface *screen;
// Set the window to the same size as the image
screen = SDL_SetVideoMode(img->w, img->h, 0, SDL_SWSURFACE | SDL_ANYFORMAT);
if (screen == NULL) {
// error management
errx(1, "Couldn't set %dx%d video mode: %s\n",
img->w, img->h, SDL_GetError());
}
// Blit onto the screen surface
if (SDL_BlitSurface(img, NULL, screen, NULL) < 0)
warnx("BlitSurface error: %s\n", SDL_GetError());
// Update the screen
SDL_UpdateRect(screen, 0, 0, img->w, img->h);
// return the screen for further uses
return screen;
}
void wait_for_keypressed() {
SDL_Event event;
// Wait for a key to be down.
do {
SDL_PollEvent(&event);
} while (event.type != SDL_KEYDOWN);
// Wait for a key to be up.
do {
SDL_PollEvent(&event);
} while (event.type != SDL_KEYUP);
}
int main() {
SDL_Surface *image_surface;
SDL_Surface *screen_surface;
init_sdl();
image_surface = load_image("/home/vinetos/Downloads/bear.png");
unsigned int image[image_surface->w][image_surface->h];
screen_surface = display_image(image_surface);
wait_for_keypressed();
// Process to grayscale
for (int i = 0; i < image_surface->w; i++) {
for (int j = 0; j < image_surface->h; j++) {
Uint32 pixel = get_pixel(image_surface, i, j);
Uint8 r, g, b;
SDL_GetRGB(pixel, image_surface->format, &r, &g, &b);
Uint8 av = 0.3 * r + 0.59 * g + 0.11 * b;
pixel = SDL_MapRGB(image_surface->format, av, av, av);
image[i][j] = av;
put_pixel(image_surface, i, j, pixel);
}
}
// End process to grayscale
update_surface(screen_surface, image_surface);
wait_for_keypressed();
// Process to OTSU
unsigned int h[256];
histo(h, image_surface->w, image_surface->h, image);
int t = otsu(h, image_surface->w, image_surface->h);
printf("%d", t);
for (int i = 0; i < image_surface->w; i++) {
for (int j = 0; j < image_surface->h; j++) {
Uint32 pixel = get_pixel(image_surface, i, j);
Uint8 r, g, b;
SDL_GetRGB(pixel, image_surface->format, &r, &g, &b);
Uint8 av = r < t ? 0 : 255; // Black and white
pixel = SDL_MapRGB(image_surface->format, av, av, av);
image[i][j] = av;
put_pixel(image_surface, i, j, pixel);
}
}
// End process to OTSU
update_surface(screen_surface, image_surface);
wait_for_keypressed();
SDL_FreeSurface(image_surface);
SDL_FreeSurface(screen_surface);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment