banner



How To Read Data From Image File In C#

Solarian Programmer

My programming ramblings

C Programming - Reading and writing images with the stb_image libraries

Posted on June 10, 2019 by Paul

In this article I will show y'all how to read and write images with the stb_image libraries. In order to exemplify the usage of the library I'll demo how to convert an prototype to gray and how to use a sepia filter to the epitome.

As a side note, the C code from this article is compatible with whatever modern C compilers similar GCC, Clang and MSVC.

You can find the source files and paradigm examples used here on the GitHub repo for this article.

The article consists of two parts:

  • stb_image basic usage
  • Writing a wrapper around the stb_image functions

stb_image basic usage

Let's start by getting the libraries from GitHub:

                                                    i                                    git clone https://github.com/nothings/stb.git                              

if you lot don't take git installed on your computer yous tin use the Download Cypher choice.

Side by side, copy the three files prefixed with stb_image from the stb binder in a new folder named stb_image that, from now on, I will assume information technology is nowadays in your projection folder. Optionally, yous can remove the stb folder from your auto.

At that place is too a video version of this role of the tutorial:

Nosotros'll start with an example of basic usage of the library functions. We'll read an prototype from the disk and write it back. The purpose of this example is to familiarize you with the library interface.

We demand to define STB_IMAGE_IMPLEMENTATION earlier including the stb_image.h header. This needs to exist defined just once. If you need to include the stb_image header in another C source file don't redefine the STB_IMAGE_IMPLEMENTATION. Same considerations apply to defining STB_IMAGE_WRITE_IMPLEMENTATION earlier including the "stb_image_write" header file:

                                                                        1                                    #include                  <stdio.h>                                                        2                                    #include                  <stdlib.h>                                                        3                                                        4                                    #define STB_IMAGE_IMPLEMENTATION                                      5                                    #include                  "stb_image/stb_image.h"                                                        six                                    #define STB_IMAGE_WRITE_IMPLEMENTATION                                      7                                    #include                  "stb_image/stb_image_write.h"                                                        eight                                                        9                                    int                  master                  (                  void                  )                  {                  10                                    // ...                  11                                    }                              

In lodge to read an prototype from the disk we'll use the stbi_load function that receives as arguments the epitome file path, width and summit of the epitome, the number of color channels and the desired number of colour channels. The last argument of the function is useful if for example you want to load merely the R, G, B channels from a 4 channel, PNG, image and ignore the transparency channel. If y'all want to load the image equally is, pass 0 as the terminal parameter of the load function. In case of error, the stbi_load part returns NULL.

                                                                        ane                                    // ...                                      ii                                                        3                                    int                  main                  (                  void                  )                  {                                      4                                    int                  width                  ,                  height                  ,                  channels                  ;                                      five                                    unsigned                  char                  *                  img                  =                  stbi_load                  (                  "heaven.jpg"                  ,                  &                  width                  ,                  &                  height                  ,                  &                  channels                  ,                  0                  );                                      6                                    if                  (                  img                  ==                  Zero                  )                  {                                      seven                                    printf                  (                  "Error in loading the prototype                  \n                  "                  );                                      8                                    exit                  (                  i                  );                                      9                                    }                  10                                    printf                  (                  "Loaded image with a width of %dpx, a height of %dpx and %d channels                  \n                  "                  ,                  width                  ,                  height                  ,                  channels                  );                  xi                                    12                                    // ...                  xiii                                    }                              

After yous've finished processing the image, y'all tin write it back to the disk using one of the stbi_image_write functions. Here I'll testify you how to relieve the above loaded image as PNG and JPG images:

                                                                        ane                                    // ...                                      ii                                                        3                                    int                  main                  (                  void                  )                  {                                      4                                    // ...                                      5                                                        6                                    stbi_write_png                  (                  "heaven.png"                  ,                  width                  ,                  summit                  ,                  channels                  ,                  img                  ,                  width                  *                  channels                  );                                      seven                                    stbi_write_jpg                  (                  "sky2.jpg"                  ,                  width                  ,                  peak                  ,                  channels                  ,                  img                  ,                  100                  );                                      8                                                        9                                    stbi_image_free                  (                  img                  );                  ten                                    }                              

