Click here to Skip to main content
15,072,134 members
Please Sign up or sign in to vote.
2.00/5 (2 votes)
See more:
hey friends
I tried to convert image pgm (greyscale) to image black and white (0 or 255) two color
I did it by python language because its so easy to convert! after I see all pixel in python and the run is good , I seen only two value 255 and 0 and I opened the image by GIMP and its all ok
-after I tried to see all pixel in c language but the display is false I seen print different than the print by python , I not seen two color only I see many value in pixel 11, 200 , 23, ...
I sow to you my tried I c and python language , please what my wrong !?

What I have tried:

// read_image_line_by_line.cpp : Defines the entry point for the console application.

#include "stdafx.h"
#include <stdio.h>
void func()
    FILE *pFile;
    pFile = fopen("result.pbm", "rb");
	char c;
	do {
     c= getc (pFile);
    } while (c != EOF);

int _tmain(int argc, _TCHAR* argv[])

from PIL import Image
image_file ="lena512.pgm") # open colour image
image_file = image_file.convert('1') # convert image to black and white'result.pbm')
widh , heigh =image_file.size
print (widh)
print (heigh)
pixel_values = list(image_file.getdata())
print (pixel_values)</conio.h></stdio.h>
Updated 8-Jun-16 0:10am
Kornfeld Eliyahu Peter 8-Jun-16 5:36am
In C you are reading the file as binary, while in Python you handle it as image!!!
yagami_md 8-Jun-16 5:52am
you wrong understand me !! in I want read in c image in pbm format , 0 or 1 egg, black or white because I need that in my project !! you can tried that in python and c language and you see the difference
Kornfeld Eliyahu Peter 8-Jun-16 5:55am
I may not understand you, but I do understand that code of yours - perfectly...
The C code you present here reads the file as binary and not as bitmap image, so you will see a lot of other things than pixels of black and white...
Richard MacCutchan 8-Jun-16 5:49am
You cannot read image files as bytes, they contain structured content.

1 solution

See The PBM Format[^].

The PBM file contains a printable ASCII header and the pixels as packed binary data. With your Python code you are creating a list from the pixel data (without header) and printing these values. I did not know what python is doing internally but I guess it creates a list of bytes (or integers) from the packed data.

In your C code you are printing the ASCII header and the packed data as they are. To get a similar output, skip the header in your C code and unpack the data bytes:
// Read header here and get width and height of image

int stride = width % 8;
for (int i = 0; i < height; i++)
    for (int j = 0; j < width / 8; j++)
        unsigned data_byte = (unsigned)getc(pFile);
        for (int k = 0; k < 8; k++)
            // Maybe the order of bits is wrong here.
            // If so check with mask 0x80 and shift left.
            // EDIT: Black is 1 and white is zero!
            printf("%d,", (data_byte & 1) ? 0 : 255);
            data_byte >>= 1;
    if (stride)
        unsigned data_byte = (unsigned)getc(pFile);
        for (int k = 0; k < stride; k++)
            // Again: Maybe the order of bits is wrong here.
            printf("%d,", (data_byte & 1) ? 0 : 255);
            data_byte >>= 1;

To parse the header it would be better to read the whole file content into memory (code is not tested but compiles):

#include <stdio.h>
#include <io.h>
#include <ctype.h>

// ...

FILE *pFile = fopen("result.pbm", "rb");
// NOTE: With Microsoft compilers these functions might require a 
//  leading under score (_filelength, _fileno)
long file_len = filelength(fileno(pFile));
unsigned char *buffer = (unsigned char *)malloc(file_len);
fread(buffer, 1, file_len, pFile);

const char *header = (const char *)buffer;

// Skip magic number "P4"
while (isalnum(*header)) header++;
// Skip white spaces
while (isspace(*header)) header++;
// Get width
int width = atoi(header);
// Skip width
while (isdigit(*header)) header++;
// Skip whitespace
while (isspace(*header)) header++;
int height = atoi(header);
// Skip height
while (isdigit(*header)) header++;
// Skip single whitespace

// Pointer to first data (pixel) byte
const unsigned char *data = (const unsigned char *)header;
// Extra byte per row if width is not a multiple of 8
int stride = width % 8;
for (int i = 0; i < height; i++)
    for (int j = 0; j < width / 8; j++)
        unsigned data_byte = *data++;
        for (int k = 0; k < 8; k++)
            // Maybe the order of bits is wrong here.
            // If so check with mask 0x80 and shift left.
            // EDIT: Black is 1 and white is zero!
            printf("%d,", (data_byte & 1) ? 0 : 255);
            data_byte >>= 1;
    if (stride)
        unsigned data_byte = *data++;
        for (int k = 0; k < stride; k++)
            // Again: Maybe the order of bits is wrong here.
            printf("%d,", (data_byte & 1) ? 0 : 255);
            data_byte >>= 1;
