2

I've been looking for a code in C++ which gets me the RGB values of all pixels of a png file.

So I searched a lot through the internet and found different ways of doing such a thing, like using libpng , OpenCV, Magick++, CImg , etc. and I just decided to go with the CImg one (mostly because I don't know how to use OpenCV although I searched a lot about how to install and use it in Code::Blocks and it just has something to do with mingw64 which the installer I downloaded from Sorceforge, keeps giving me errors in the middle of downloading some files, and about the rest of them I just can't find the appropriate header file (like Magick++.h) which's compatible with Code::Blocks... So if you think some of these would be better and simpler than CImg.h, then I'd appreciate if you provided me a download link of the header or any other necessary thing)

So here is the code I found with Cimg :

#include <windows.h>
#include <iostream>
using namespace std;

#include <CImg.h>
using namespace cimg_library;

int main()
{
CImg<unsigned char>src("twittericon.png");
int width = src.width();
int height = src.height();
cout << width << "x" << height << endl;
for (int r = 0; r < height; r++)
for (int c = 0; c < width; c++)
   cout << "(" << r << "," << c << ") ="
        << " R" << (int)src(c,r,0,0)
        << " G" << (int)src(c,r,0,1)
        << " B" << (int)src(c,r,0,2) << endl;
return 0;
}

But the problem is after running the program, it gives me the error : CImg::load(): Failed to recognize format of file 'twittericon.png' 

What should I do with the error?

And by the way, do you know any better way to read these RGB values of a png file? If you do, could you please also provide me a little bit of an instruction for it? Thanks.

mitrafrz
  • 51
  • 6
  • 2
    Google Search: "MSDN SetDIBitsToDevice", click on the 1st link, go to the table at the bottom of the page and include the library in your linker settings. All of the Win32API functions are listed on the MSDN site with required headers and libraries. – Richard Critten Feb 14 '18 at 14:08
  • I added the line: #include And I downloaded Gdi32.lib and added it to Linker Settings in my compiler settings. Now there's no error in running the program, but afterwards, it gives this error instead: CImg::load(): Failed to recognize format of file 'twittericon.png' Now what should I do? Doesn't it work with png file? – mitrafrz Feb 14 '18 at 22:41
  • 1
    You have to install `libpng` to read/write PNG files. I suspect you would be better off installing **ImageMagick** instead though, because CImg can use that to read most file formats for you. Remember to tick the option *"Install Legacy tools"* when installing **ImageMagick**. – Mark Setchell Feb 14 '18 at 23:32
  • Could you please help me with which one to download? I'm using windows 10, C++, and Code::Blocks in case you need. https://www.imagemagick.org/script/install-source.php – mitrafrz Feb 15 '18 at 14:48
  • You don't need to install the source. You can use the ready-built binaries, it's easier. – Mark Setchell Feb 15 '18 at 15:37
  • Okay so I need to download and install this : ImageMagick-7.0.7-22-Q16-x64-dll.exe ? Sorry for asking a lot of questions I'm just so beginner in this... I'd be really grateful if you enlightened me a little bit more about it – mitrafrz Feb 15 '18 at 19:43
  • What is it you are actually trying to do overall? Do you want to just read the RGB values of one single PNG file once? Or are you writing a large, general purpose image processing system that you will use for years and needs to be able to read many file formats? What sort of processing do you need to do? – Mark Setchell Feb 15 '18 at 20:34
  • Could you please have a try at answering the question above before asking any more - else I have to keep answering 3 times over to cover all eventualities :-) – Mark Setchell Feb 16 '18 at 10:50

1 Answers1

1

There are many ways to get the RGB pixel values in a PNG file, and the best one depends what your actual usage scenario is.


Option 1

If you have one or two PNG files and you just want to get the RGB pixels easily one time, then I would suggest you install any of the ready-built ImageMagick binaries you have already given links for. Then we can make a test PNG file like this at the command line in Terminal or Command Prompt:

convert xc:red xc:lime xc:blue +append \( xc:cyan xc:magenta xc:yellow +append \) -append image.png

and it will look like this (just smaller):

enter image description here

(I think you omit the backslashes under Windows in the above command)

Ok, now you want to see the RGB values, so you can either dump the file as text:

convert image.png -depth 8 txt:

Sample Output

# ImageMagick pixel enumeration: 3,2,65535,srgb
0,0: (65535,0,0)  #FF0000  red
1,0: (0,65535,0)  #00FF00  lime
2,0: (0,0,65535)  #0000FF  blue
0,1: (0,65535,65535)  #00FFFF  cyan
1,1: (65535,0,65535)  #FF00FF  magenta
2,1: (65535,65535,0)  #FFFF00  yellow

Or, you can convert the file to the venerable (but superb) NetPBM format Wikipedia description of NetPBMin ASCII mode:

convert image.png -compress none image.pnm

Now you get a file like this that you can easily read:

P3                              # PPM in ASCII mode
3 2                             # width=3 height=2
255                             # 8-bit
255 0 0 0 255 0 0 0 255 
0 255 255 255 0 255 255 255 0 