The 6th parameter of the stbi_write_png office from the above code is the image stride, which is the size in bytes of a row of the image. The last parameter of the stbi_write_jpg function is a quality parameter that goes from ane to 100. Since JPG is a lossy image format, you tin can chose how much data is dropped at salve time. Lower quality means smaller image size on disk and lower visual epitome quality. Most image editors, like GIMP, will relieve jpg images with a default quality parameter of 80 or 90, but the user can melody the quality parameter if required. I've used a quality parameter of 100 in all examples from this commodity.

Once you are done with an image, you tin can release the retention used to store its information with the stbi_image_free role.

Yous can try the in a higher place code by building and running t0.c from the commodity repo.

Every bit mentioned before, you can load merely the first channels of an image. Here is an instance of loading the first iii color channels of a PNG paradigm:

                                                                        1                                    // ...                                      2                                                        3                                    int                  main                  (                  void                  )                  {                                      iv                                    int                  width                  ,                  height                  ,                  original_no_channels                  ;                                      5                                    int                  desired_no_channels                  =                  iii                  ;                                      6                                    unsigned                  char                  *                  img                  =                  stbi_load                  (                  "Shapes.png"                  ,                  &                  width                  ,                  &                  tiptop                  ,                  &                  original_no_channels                  ,                  desired_no_channels                  );                                      vii                                    if                  (                  img                  ==                  NULL                  )                  {                                      8                                    printf                  (                  "Fault in loading the epitome                  \n                  "                  );                                      9                                    go out                  (                  one                  );                  10                                    }                  11                                    printf                  (                  "Loaded paradigm with a width of %dpx, a height of %dpx. The original epitome had %d channels, the loaded image has %d channels.                  \n                  "                  ,                  width                  ,                  summit                  ,                  original_no_channels                  ,                  desired_no_channels                  );                  12                                    13                                    // ...                  14                                    }                              

Observation, if yous make up one's mind to load merely a sure number of channels from an paradigm, be conscientious to use the desired number of channels in further operations on the paradigm data. The fourth argument of the stbi_load function volition be initialized with the original number of channels of the image. For example, if you desire to salvage the above loaded image yous will use something like this:

                                                    1                                    // ...                  2                                    3                                    int                  master                  (                  void                  )                  {                  4                                    // ...                  5                                    vi                                    stbi_write_png                  (                  "1.png"                  ,                  width                  ,                  height                  ,                  desired_no_channels                  ,                  img                  ,                  width                  *                  desired_no_channels                  );                  seven                                    eight                                    // ...                  nine                                    }                              

You tin see a complete instance of partially loading an epitome in t01.c from this article repo.

Another observation, if y'all are interested only in the image full general information, similar the image size and number of channels, you lot can avoid loading the paradigm in memory by using the stbi_info function which will initialize the width, height and number of channels parameters. Hither is a snippet example:

                                                    one                                    // ...                  2                                    iii                                    int                  main                  (                  void                  )                  {                  iv                                    int                  width                  ,                  height                  ,                  channels                  ;                  5                                    const                  char                  *                  fname                  =                  "Shapes.png"                  ;                  vi                                    stbi_info                  (                  fname                  ,                  &                  width                  ,                  &                  height                  ,                  &                  channels                  );                  7                                    8                                    // ...                  9                                    }                              

As a kickoff example of prototype manipulation, I will show yous how to convert the loaded prototype to gray and save information technology to the deejay. The purpose of this example is to evidence you how to loop over an epitome data and how to access and modify the pixel values.

Permit's assume that you lot've successfully loaded a PNG or JPG epitome and that you want to convert this to gray. The output image will have two or ane channels. For instance, if the input image has a transparency channel this will exist simply copied to the second channel of the gray image, while the first channel of the gray image will contain the grey pixel values. If the input image has three channels, the output image will accept just one channel with the gray data.

