29

How can I read a gray scale JPEG image file in C/C++ into a 2D array?

Thomas Fritz
  • 140
  • 2
  • 10
skyrulz
  • 367
  • 1
  • 5
  • 6
  • Is the documentation for libjpeg (http://www.ijg.org/) or whatever native API you have inadequate? – greyfade Jan 16 '10 at 07:01
  • 3
    Don't forget to pick a correct answer for the three questions you've asked. – mwcz Jan 20 '10 at 14:33
  • Check this thread out: [read and write image file](http://web.archive.org/web/20080625002549/http://www.dreamincode.net/forums/showtopic29852.htm). Also, have a look at [this other question at Stackoverflow](https://stackoverflow.com/questions/1533542/opencv-cant-read-image). – Lazer Jan 25 '10 at 15:56

6 Answers6

26

If you decide to go for a minimal approach, without libpng/libjpeg dependencies, I suggest using stb_image and stb_image_write, found here.

It's as simple as it gets, you just need to place the header files stb_image.h and stb_image_write.h in your folder.

Here's the code that you need to read images:

#include <stdint.h>

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

int main() {
    int width, height, bpp;

    uint8_t* rgb_image = stbi_load("image.png", &width, &height, &bpp, 3);

    stbi_image_free(rgb_image);

    return 0;
}

And here's the code to write an image:

#include <stdint.h>

#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"

#define CHANNEL_NUM 3

int main() {
    int width = 800; 
    int height = 800;

    uint8_t* rgb_image;
    rgb_image = malloc(width*height*CHANNEL_NUM);

    // Write your code to populate rgb_image here

    stbi_write_png("image.png", width, height, CHANNEL_NUM, rgb_image, width*CHANNEL_NUM);

    return 0;
}

You can compile without flags or dependencies:

g++ main.cpp

Other lightweight alternatives include:

Jaime Ivan Cervantes
  • 3,579
  • 1
  • 40
  • 38
  • 2
    I had to include the math.h library and link it while compiling (http://stackoverflow.com/questions/8671366/undefined-reference-to-pow-and-floor) or I would get an undefined reference to pow in the image library. – Ste_95 Feb 08 '17 at 16:03
  • 2
    I know it's just an example but can you clarify what the magic number 3 means in the code? – mattshu Jan 24 '18 at 04:56
  • 2
    @mattshu it's the number of channels (red, green, blue), maybe I should clarify this on my code, I'll do a edit. – Jaime Ivan Cervantes Jan 25 '18 at 02:41
  • How would I do something like this WITHOUT any odd libraries? I am not the author of the question, but I want to know how to this only using standard libraries like stdio.h Actually, how to do this ONLY using stdio.h? –  Jan 16 '20 at 17:32
  • STB developers ain't good. – tripulse Oct 20 '20 at 10:23
  • How do I store the result in a 3D array, with the third dimension being the channel? – user3236841 Apr 02 '22 at 02:28
15

You could write your own by looking at the JPEG format.

That said, try a pre-existing library like CImg, or Boost's GIL. Or for strictly JPEG's, libjpeg. There is also the CxImage class on CodeProject.

Here's a big list.

GManNickG
  • 494,350
  • 52
  • 494
  • 543
  • 2
    Boost.GIL does not work and is not being maintained. – Tronic Jan 25 '10 at 15:59
  • 2
    Since C is allowed, I second libjpeg as the most lightweight solution. CImg and GIL are definitely easier syntax-wise--but also require libjpeg. You can trivially copy the data from a CImg object into some STL container or an array. – jiggunjer Jun 30 '15 at 15:24
  • 1
    CImg also uses an LGPL-like license which is significantly more restrictive than libjpeg's BSD-like license. – TypeIA Oct 07 '16 at 15:38
  • @Tronic I see it still being maintained https://github.com/boostorg/gil – phuclv Jun 08 '23 at 05:00
4

Check out Intel Open CV library ...

Ashish
  • 8,441
  • 12
  • 55
  • 92
3

corona is nice. From the tutorial:

corona::Image* image = corona::OpenImage("img.jpg", corona::PF_R8G8B8A8);
if (!image) {
  // error!
}

int width  = image->getWidth();
int height = image->getHeight();
void* pixels = image->getPixels();

// we're guaranteed that the first eight bits of every pixel is red,
// the next eight bits is green, and so on...
typedef unsigned char byte;
byte* p = (byte*)pixels;
for (int i = 0; i < width * height; ++i) {
  byte red   = *p++;
  byte green = *p++;
  byte blue  = *p++;
  byte alpha = *p++;
}

pixels would be a one dimensional array, but you could easily convert a given x and y position to a position in a 1D array. Something like pos = (y * width) + x

Firas Assaad
  • 25,006
  • 16
  • 61
  • 78
2

Try out the CImg library. The tutorial will help you get familiarized. Once you have a CImg object, the data() function will give you access to the 2D pixel buffer array.

mwcz
  • 8,949
  • 10
  • 42
  • 63
1

Check out the Magick++ API to ImageMagick.

R Samuel Klatchko
  • 74,869
  • 16
  • 134
  • 187