If you omit the -compress none you will get the same file but the RGB data will be in 8-bit unsigned binary and then the whole file is very easy to read in C/C++. In fact, CImg knows how to read/write these anyway.

So, you could feasibly, convert any images (TIF, BMP, JPEG, GIF) you want to access into NetBM PPM files in advance and just read and write PPM files using the built-in routines in CImg. Job done!


Option 2

At the next level, you could install ImageMagick from the pre-built binaries on the ImageMagick website and then use CImg. CImg will then locate ImageMagick's convert/magick program use that to convert anything it can't read itself on its behalf. That way you get instant access to around 200+ formats that ImageMagick knows about - for free.


Option 3

Alternatively, you could build and install libpng and then when you write code with CImg you define a macro before including CImg.h and it uses libpng to read and write PNG files.

That is quite a lot of trouble to go to when you could just let ImageMagick do all the work, and at the end of it you only get PNG support not 200+ formats for all that work.

This scenario looks like this:

#define cimg_use_png 1
#include "CImg.h"
...
...

You would compile with:

c++ -I CIMG_DIRECTORY -L LIBPNG_DIRECTORY -lpng -lz

I did another answer, using this option for libjpeg and getting CIMg to read and write JPEGs. I can only say it was a total pain - that answer is here.

Mark Setchell
  • 191,897
  • 31
  • 273
  • 432
  • Sorry again for asking endless questions, as I already said, I'm just a beginner (who's so grateful for your guide though:) ) So here goes the first question, what exactly is this line in the Option 1 section about? : `convert xc:red xc:lime xc:blue +append \( xc:cyan xc:magenta xc:yellow +append \) -append image.png` and the 2nd question would be the same as first question, but about this line: `convert image.png -compress none image.pnm` As it seems, these are not commands, so what are they? Better say, how should the code look like (it may seem too stupid, but I just don't get it:( ) – mitrafrz Feb 15 '18 at 23:23
  • And is there anything else I need to do rather than installing ImageMagick and copying Include folder contents from its installation directory, to the Include folder in Code::Blocks installation directory, and then adding the line `#include ` to the beginning of my code? Because that's all I did (all I knew I was supposed to do) And about the Option 2 part, in which CImg uses ImageMagick for conversions, what do you mean by `convert/magick` ? Is it going to be a part of the code I mentioned at first? (GOD IM SO SO SORRY IF IM CAUSING YOU A HEADACHE!:( ) – mitrafrz Feb 15 '18 at 23:56
  • No problems, we are all learning. Q1) You just type that command into a Terminal, or Command Prompt, or DOS Box, or whatever Windows calls it when you type in commands like `DIR`. – Mark Setchell Feb 16 '18 at 07:10
  • Q3) No, do not `#include Magick++.h` that is experimental and unnecessary. – Mark Setchell Feb 16 '18 at 07:27
  • Q4) At version 7 of **ImageMagick**, the command you type to run it in the Command Prompt changed from `convert` (v6) to `magick` (v7). If, when you install v7, you check the box labelled `Install legacy tools`, you will be able to use `magick` or `convert` at the commandline. If you do not check that box, you will only be able to use `magick`. – Mark Setchell Feb 16 '18 at 07:32
  • And one more question, how can I save the color codes in a 2D array? – mitrafrz Feb 16 '18 at 10:38
  • Not sure what you mean by a 2-D array. Your image has 3 dimensions, height, width and colour channel surely? It is already in an array if you use `CImg` - what do you think `src(c,r,0,0)` in your program is? – Mark Setchell Feb 16 '18 at 10:41
  • First of all, as I've said twice, I'm so much of a beginner in this, and that it's the very first time I'm working with 'files' (at school !) So about that code, I do have some questions, and yes one of them would be: what is `src(int,int,int,int)`? All I can guess is it's just an abbreviation for 'Source' or something? And even if it is so, what's the usage of it? Because we've recently just learned about files and done a bit of a coding with **fstream** , so this question just pops into my mind that why can't we just use `ifstream` to get the png file, and what exactly is `src` doing? – mitrafrz Feb 16 '18 at 12:39
  • And about the 2D array, I meant a height×width array, having the hex color codes saved in, e.g. I want FF0000 to be saved for the Red color instead of saving all 3 codes of 255,0,0. How can I do that? – mitrafrz Feb 16 '18 at 12:39
  • `src()` is effectively an array already. You access the red pixel with `src(c,r,0,0)`, and the green one with `src(c,r,0,1)`. There is no need to store everything twice. If you want to see hex, just do `std::cout << std::hex << src(c,r,0,0) << std::endl;` – Mark Setchell Feb 16 '18 at 12:56
  • Thanks and one more question... what is that third 0 in src(c,r,**0***,0) ? – mitrafrz Feb 16 '18 at 16:45
  • Leave it at zero. `CImg` is able to deal with 3-D volumetric shapes, like CT (Computed Tomography) scans, and that zero is the index for the Z-axis. – Mark Setchell Feb 16 '18 at 17:22