Here is a possible implementation of setting the number of channels and allocating memory for the gray prototype:

                                                                        one                                    // ...                                      ii                                                        3                                    int                  main                  (                  void                  )                  {                                      4                                    // Load an image                                      5                                    // ...                                      6                                                        7                                    // Convert the input prototype to gray                                      8                                    size_t                  img_size                  =                  width                  *                  height                  *                  channels                  ;                                      ix                                    int                  gray_channels                  =                  channels                  ==                  iv                  ?                  2                  :                  one                  ;                  x                                    size_t                  gray_img_size                  =                  width                  *                  height                  *                  gray_channels                  ;                  11                                    12                                    unsigned                  char                  *                  gray_img                  =                  malloc                  (                  gray_img_size                  );                  xiii                                    if                  (                  gray_img                  ==                  NULL                  )                  {                  xiv                                    printf                  (                  "Unable to allocate memory for the gray image.                  \n                  "                  );                  15                                    exit                  (                  1                  );                  16                                    }                  17                                    xviii                                    // ...                  19                                    }                              

Next, we'll loop over the pixels of the input prototype, calculate the greyness value as the boilerplate of the blood-red, light-green and blue channels and store the grey value in the output epitome. If the input image has a transparency channel, we'll re-create the values of this to the second channel of the output grayness image:

                                                                        1                                    // ...                                      ii                                                        3                                    int                  main                  (                  void                  )                  {                                      4                                    // Load an image                                      five                                    // ...                                      6                                                        seven                                    // Catechumen the input image to grayness                                      8                                    // Allocate memory for the output image                                      9                                    // ...                  10                                    11                                    for                  (                  unsigned                  char                  *                  p                  =                  img                  ,                  *                  pg                  =                  gray_img                  ;                  p                  !=                  img                  +                  img_size                  ;                  p                  +=                  channels                  ,                  pg                  +=                  gray_channels                  )                  {                  12                                    *                  pg                  =                  (                  uint8_t                  )((                  *                  p                  +                  *                  (                  p                  +                  ane                  )                  +                  *                  (                  p                  +                  2                  ))                  /                  3.0                  );                  13                                    if                  (                  channels                  ==                  iv                  )                  {                  xiv                                    *                  (                  pg                  +                  1                  )                  =                  *                  (                  p                  +                  three                  );                  fifteen                                    }                  16                                    }                  17                                    18                                    // ...                                    nineteen                                    }                              

In the above code the p arrow volition go over the input image, while the pg arrow will go over the output prototype.

Once the gray image is filled, y'all can save it every bit before, due east.m.:

                                                                        ane                                    // ...                                      ii                                                        three                                    int                  master                  (                  void                  )                  {                                      4                                    // Load an epitome and convert it to gray                                      5                                    // ...                                      half-dozen                                                        seven                                    stbi_write_jpg                  (                  "sky_gray.jpg"                  ,                  width                  ,                  tiptop                  ,                  gray_channels                  ,                  gray_img                  ,                  100                  );                                      8                                                        nine                                    // ...                                    10                                    }                              

