diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index fc89c64..5722156 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -7,6 +7,11 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 + - name: Install deps + run: | + sudo apt-get update -y -qq + sudo apt install libsdl1.2-dev libsdl-image1.2-dev libsdl2-dev + libsdl2-image-dev - name: CMake the project run: cmake . - name: Make the projet diff --git a/CMakeLists.txt b/CMakeLists.txt index b0167f4..69606c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,13 +2,29 @@ cmake_minimum_required(VERSION 3.16) project(CText C) set(CMAKE_C_STANDARD 99) +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/") + + +find_package(SDL2 REQUIRED) +find_package(SDL REQUIRED) +find_package(SDL2_image REQUIRED) + +include_directories( + ${SDL2_INCLUDE_DIRS} + ${SDL_INCLUDE_DIRS} + ${SDL2_IMAGE_INCLUDE_DIRS} +) add_executable( - CText src/main.c + CText src/neuralnetwork/main.c src/neuralnetwork/neuron.c src/neuralnetwork/neuron.h src/neuralnetwork/function.c src/neuralnetwork/function.h src/neuralnetwork/layer.c src/neuralnetwork/layer.h src/util.c src/util.h + src/display/pixel_operations.c src/display/pixel_operations.h + src/display/display.c src/display/display.h + src/preprocessing/grayscale.c src/preprocessing/grayscale.h + src/preprocessing/otsu.c src/preprocessing/otsu.h ) add_executable( @@ -21,17 +37,27 @@ add_executable( src/test/test_method.c src/test/test_method.h ) +add_executable( + CText-display src/preprocessing/main.c + src/display/pixel_operations.c src/display/pixel_operations.h + src/display/display.c src/display/display.h + src/preprocessing/grayscale.c src/preprocessing/grayscale.h + src/preprocessing/otsu.c src/preprocessing/otsu.h +) + add_executable( CText-seg src/segmentation/segmentation.c src/segmentation/segmentation.h ) -target_link_libraries(CText m) +target_link_libraries(CText m ${SDL_LIBRARY} ${SDL2_LIBRARY} ${SDL2_IMAGE_LIBRARIES}) +target_link_libraries(CText-display m ${SDL_LIBRARY} ${SDL2_LIBRARY} + ${SDL2_IMAGE_LIBRARIES}) target_link_libraries(CText-tests m) -if ( CMAKE_COMPILER_IS_GNUCC ) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wshadow -Wdouble-promotion -Wformat=2 -Wformat-truncation -Wformat-overflow -Wundef -fno-common -Wconversion") -endif() -if ( MSVC ) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4") -endif() \ No newline at end of file +if (CMAKE_COMPILER_IS_GNUCC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wshadow -Wdouble-promotion -Wformat=2 -Wformat-truncation -Wformat-overflow -Wundef -fno-common -Wconversion") +endif () +if (MSVC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4") +endif () \ No newline at end of file diff --git a/README b/README index 70c64c5..e8301bf 100644 --- a/README +++ b/README @@ -9,6 +9,9 @@ git clone https://github.com/C-Text/CText.git gcc cmake make +sdl +sdl2 +sdl2_image = Build = cmake . diff --git a/cmake/FindSDL2_image.cmake b/cmake/FindSDL2_image.cmake new file mode 100644 index 0000000..04b60de --- /dev/null +++ b/cmake/FindSDL2_image.cmake @@ -0,0 +1,100 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#.rst: +# FindSDL2_image +# ------------- +# +# Locate SDL2_image library +# +# This module defines: +# +# :: +# +# SDL2_IMAGE_LIBRARIES, the name of the library to link against +# SDL2_IMAGE_INCLUDE_DIRS, where to find the headers +# SDL2_IMAGE_FOUND, if false, do not try to link against +# SDL2_IMAGE_VERSION_STRING - human-readable string containing the +# version of SDL2_image +# +# +# +# For backward compatibility the following variables are also set: +# +# :: +# +# SDL2IMAGE_LIBRARY (same value as SDL2_IMAGE_LIBRARIES) +# SDL2IMAGE_INCLUDE_DIR (same value as SDL2_IMAGE_INCLUDE_DIRS) +# SDL2IMAGE_FOUND (same value as SDL2_IMAGE_FOUND) +# +# +# +# $SDLDIR is an environment variable that would correspond to the +# ./configure --prefix=$SDLDIR used in building SDL. +# +# Created by Eric Wing. This was influenced by the FindSDL.cmake +# module, but with modifications to recognize OS X frameworks and +# additional Unix paths (FreeBSD, etc). + +if(NOT SDL2_IMAGE_INCLUDE_DIR AND SDL2IMAGE_INCLUDE_DIR) + set(SDL2_IMAGE_INCLUDE_DIR ${SDL2IMAGE_INCLUDE_DIR} CACHE PATH "directory cache entry initialized from old variable name") +endif() +find_path(SDL2_IMAGE_INCLUDE_DIR SDL_image.h + HINTS + ENV SDL2IMAGEDIR + ENV SDL2DIR + ${SDL2_DIR} + PATH_SUFFIXES SDL2 + # path suffixes to search inside ENV{SDL2DIR} + include/SDL2 include + ) + +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(VC_LIB_PATH_SUFFIX lib/x64) +else() + set(VC_LIB_PATH_SUFFIX lib/x86) +endif() + +if(NOT SDL2_IMAGE_LIBRARY AND SDL2IMAGE_LIBRARY) + set(SDL2_IMAGE_LIBRARY ${SDL2IMAGE_LIBRARY} CACHE FILEPATH "file cache entry initialized from old variable name") +endif() +find_library(SDL2_IMAGE_LIBRARY + NAMES SDL2_image + HINTS + ENV SDL2IMAGEDIR + ENV SDL2DIR + ${SDL2_DIR} + PATH_SUFFIXES lib ${VC_LIB_PATH_SUFFIX} + ) + +if(SDL2_IMAGE_INCLUDE_DIR AND EXISTS "${SDL2_IMAGE_INCLUDE_DIR}/SDL2_image.h") + file(STRINGS "${SDL2_IMAGE_INCLUDE_DIR}/SDL2_image.h" SDL2_IMAGE_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL2_IMAGE_MAJOR_VERSION[ \t]+[0-9]+$") + file(STRINGS "${SDL2_IMAGE_INCLUDE_DIR}/SDL2_image.h" SDL2_IMAGE_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL2_IMAGE_MINOR_VERSION[ \t]+[0-9]+$") + file(STRINGS "${SDL2_IMAGE_INCLUDE_DIR}/SDL2_image.h" SDL2_IMAGE_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL2_IMAGE_PATCHLEVEL[ \t]+[0-9]+$") + string(REGEX REPLACE "^#define[ \t]+SDL2_IMAGE_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_IMAGE_VERSION_MAJOR "${SDL2_IMAGE_VERSION_MAJOR_LINE}") + string(REGEX REPLACE "^#define[ \t]+SDL2_IMAGE_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_IMAGE_VERSION_MINOR "${SDL2_IMAGE_VERSION_MINOR_LINE}") + string(REGEX REPLACE "^#define[ \t]+SDL2_IMAGE_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL2_IMAGE_VERSION_PATCH "${SDL2_IMAGE_VERSION_PATCH_LINE}") + set(SDL2_IMAGE_VERSION_STRING ${SDL2_IMAGE_VERSION_MAJOR}.${SDL2_IMAGE_VERSION_MINOR}.${SDL2_IMAGE_VERSION_PATCH}) + unset(SDL2_IMAGE_VERSION_MAJOR_LINE) + unset(SDL2_IMAGE_VERSION_MINOR_LINE) + unset(SDL2_IMAGE_VERSION_PATCH_LINE) + unset(SDL2_IMAGE_VERSION_MAJOR) + unset(SDL2_IMAGE_VERSION_MINOR) + unset(SDL2_IMAGE_VERSION_PATCH) +endif() + +set(SDL2_IMAGE_LIBRARIES ${SDL2_IMAGE_LIBRARY}) +set(SDL2_IMAGE_INCLUDE_DIRS ${SDL2_IMAGE_INCLUDE_DIR}) + +include(FindPackageHandleStandardArgs) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2_image + REQUIRED_VARS SDL2_IMAGE_LIBRARIES SDL2_IMAGE_INCLUDE_DIRS + VERSION_VAR SDL2_IMAGE_VERSION_STRING) + +# for backward compatibility +set(SDL2IMAGE_LIBRARY ${SDL2_IMAGE_LIBRARIES}) +set(SDL2IMAGE_INCLUDE_DIR ${SDL2_IMAGE_INCLUDE_DIRS}) +set(SDL2IMAGE_FOUND ${SDL2_IMAGE_FOUND}) + +mark_as_advanced(SDL2_IMAGE_LIBRARY SDL2_IMAGE_INCLUDE_DIR) diff --git a/src/display/display.c b/src/display/display.c new file mode 100644 index 0000000..c5a7ffd --- /dev/null +++ b/src/display/display.c @@ -0,0 +1,84 @@ +#include +#include "SDL/SDL.h" +#include "SDL/SDL_image.h" + + +/** + *Author: Lise Giraud + *Date: 20/10/2020 + */ + +/** + *Init only the video part. + * + *@throw error message if it fail. + */ +void init_sdl() { + if (SDL_Init(SDL_INIT_VIDEO) == -1) + errx(1, "Could not initialize SDL: %s.\n", SDL_GetError()); +} + +/** + *Load an image from a given path using SDL_image with format detection. + * + *@throw error if there is no image at the given path. + *@param path: the path of the image to display. + * + *@return image found at the given path. + */ +SDL_Surface *load_image(char *path) { + SDL_Surface *img; + + img = IMG_Load(path); + if (!img) + errx(3, "can't load %s: %s", path, IMG_GetError()); + + return img; +} + +/** + *Displays a given image in a window. + * + *@throw error if screen is null (cannot set video mode). + *@param img the image to display in a window. + * + @return screen: a displayed image in a window. + */ +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; +} + +/** + *Wait for a key of the keyboard to be pressed before executing any action. + */ +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); +} \ No newline at end of file diff --git a/src/display/display.h b/src/display/display.h new file mode 100644 index 0000000..4413b97 --- /dev/null +++ b/src/display/display.h @@ -0,0 +1,41 @@ +/** + *Author: Lise Giraud + *Date: 20/10/2020 + *File's name: display.h + */ +#ifndef CTEXT_SRC_DISPLAY_DISPLAY_H_ +#define CTEXT_SRC_DISPLAY_DISPLAY_H_ + +#include +/** + *Init only the video part. + *@throw error message if it fail. + */ +void init_sdl(); + +/** + *Load an image from a given path using SDL_image with format detection. + * + *@throw error if there is no image at the given path. + *@param path: the path of the image to display. + * + *@return image found at the given path. + */ +SDL_Surface *load_image(char *path); + +/** + *Displays a given image in a window. + * + *@throw error if screen is null (cannot set video mode). + *@param img the image to display in a window. + * + @return screen: a displayed image in a window. + */ +SDL_Surface *display_image(SDL_Surface *img); + +/** + *Wait for a key of the keyboard to be pressed before executing any action. + */ +void wait_for_keypressed(); + +#endif //CTEXT_SRC_DISPLAY_DISPLAY_H_ diff --git a/src/display/pixel_operations.c b/src/display/pixel_operations.c new file mode 100644 index 0000000..88e8de0 --- /dev/null +++ b/src/display/pixel_operations.c @@ -0,0 +1,103 @@ +/** + *Author: Lise + *Date: 22/10/2020 + *File's name: pixel_operations.c + */ +// Simple get/put pixel for SDL +// Inspired by code from SDL documentation +// (http://www.libsdl.org/release/SDL-1.2.15/docs/html/guidevideo.html) + +#include +#include "pixel_operations.h" +#include + +/** + *Determines on how many bytes pixels are encoded. + * + *@param surf is the SDL surface of the image. + *@param x and param y are the coordonates (x,y) of the pixel on the surface. + * + *@return the value of the pixel(r,g,b) in decimal base. + */ +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; +} + +/** + *get the pixel on coordonates x y of the image. + * + *@param *surface is the SDL surface of the image. + *@param x and param y are the coordonates (x,y) of the pixel on the surface. + * + *@return the pixel (x,y) in the right format. + */ +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; +} + +/** + *Replace the pixel (x,y) by the new value pixel on a given surface + * + *@param *surface is the SDL surface of the image + *@param x and param y are the coordinates (x,y) of the pixel to replace onthe image. + *@param pixel is the new value of the pixel. + * + */ +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; + } +} + +/** + *Update the "old" surface with its new values. + * + *@throw warning if there is no surface to blit. + *@param screen is the window to update + *@param image is the image to update + */ +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); +} diff --git a/src/display/pixel_operations.h b/src/display/pixel_operations.h new file mode 100644 index 0000000..b439125 --- /dev/null +++ b/src/display/pixel_operations.h @@ -0,0 +1,41 @@ +#ifndef CTEXT_SRC_PREPROCESSING_PIXEL_OPERATIONS_H_ +#define CTEXT_SRC_PREPROCESSING_PIXEL_OPERATIONS_H_ +/** + *Author: Lise Giraud + *Date: 22/10/2020 + *File's name: pixel_operations.h + */ + +#include +#include + +/** + *get the pixel on coordonates x y of the image. + * + *@param *surface is the SDL surface of the image. + *@param x and param y are the coordonates (x,y) of the pixel on the surface. + * + *@return the pixel (x,y) in the right format. + */ +Uint32 get_pixel(SDL_Surface *surface, unsigned x, unsigned y); + +/** + *Replace the pixel (x,y) by the new value pixel on a given surface. + * + *@param *surface is the SDL surface of the image. + *@param x and param y are the coordinates (x,y) of the pixel to replace on the image. + *@param pixel is the new value of the pixel. + * + */ +void put_pixel(SDL_Surface *surface, unsigned x, unsigned y, Uint32 pixel); + +/** + *Update the "old" surface with its new values. + * + *@throw warning if there is no surface to blit. + *@param screen is the window to update. + *@param image is the image to update. + */ +void update_surface(SDL_Surface *screen, SDL_Surface *image); + +#endif //CTEXT_SRC_PREPROCESSING_PIXEL_OPERATIONS_H_ diff --git a/src/main.c b/src/neuralnetwork/main.c similarity index 96% rename from src/main.c rename to src/neuralnetwork/main.c index fa02be5..49e7f28 100644 --- a/src/main.c +++ b/src/neuralnetwork/main.c @@ -1,4 +1,4 @@ -#include "neuralnetwork/layer.h" +#include "layer.h" #include void prints(layer *l1, layer *l2) { diff --git a/src/preprocessing/grayscale.c b/src/preprocessing/grayscale.c new file mode 100644 index 0000000..3064d59 --- /dev/null +++ b/src/preprocessing/grayscale.c @@ -0,0 +1,32 @@ +#include "SDL/SDL.h" +#include "../display/pixel_operations.h" + +/** + *Author: Lise Giraud + *Date: 22/10/2020 + *File's name: grayscale.c + */ + +/** + *Convert colored image into grayscale image. + * + *@param image_surface is the image to convert into grayscale. + */ +void grayscale(SDL_Surface *image_surface) { + int w = image_surface->w; + int h = image_surface->h; + Uint8 r, g, b; + + for (int i = 0; i < w; i++) { + for (int j = 0; j < h; j++) { + Uint32 pixel = get_pixel(image_surface, i, j); + SDL_GetRGB(pixel, image_surface->format, &r, &g, &b); + float average = 0.3 * r + 0.59 * g + 0.11 * b; + r = average; + b = average; + b = average; + pixel = SDL_MapRGB(image_surface->format, r, g, b); + put_pixel(image_surface, i, j, pixel); + } + } +} diff --git a/src/preprocessing/grayscale.h b/src/preprocessing/grayscale.h new file mode 100644 index 0000000..295feb7 --- /dev/null +++ b/src/preprocessing/grayscale.h @@ -0,0 +1,19 @@ +/** + *Author: Lise Giraud + *Date: 22/10/2020 + *File's name: grayscale.h + */ + +#ifndef CTEXT_SRC_PREPROCESSING_GRAYSCALE_H_ +#define CTEXT_SRC_PREPROCESSING_GRAYSCALE_H_ + +#include "SDL/SDL.h" + +/** + *Convert colored image into grayscale image. + * + *@param image_surface is the image to convert into grayscale. + */ +void grayscale(SDL_Surface *image_surface); + +#endif //CTEXT_SRC_PREPROCESSING_GRAYSCALE_H_ diff --git a/src/preprocessing/main.c b/src/preprocessing/main.c new file mode 100644 index 0000000..668b519 --- /dev/null +++ b/src/preprocessing/main.c @@ -0,0 +1,89 @@ +/** + *Author: Lise Giraud + *Date: 24/10/2020 + *File's name: main.c +*/ +#include +#include "SDL/SDL.h" +#include "SDL/SDL_image.h" +#include +#include "../display/pixel_operations.h" +#include "../display/display.h" +#include "grayscale.h" +#include "otsu.h" + +/** + *Main function: use all functions initialized above to display an image and convert it into grayscale. + *Then, it prints the binarization matrice of the given image and display the binarized image. + */ +int main() { + char str[100]; + + printf("Enter the path of an image :"); + int scan = scanf("%s", str); + if (scan == 0) { + printf("error :c"); + errx(1, "Could not initialize SDL: %s.\n", SDL_GetError()); + } + + printf("\nYou entered: %s", str); + + SDL_Surface *image_surface; + SDL_Surface *screen_surface; + + init_sdl(); + + image_surface = load_image(str); + screen_surface = display_image(image_surface); + + wait_for_keypressed(); + + grayscale(image_surface); + + update_surface(screen_surface, image_surface); + + wait_for_keypressed(); + + int w = image_surface->w; + int h = image_surface->h; + + unsigned int his[256]; + histo(h, w, his, image_surface); + + int threshold; + threshold = otsu(his, w, h); + + char bin[w][h]; + binarization(w, h, bin, threshold, image_surface); + + //print the matrix of the binarized image. + printf("binarization: "); + for (int i = 0; i < w; i++) { + for (int j = 0; j < h; j++) { + printf("%d", bin[i][j]); + } + printf("\n"); + } + + //display the binarized image. + Uint8 gray; + for (int i = 0; i < w; i++) { + for (int j = 0; j < h; j++) { + Uint32 pixel = get_pixel(image_surface, i, j); + SDL_GetRGB(pixel, image_surface->format, &gray, &gray, + &gray); + pixel = SDL_MapRGB(image_surface->format, gray * 255, + gray * 255, gray * 255); + put_pixel(image_surface, i, j, pixel); + } + } + + update_surface(screen_surface, image_surface); + + wait_for_keypressed(); + + SDL_FreeSurface(image_surface); + SDL_FreeSurface(screen_surface); + + return 0; +} diff --git a/src/preprocessing/otsu.c b/src/preprocessing/otsu.c new file mode 100644 index 0000000..fcd7f71 --- /dev/null +++ b/src/preprocessing/otsu.c @@ -0,0 +1,118 @@ +/** + *Author: Lise Giraud and Valentin Chassignol + *Date: 24/10/2020 + *File's name : otsu.c + */ + +#include +#include "SDL/SDL.h" +#include "SDL/SDL_image.h" +#include "../display/pixel_operations.h" +#include "../display/display.h" +#include "grayscale.h" + +/** + *Calculation of the median in the histogram between start and end values. + * + *@param histo is the histogram of grayscale in a given image. + *@param start is where to start to calculate the median. + *@param end is where to end to calculate the median. + * + *@return the median value between start and end in the histogram. + */ +int mean(unsigned int *histo, int start, int end) { + return histo[end - start]; +} + +/** + *Calculate the sum between start and end (end excluded) of the histogram. + * + *@param *histo is the histogram of grayscale in a given image. + *@param start is where to start the calculus. + *@param end is where to end the calculus (end is excluded). + * + *@return the sum of all the values between start and end. + */ +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; +} + +/** + *Make the grayscale histogram of a given image. + * + *@param histo is the histogram to complete. + *@param w is the weight of the image. + *@param h is the height of the image. + *@param image_surface is the given image to make histogram. + */ +void histo(unsigned int histo[256], unsigned w, unsigned h, + SDL_Surface *image_surface) { + Uint8 gray; + + for (int i = 0; i < w; i++) { + for (int j = 0; j < h; j++) { + Uint32 pixel = get_pixel(image_surface, i, j); + SDL_GetRGB(pixel, image_surface->format, + &gray, &gray, &gray); + histo[gray] += 1; + } + } +} + +/** + *Use the otsu's method to calculate the optimal threshold of a grayscale image. + * + *@param histo is the histogram of grayscale of the image. + *@param w is the weight of the image. + *@param h is the height of the image. + * + *@return the optimal threshold. + */ +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; +} + +/** + *Complete the binarization matrice (matrice of 1 and 0). + * + *@param w is the weight of the image to binarize. + *@param h is the height of the image to binarize. + *@param binarization is the binarization matrice of the image. Must contain only 0 and 1. + *@param final_t is the optimal threshold of the image to binarize. + *@param image_surface is the image to binarize. + */ +void binarization(unsigned int w, unsigned int h, char binarization[w][h], + int final_t, SDL_Surface *image_surface) { + Uint8 average; + for (int i = 0; i < w; i++) { + for (int j = 0; j < h; j++) { + Uint32 pixel = get_pixel(image_surface, i, j); + SDL_GetRGB(pixel, image_surface->format, &average, + &average, &average); + if (average > final_t) + binarization[i][j] = 1; + else + binarization[i][j] = 0; + } + } +} \ No newline at end of file diff --git a/src/preprocessing/otsu.h b/src/preprocessing/otsu.h new file mode 100644 index 0000000..99177fb --- /dev/null +++ b/src/preprocessing/otsu.h @@ -0,0 +1,68 @@ +/** + *Authors: Lise Giraud and Valentin Chassignol + *Date: 24/10/2020 + *File's name: otsu.h + */ + +#ifndef CTEXT_SRC_PREPROCESSING_OTSU_H_ +#define CTEXT_SRC_PREPROCESSING_OTSU_H_ + +#include "SDL/SDL.h" + +/** + *Calculation of the median in the histogram between start and end values. + * + *@param histo is the histogram of grayscale in a given image. + *@param start is where to start to calculate the median. + *@param end is where to end to calculate the median. + * + *@return the median value between start and end in the histogram. + */ +int mean(unsigned int *histo, int start, int end); + +/** + *Calculate the sum between start and end (end excluded) of the histogram. + * + *@param *histo is the histogram of grayscale in a given image. + *@param start is where to start the calculus. + *@param end is where to end the calculus (end is excluded). + * + *@return the sum of all the values between start and end. + */ +int sum(unsigned int *histo, int start, int end); + +/** + *Make the grayscale histogram of a given image. + * + *@param histo is the histogram to complete. + *@param w is the weight of the image. + *@param h is the height of the image. + *@param image_surface is the given image to make histogram. + */ +void histo(unsigned int histo[256], unsigned w, unsigned h, + SDL_Surface *image_surface); + +/** + *Use the otsu's method to calculate the optimal threshold of a grayscale image. + * + *@param histo is the histogram of grayscale of the image. + *@param w is the weight of the image. + *@param h is the height of the image. + * + *@return the optimal threshold. + */ +int otsu(unsigned int histo[256], unsigned w, unsigned h); + +/** + *Complete the binarization matrice (matrice of 1 and 0). + * + *@param w is the weight of the image to binarize. + *@param h is the height of the image to binarize. + *@param binarization is the binarization matrice of the image. Must contain only 0 and 1. + *@param final_t is the optimal threshold of the image to binarize. + *@param image_surface is the image to binarize. + */ +void binarization(unsigned int w, unsigned int h, char binarization[w][h], + int final_t, SDL_Surface *image_surface); + +#endif //CTEXT_SRC_PREPROCESSING_OTSU_H_