CPallini 8-Jun-16 6:22am
yagami_md 8-Jun-16 6:30am
friend I liked your solution , because you understand what I want , but please how I can out the header only and the packet only? can you modify my code in c language with your code
Jochen Arndt 8-Jun-16 6:33am
By parsing the header. I will update my solution but this will took some time because it can be better done by reading the whole file content.
yagami_md 8-Jun-16 6:41am
please you can give me image pmb , because I do not find , i'm convert into python language
Jochen Arndt 8-Jun-16 6:59am
I do not understand now what you want. Do you want to perform the conversion with C?

Then use similar code as from my updated solution to read the PGM file, write the PBM header, and loop through the rows and columns to create the packed PBM data and write them.
yagami_md 8-Jun-16 7:23am
your code is not easy !!
Jochen Arndt 8-Jun-16 7:31am
I don't think so. It should be understandable by everyone having some knowledge in C. But feel free to ask where you have problems.

Some explanations:

First block is reading a file into allocated memory. This is a common task.

Second block parses ASCII text and converts text to numbers. Common too.

Third is processig binary data according to the file format specification. Looping through rows and columns and unpacking binary data is common too.
Richard MacCutchan 8-Jun-16 8:29am
Quote: A raster of Height rows, in order from top to bottom. Each row is Width bits, packed 8 to a byte, with don't care bits to fill out the last byte in the row. Each bit represents a pixel: 1 is black, 0 is white. The order of the pixels is left to right. The order of their storage within each file byte is most significant bit to least bit. The order of the file bytes is from the beginning of the file toward the end of the file.
Jochen Arndt 8-Jun-16 8:33am
You want me to find my error by reading it again?

I got it. Black is 1 and white is 0!

Thank's Richard.
yagami_md 8-Jun-16 8:42am
I have some error :
fread+fclose+data_byte error is : "this declaration has no storage class or type specifier"
while error is : "expected a declaration"
Jochen Arndt 8-Jun-16 8:48am
You must put the complete code into a function (e.g. into func()):

// Include files here

void func()
// Insert the code here

I just posted the code portions to be used.
yagami_md 8-Jun-16 9:11am
thank you so much brother , but I have a question , if I rebuilt the image , it means after put my file result.pbm , and convert to blck and white you can give me the code for see my image after this processing? ad thnks
Jochen Arndt 8-Jun-16 9:22am
What do you mean by see the image?
Do you want to display the image using C code?

If so you should raise a new question. But you should add information about the operating system and the used GUI (if any and not using Windows). In general GUIs and graphic libraries for console programs supports only a few image formats. They are all working internally with binary pixel formats and can convert a set of image formats. If the PBM format is not supported, it must be converted first to a supported format.
yagami_md 8-Jun-16 19:28pm
I use windows 10 and visual studio 2010 ,
for to be clear , I need to convert my image pgm to pbm (black and white) because I work with the coding canal , my work is :
1:input the image (pgm: greyscale)
2:convert image to 2 byte only 0 or 1 binary
// coding function (input(my image binary),output(another file contains binary for transfer in channel)
I have the coding work with pgm image but I need to read the image in binary it mans like a pbm format
nota: it must too to not deete the header of the image because in decoding processing I must to rebuilt the initial image
-- I add this for saved to file.pbm "fprintf(Image,"%d",(data_byte & 1) ? 1 : 0);"
and I tried to opened this file.pbm by GIMP programs but I can't !!
I think that we must convert the header?
Jochen Arndt 9-Jun-16 3:25am
You have to read the PGM format specifiaction at and write a function that converts a PGM to a PGB.

This requires these steps:
- Read the PGM file into memory like in my PGB example.
- Parse the header like in my PGB example but don't forget to add code for the additional max. gray value.
- Open the output PBM file in binary mode
- Write the header to the PBM file using fprintf:
  fprintf("P4\n%d %d\n", width, height)
- Loop through the binary PGM data ;
-- Row loop
--- Column loop, increment is 8
---- Create packed PBM byte from 8 PGM pixel data
---- Write byte to PBM file: fwrite(&packed_byte, 1, 1, pOut);
- Cleanup (close files and release memory)

I could add some code to my answer but it would be better to raise a new question. Because you are using Visual C it would be also better to use C++ rather than plain C (C functions can still be usud inside C++ modules).
yagami_md 9-Jun-16 7:09am
good morning
my project is on c language not c++
please i'm sorry but can you update to be convert too the headers for it can be opened it means convert to binary P5 and widh and height because I need it when I will rebuilt the initiai image
Jochen Arndt 9-Jun-16 7:33am
Updating my answer would make this thread more confusing as it is already.

You might raise a new question (convert PGM to PBM) and show what you have done so far. I might answer. But all here are answering voluntary on their own time without being paid.

For that reason requests to get complete code written by others is not well received here. This is also indicated by "quick answers".

