Can't get value from an array (c) - c

I'm reading a code from a ppm file and store the value of each pixel in p1, array of pixel, which is a struct of .red .green .blue (int). I managed to create a "Negative Filter" of the picture, however. I'm trying to get a black and white by taking the mean of red, green, and blue pixel.
I have pixel p1, pixel p2(negative filter) and int p3(b&w). However every action that have p3 = ...., will stop responding. such as
for (i = 0; i < WIDTH; i++) {
for (j = 0; j < HEIGHT; j++) {
p3[i][j] = ((p1[i][j].red + p1[i][j].green + p1[i][j].blue)/3);
}
}
or
for (i = 0; i < WIDTH; i++) {
for (j = 0; j < HEIGHT; j++) {
fprintf(pf3, "%d", p3[i][j]);
}
}
However when I change int p3[WIDTH][HEIGHT] to char p3[WIDTH][HEIGHT], the program runs but gives a wrong output. Both int and char, compiled successfully. Can someone help me? thanks.
EDIT:
What I'm hoping is I could create a .pgm black and white extension of picture from .ppm by inputting .ppm value to pixel p1[WIDTH][HEIGHT] in .red, .green, and .blue. Then calculate the mean of RGB and assign it in int p3 before being written in .pgm.
What I got when using int p3, it crashes when I run the .exe stopped working without giving any error.
When I use char p3, it run perfectly, but it gives all negative value for the mean of all the pixel. (This already being helped by putting unsigned infront of the char thanks to #egoteclair)
My new question would be why can't I use int instead of unsigned char?

Normal char size is 8-bit. The first bit will be used for the sign extension. In a 24 bit png file each color-field contains 8 bits.
24 / 3 = 8
So try to use unsigned char instead of char. This allows you to use the complete 8 bits of the char.

Related

Understanding fread() to store rgb pixel values

The for loop should be replaced with a fread I believe, however, I am very unclear on how fread will work.
How does fread know the value of green pixel # given location and where to save the value. My understanding is that I have a chunk of heap memory, a rectangle has a tbd number of pixels. Each pixel has 3 values. How will fread (or any other method I can use)?
If anyone could just explain how the fread line below would work with my code? This is for an assignment, I am just trying to understand what is going on since it is one we will be building on.
fread(pixelD, sizeof(Pixel), width*height, file);
typdef struct
{
unsigned char green;
unsigned char blue;
unsigned char red;
}pixelD;
typedef struct
{
pixelD * pixel;
} Color;
Image * ReadImage(char *filename)
{
int width, height, maxval;
int imgSize = width * height * sizeof(pixel);
//fscanf line was given by prof
fscanf(f_in, "%s\n%d %d\n%d\n", magicNum, &width, &height, &maxval);
pixel = malloc(imgSize);
for(int i = 0; i <imgSize; i++)
{
pixel.green = pixel[i]; ????
pixel.blue = ;
pixel.red = ;
}
}
From the looks of it you are reading a PPM file.
Read the header doing something like this:
int width, height, max;
my_assert(3==fscanf(f_in, "P6%d%d%d ", &width, &height, &max));
/* TODO: error handling */
The format specifiers tells it to read the expected magic number ("P6"), then second, third and fourth words as integers (implicitly skipping any whitespace between), and then consume a whitespace ("mostly a newline" according PPM) to set the file read position to where the binary data starts. You should probably make sure width/height/max being within what your application expects and can cope with.
And then read the rest of the data into memory. fread read from the current read position size*count bytes; no formatting:
int channel_width = max < 256 ? 1 : 2; /* PPM channel width can be either 1- or 2-byte */
int rgb = 3;
int imgsize = width*height*rgb*channel_width;
void* texture = malloc(imgsize);
my_assert(imgsize==fread(texture, 1, imgsize, f_in));
/* do something with the texture memory */
At that point you can just cast the texture pointer to whatever struct you like to use, e.g. pixel1D* pixs = texture (just be careful if channels are 2-byte long since your posted struct is not). I find a structure carrying the meta and a typeless memory block more flexible since mostly working with OpenGL. Maybe that is what you meant to do with the Image type.
The code is completely untested. Have fun debugging it.

For loop stops for no reason

So I'm trying to make a program to read a ppm file and store it in memory, I've got everything working up to the colors, this function is giving me problems:
typedef struct{
int red, green, blue;
} COLOR;
COLOR * getNextColor(FILE *fd);
COLOR **getColors(FILE *fd, int width, int height){
printf("\nentered get colors");
COLOR **colors = malloc(sizeof(COLOR*)*height);
printf("\nallocated %d space height",height);
int i,j;
for(i = 0; i < height; i++, colors++){
*colors = malloc(sizeof(COLOR)*width);
printf("\nallocated %d space width",width);
for(j = 0; j < width; j++, *colors++){
printf("\nlooping through to get the colors for point (%d,%d)", j,i);
//*colors = getNextColor(fd);
}
*colors -= width;
printf("\nmoved the pointer for *colors back %d spaces",width);
}
colors -= height;
printf("\nmoved the pointer for colors back %d spaces",height);
return colors;
}
I'm passing in a file pointer that is currently pointing at the first digit of the first color, the width = 400 and height is 530. The output looks like this:
allocated 530 space height
allocated 400 space width
looping through to get the colors for point (0,0)
looping through to get the colors for point (1,0)
looping through to get the colors for point (2,0)
...
looping through to get the colors for point (398,0)
looping through to get the colors for point (399,0)
moved the pointer for *colors back 400 spaces
allocated 400 space width
looping through to get the colors for point (0,1)
looping through to get the colors for point (1,1)
...
looping through to get the colors for point (398,1)
looping through to get the colors for point (399,1)
moved the pointer for *colors back 400 spaces
allocated 400 space width
and pattern repeats this all the way up to
looping through to get the colors for point (399,36)
then crashes. Any ideas?
There is a problem with *colors++ that does not probably mean what you think it does. This is due to operator precedence, highest precedence has postfix increment/decrement operators and lower precedence has indirection. So *colors++ actually meanst *(colors)++ which doesn't make much sense. You probably meant (*colors)++

printing matrix[20][20] with double type

i'm trying to create a matrix 20X20 double type so i could perform operations on it.
The problem is that when I try to print it so it could like like a matrix, there are many zeros because of the type double. And it doesn't look like a matrix.
This is what I wrote:
for (i = 0; i < SIZE; i++)
{
for (j = 0; j < SIZE; j++)
{
mat[i][j] = (rand() % (SIZE + 1) + 0);
}
}
for (i = 0; i < SIZE; i++)
{
for (j = 0; j < SIZE; j++)
printf("%10lf", mat[i][j]);
printf("\n\n");
}
How can I make it look like 20X20 matrix and keep the double type?
If no precision is specified for %f argument of printf, it is using 6 decimal digits.
Also, for printf there is no need to use %lf, float arguments are always promoted to double when passed (Why does printf() promote a float to a double?). But usually, a printf implementation will ignore the l prefix.
For a proper print alignment, in this case you can use:
printf("%4.1f ", mat[i][j]);
// Here a space is added after printing the number.
// "%5.1f" could also be used for alignment (difference: the space will be prefixed),
// but then if the number will have 3 or more integer digits, it will be displayed
// "concatenated" with the previous one. Using a space prevents this
Using this, there will be 4 positions allocated to print each number, from which one position will be used by the decimal point, and another one for the decimal places (1 in this case). Two positions are remaining for the integer part (if it doesn't fit in these 2 positions, more will be used and may broke the alignment.
If running in a default Windows terminal: Even if using this alignment, there will not be enough room to print a matrix row on a single line, and 2 lines will be used. This is because by default, Windows terminal line width is 80 characters. Increasing it to 100 or more will fix the problem. This can be changed using the Properties options, or even programatically, as described here:
How can I change the width of a Windows console window?

fwrite() not writing entire ppm file

So, I'm struggling with a homework which asks me to anti-alias a photo. But that's not the point of my question. The files are .ppm ppm format. I read it, using fread (it's color so I need to read rgb).
fread(tmp, 3 * sizeof(char), maxWidth * maxHeight, f)
where
tmp = (char *)malloc(width * height * 3 * sizeof(char));
I cast the tmp to short int (I need to do some work on the resulting matrix):
for(i=0; i < width * height; i++){
values[i] = (short int)tmp[i];
}
values is defined as short int:
values = (short int*) malloc(width * height * sizeof(short int));
The thing is that I just wanted to make a test. Read the image, transform it to int, transform it back to char, write the image. In this stage, only 1/4 of the image is written and I don't know why. I read the documentation for fwrite, but I cannot find out what I am doing wrong. Transform the image back (tmp2 allocated as img):
for(i=0; i < width * height; i++){
tmp2[i] = (char)values[i];
}
fwrite(tmp2, 3 * sizeof(char), width * height, g);
Am I using fwrite correctly? Maybe someone struggled with this too and knows how to answer.
A short int is 16 bits, or two bytes. In:
for(i=0; i < width * height; i++){
values[i] = (short int)tmp[i];
}
you are only copying 2/3rd of the image data (and there is more wrong as each byte gets copied twice: i is incremented with 1 byte and the cast takes two bytes, one of which was copied already). Then in:
for(i=0; i < width * height; i++){
tmp2[i] = (char)values[i];
}
you are copying only half of values (the first byte of each short), or 1/3rd of the image. Then in:
fwrite(tmp2, 3 * sizeof(char), width * height, g);
you are writing the correct mount of bytes, but the file contains only 1/3rd of the image (and a lot of garbage or zeroes).
I leave fixing this to you.

Image conversion - can't access the element from struct inside another

I'm writing a program to manipulate images .PPM based on a template given by my professor. The template has these structures:
typedef struct {
unsigned char gray;
} PPMGrayPixel;
typedef struct {
int x, y;
PPMGrayPixel *data;
} PPMGrayImage;
I'm trying to convert a regular .ppm to a gray scale .ppm. Actually, in this case, I already have an empty grayscale image with the same size that my original image. This grayscale file just have one channel of color (the original has three). I'm okay with the formula to convert, but I think I'm missing something while I try to access the elements of the grayscale file.
I'm not worried to set the right number, I just want to set the values for black and white now. I want to be sure that I'm accessing the right pixel.
This is my code:
PPMGrayImage * ConvertToGrayFromColorImage(PPMImage *img) {
PPMGrayImage *img2;
img2 = CreateEmptyGrayImageFromColorImage(img);
for (int i=0; i < img2->x*img2->y; i++) {
if (i % 2 == 0) {
img2.data[i].gray = 0;
}
else {
// sign 1
}
}
Am I missing something in the logic of the problem or in sintax?
img2.data[i].gray = 0;
img2 is a pointer to struct, so you cannot access its members directly. You have to write:
(*img2).data[i].gray = 0;
or:
img2->data[i].gray = 0;

Resources