Next, I volition show you how to convert a color image to sepia. In this case the output image volition have the same size in bytes as the input image. The color channels of the sepia paradigm are a mix of the color channels of the input image:

                                                                        ane                                    // ...                                      2                                                        three                                    int                  chief                  (                  void                  )                  {                                      four                                    // Load an epitome                                      5                                    // ...                                      6                                                        7                                    // Convert the input image to sepia                                      8                                    unsigned                  char                  *                  sepia_img                  =                  malloc                  (                  img_size                  );                                      ix                                    if                  (                  sepia_img                  ==                  Zilch                  )                  {                  10                                    printf                  (                  "Unable to allocate memory for the sepia image.                  \northward                  "                  );                  11                                    leave                  (                  1                  );                  12                                    }                  xiii                                    14                                    // Sepia filter coefficients from https://stackoverflow.com/questions/1061093/how-is-a-sepia-tone-created                  15                                    for                  (                  unsigned                  char                  *                  p                  =                  img                  ,                  *                  pg                  =                  sepia_img                  ;                  p                  !=                  img                  +                  img_size                  ;                  p                  +=                  channels                  ,                  pg                  +=                  channels                  )                  {                  16                                    *                  pg                  =                  (                  uint8_t                  )                  fmin                  (                  0.393                  *                  *                  p                  +                  0.769                  *                  *                  (                  p                  +                  1                  )                  +                  0.189                  *                  *                  (                  p                  +                  ii                  ),                  255.0                  );                  // red                  17                                    *                  (                  pg                  +                  one                  )                  =                  (                  uint8_t                  )                  fmin                  (                  0.349                  *                  *                  p                  +                  0.686                  *                  *                  (                  p                  +                  i                  )                  +                  0.168                  *                  *                  (                  p                  +                  two                  ),                  255.0                  );                  // light-green                  18                                    *                  (                  pg                  +                  ii                  )                  =                  (                  uint8_t                  )                  fmin                  (                  0.272                  *                  *                  p                  +                  0.534                  *                  *                  (                  p                  +                  i                  )                  +                  0.131                  *                  *                  (                  p                  +                  ii                  ),                  255.0                  );                  // blue                                    19                                    if                  (                  channels                  ==                  four                  )                  {                  20                                    *                  (                  pg                  +                  iii                  )                  =                  *                  (                  p                  +                  3                  );                  21                                    }                  22                                    }                  23                                    24                                    stbi_write_jpg                  (                  "sky_sepia.jpg"                  ,                  width                  ,                  height                  ,                  channels                  ,                  sepia_img                  ,                  100                  );                  25                                    26                                    27                                    // ...                                    28                                    }                              

Y'all tin notice a complete example of loading an image and converting it to gray and sepia as t1.c in the repo for this article.

Writing a wrapper around the stb_image functions

In this part of the article we are going to abstract the lawmaking presented before to a small-scale prototype library. The reward of using a small abstraction over directly calling the stb_image functions is that nosotros can put all image related data in a structure and write some utility functions that manipulate the Prototype struct. Nosotros can also reduce the possibility of user errors by presenting a simpler interface.

There is likewise a video version of this role of the tutorial:

We'll start by writing the Image header file which comprise the public interface for our small library:

                                                                        1                                    #pragma once                                      2                                                        three                                    #include                  <stdlib.h>                                                        4                                    #include                  <stdint.h>                                                        five                                    #include                  <stdbool.h>                                                        6                                                        seven                                    enum                  allocation_type                  {                                      eight                                    NO_ALLOCATION                  ,                  SELF_ALLOCATED                  ,                  STB_ALLOCATED                                      ix                                    };                  10                                    11                                    typedef                  struct                  {                  12                                    int                  width                  ;                  xiii                                    int                  height                  ;                  14                                    int                  channels                  ;                  15                                    size_t                  size                  ;                  16                                    uint8_t                  *                  data                  ;                  17                                    enum                  allocation_type                  allocation_                  ;                  18                                    }                  Epitome                  ;                  nineteen                                    20                                    void                  Image_load                  (                  Image                  *                  img                  ,                  const                  char                  *                  fname                  );                  21                                    void                  Image_create                  (                  Image                  *                  img                  ,                  int                  width                  ,                  int                  height                  ,                  int                  channels                  ,                  bool                  zeroed                  );                  22                                    void                  Image_save                  (                  const                  Prototype                  *                  img                  ,                  const                  char                  *                  fname                  );                  23                                    void                  Image_free                  (                  Image                  *                  img                  );                  24                                    void                  Image_to_gray                  (                  const                  Paradigm                  *                  orig                  ,                  Epitome                  *                  gray                  );                  25                                    void                  Image_to_sepia                  (                  const                  Epitome                  *                  orig                  ,                  Epitome                  *                  sepia                  );                              

The Image struct from the in a higher place header file is self explanatory, you can find information technology every bit Prototype.h in the article repo. The last field of the Image struct, the allocation blazon enumeration, is used to record if the memory was allocated past the user or by one of the stb_image functions.

