Created
October 24, 2020 19:28
-
-
Save Vinetos/87c5a63ccc68cb519ff80d2aba9817f5 to your computer and use it in GitHub Desktop.
Otsu algorithm usin SDL in C
This file contains hidden or 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
#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