Another reason is that you won't learn much if the work is done by others. I don't know your background. But if you are going to become a programmer and will use C in the future, you should try to do it yourself. If you than get stuck, you will get vaulable help here.
yagami_md 10-Jun-16 6:58am
in this 2 last days i learn about image processing , please friend i have idea i can read the pixel in image by table 2D? it means convert image to table 2D ?
Jochen Arndt 10-Jun-16 7:03am
There is no need to do so.
Just access a 1D table using table1[row * width + col].
This similar to acessing a 2D table2[row][col].
yagami_md 10-Jun-16 7:46am
yes thnk you somuch :) but I tried to change your code , idont know why you delete the header of image ? I so importanat think that why I can't open the image with image editor!!
Jochen Arndt 10-Jun-16 7:53am
My answer was for the initial question:
Why my C code does not print the same as the Python code.

I do not delete the header. I'm parsing it to get the required information (height and width). That's all what the code is doing:
Printing the same as the Python code.

The conversion itself must be done as described some comments above.
yagami_md 10-Jun-16 8:10am
yes friend but until now I don't understand why the read is different between c and python, ? is norml in read the ascii it means in console I will see just ascii 0 is 48 and ascii 255 I y !!! you can explain me why?
Jochen Arndt 10-Jun-16 8:27am
Because you are using the Python Imaging Library (PIL) which provides high level functions to handle images.

With C, you are just accessing the file as it is (a bunch of binary bytes). It is up to you know what these bytes mean (defined by the file format) and how to handle them for the operations you want to be applied.

The PIL will do that for. It reads the file as binary, determines the image type (e.g. PGM, PBM, PNG, JPEG), parses the header to determine the dimensions and other information, stores that information internally, and provides a pointer to access the payload (the pixel values). It offers functions to convert to other image formats and writing that to a valid file.

In fact the PIL itself is written in C (you can get the sources). But it relies on other libraries and reading such sources requires good C and image format knowledge.
yagami_md 10-Jun-16 8:59am
so what you think I can use Opencv library too in c for get same resut?
Jochen Arndt 10-Jun-16 9:07am
You can use any library that supports the required operations. I'm not sure if OpenVC supports PBM and PGM files.

If you only need the conversion PGM to PBM here it might be simpler to write it in C rather than using a big library.

Alternatively you can install ImageMagick. That provides command line tools for conversions and supports PBM and PGM.
yagami_md 10-Jun-16 9:54am
my problem is in coding processing I must enter not normal image but only binary 0 or 1 , I tried to work with pgm format and after I convert all pixel to binary but the file wwill be big 512*512*8 byte , I searched in google and I found that pbm format is binary , I tried to go online and convert pgm image to pbm and its all oki and I seen the image in GIMP and it black and white , next step I go to c and I see all ixel by
while c=getc(*fil) but I seen in console that pixel not 0 or 1 only !!!!!
in my project I must put image and convert it to binary!!!its just my work
Jochen Arndt 10-Jun-16 10:07am
It seems that you still not understand the used image format and how C can be used to print the content in a readable form.

You have converted the PGM file to PBM using python. The file is OK (loaded by GIMP). The code from my solution does nothing else than these Python lines:

image_file ="result.pbm")
width , heigh =image_file.size
pixel_values = list(image_file.getdata())
print (pixel_values)

The C getc() function will read a byte from the file. But the first bytes are (printable) ASCII characters (the header) and the follwing pixel values are packed (each byte contains the data of 8 pixels).

If you have 8 black pixels in a row, such a byte would be zero. If you have 8 white pixels it would be hex 0xff / decimal 255 / binary 11111111. If you have alternating black and white it may be 0x55 (01010101). If you print such a byte it can contain all values from 0 to 255 (0xff).

You must understand this before trying to program.
Read about bits, bytes and characters. Then how these are used (here in the PGM and PBM files).

What you are seeing is (probably) correct. But you don't know how to interpret what you are seeing.
Richard MacCutchan 8-Jun-16 8:53am
No, it was just the comment in your code about bit order.
Jochen Arndt 8-Jun-16 9:05am
Oh that. I was (and I'm still) too lazy to think about it:
Is the MSB of the byte the left-most or right-most pixel here?

From my point of view the description is not really clear here but it can be simply verified by comparing with the output from the Python code.
Richard MacCutchan 8-Jun-16 9:07am
Bit 0 is the rightmost, thus LSB. So MSB to LSB is right to left. I assume.
yagami_md 12-Jun-16 19:44pm
hey sir jochen :)
in the last 2 days I learned about opencv librry in c and I succed to get a image binary black and white but my problem is in the header , so I want when I read the image , the header be alone and data be alone :)
header in file and data in file :)
Jochen Arndt 13-Jun-16 4:29am
It is not clear what you mean.
If you use OpenVC, it will do it for you and should provide functions to access the image properties (read from the header) and the pixel data. Similar when writing an image file with OpenVC: It will create the header and the payload and write them to a file.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900