Adjacent, we accept utility functions to load, create, relieve and free an image. For simplicity, nosotros've assumed that the user will relieve to disk just PNG or JPG images. The code can be easily extended with other output functions from the stb_image_write or with new functions written by the user.

The terminal two functions from Image.h are used to convert an input epitome to gray or sepia. Nosotros basically, have the code written in t1.c and put it in split functions. These two functions volition also allocate the necessary memory for the output image.

The actual implementation of the higher up functions is in Image.c. The implementation code is basically a modified version of the code from t1.c, so information technology won't exist presented in the article.

Hither is an example of using the above library to load two input images: sky.jpg and Shapes.png, convert the images to gray and sepia, save the output images and free the retention used for storing the input and output images:

                                                                        1                                    #include                  "Image.h"                                                        2                                    #include                  "utils.h"                                                        3                                                        4                                    int                  main                  (                  void                  )                  {                                      5                                    Paradigm                  img_sky                  ,                  img_shapes                  ;                                      vi                                                        7                                    Image_load                  (                  &                  img_sky                  ,                  "heaven.jpg"                  );                                      8                                    ON_ERROR_EXIT                  (                  img_sky                  .                  data                  ==                  Naught                  ,                  "Fault in loading the paradigm"                  );                                      ix                                    Image_load                  (                  &                  img_shapes                  ,                  "Shapes.png"                  );                  10                                    ON_ERROR_EXIT                  (                  img_shapes                  .                  data                  ==                  NULL                  ,                  "Error in loading the image"                  );                  11                                    12                                    // Convert the images to gray                  13                                    Paradigm                  img_sky_gray                  ,                  img_shapes_gray                  ;                  14                                    Image_to_gray                  (                  &                  img_sky                  ,                  &                  img_sky_gray                  );                  15                                    Image_to_gray                  (                  &                  img_shapes                  ,                  &                  img_shapes_gray                  );                  16                                    17                                    // Convert the images to sepia                  18                                    Image                  img_sky_sepia                  ,                  img_shapes_sepia                  ;                  nineteen                                    Image_to_sepia                  (                  &                  img_sky                  ,                  &                  img_sky_sepia                  );                  twenty                                    Image_to_sepia                  (                  &                  img_shapes                  ,                  &                  img_shapes_sepia                  );                  21                                    22                                    // Save images                  23                                    Image_save                  (                  &                  img_sky_gray                  ,                  "sky_gray.jpg"                  );                  24                                    Image_save                  (                  &                  img_sky_sepia                  ,                  "sky_sepia.jpg"                  );                  25                                    Image_save                  (                  &                  img_shapes_gray                  ,                  "Shapes_gray.png"                  );                  26                                    Image_save                  (                  &                  img_shapes_sepia                  ,                  "Shapes_sepia.png"                  );                  27                                    28                                    // Release memory                  29                                    Image_free                  (                  &                  img_sky                  );                  30                                    Image_free                  (                  &                  img_sky_gray                  );                  31                                    Image_free                  (                  &                  img_sky_sepia                  );                  32                                    33                                    Image_free                  (                  &                  img_shapes                  );                  34                                    Image_free                  (                  &                  img_shapes_gray                  );                  35                                    Image_free                  (                  &                  img_shapes_sepia                  );                  36                                    }                              

A special mention virtually utils.h used in the to a higher place code, this header file contains an error checking helper macro that, in case of error, will print the calling role and line number were the error was detected. You can observe the above lawmaking every bit t2.c in the commodity repo.

If you lot want to learn more than nigh C99/C11 I would recommend reading 21st Century C: C Tips from the New Schoolhouse by Ben Klemens:

or the classic C Bible, The C Programming Linguistic communication by B.Westward. Kernighan, D.M. Ritchie:



How To Read Data From Image File In C#,

Source: https://solarianprogrammer.com/2019/06/10/c-programming-reading-writing-images-stb_image-libraries/

Posted by: bustillosclaill1953.blogspot.com

0 Response to "How To Read Data From Image File In C#"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel