Writing to a bmp file in C - c

I am having difficulties when writing to a bmp file.
Here is the code where the matrix is allocated:
// Dynamically allocate matrix for the bitmap and
// while doing so, color it in blue.
Pixel **bmp_matrix = (Pixel**)malloc(config.resolution_height_ *
sizeof(Pixel*));
if (bmp_matrix == NULL)
{
printf("error: out of memory\n");
return MEMORY_ERROR;
}
int rows = 0;
for(; rows < config.resolution_height_; rows++)
{
bmp_matrix[rows] = (Pixel*)malloc(config.resolution_width_ *
sizeof(Pixel));
if (bmp_matrix[rows] == NULL)
{
while(--rows >= 0)
free(bmp_matrix[rows]);
free(bmp_matrix);
printf("error: out of memory\n");
return MEMORY_ERROR;
}
int columns = 0;
for(; columns < config.resolution_width_; columns++)
{
bmp_matrix[rows][columns].red_ = 175;
bmp_matrix[rows][columns].green_ = 175;
bmp_matrix[rows][columns].blue_ = 255;
}
}
Here is the code for writing the pixels:
int height, width, pad_iterator;
for(height = info_header.height_ - 1; height >= 0; height--)
{
// for(width = 0; width < info_header.width_; width++)
// fwrite(&bmp_matrix[height][width], sizeof(Pixel), 1, bitmap_file);
fwrite(&bmp_matrix[height], sizeof(Pixel), info_header.width_, bitmap_file);
for(pad_iterator = 0; pad_iterator < pad_length; pad_iterator++)
fwrite(&pad, sizeof(Byte), 1, bitmap_file);
}
Now, when I use the for loop which is commented, everything works perfectly. The resulting image is OK.
However, I am trying to substitute it with a single fwrite so the program would not have to iterate the loop.
In this case the resulting image is completely wrong.
Any help?

Your second try is incorrect.
In your commented write (fwrite(&bmp_matrix[height][width], sizeof(Pixel), 1, bitmap_file);), you use one pixel at address &bmp_matrix[height][width] which is correct.
But in fwrite(&bmp_matrix[height], sizeof(Pixel), info_header.width_, bitmap_file);, you write bytes from the address &bmp_matrix[height] ... which may be different things depending on the actual declaration of bmp_matrix
You should use either &bmp_matrix[height][0] ie. the address of first pixel in a row or equivently (as suggested by Peter Schneider) bmp_matrix[height] (without the &) both giving a correct address.

Related

c - segmentation fault assigning to 2d array

I'm trying to take a bmp file and make a grayscale copy. I'm learning about dynamic allocation and I have to dynamically allocate a 2D array which I import the bmp file to and manipulate it from, so it will work with various picture sizes. But near the end (I labeled where) I get a Seg Fault and I have no idea why. Everything works great if I don't dynamically allocate "pixels".
#include <stdio.h>
#include <stdlib.h>
int main(void) {
const int HEADER_SIZE = 54;
FILE *infile = fopen("test1.bmp", "rb");
FILE *outfile1 = fopen("copy1.bmp", "wb");
int i, width, height, r, c, bmpsize;
char header[HEADER_SIZE], filename[32];
char **pixels; //initialize pixels here
puts("Enter the filename: ");
i = -1;
while(filename[i] != '\n')
{
i++;
scanf("%c", &filename[i]);
}
filename[i] = '.';
filename[i+1] = 'b';
filename[i+2] = 'm';
filename[i+3] = 'p';
filename[i+4] = '\0';
i = -1;
while(filename[i] != '\0')
{
i++;
printf("%c", filename[i]);
}
infile = fopen(filename, "rb");
puts("Enter the height and width (in pixels): ");
scanf("%d%d", &height, &width);
bmpsize = 3 * width * height;
pixels = malloc(height * sizeof(char*)); //DA part 1
for(i = 0; i < height; i++)
{
pixels[i] = malloc((width * 3) * sizeof(char)); //DA part 2
}
fread(header, 1 , HEADER_SIZE, infile);
fread(pixels, 1 , bmpsize, infile);
for( r = 0; r < height; r++) {
for ( c = 0; c < width*3; c += 3) {
int avg= 0;
puts("THIS PUTS PRINTS: THE NEXT LINE IS MY PROBLEM");
avg = ((int) pixels[r][c] + (int) pixels[r][c+1] + (int) pixels[r][c+2]) / 3;//This is my problem line, why?
puts("THIS PUTS DOESN'T PRINT. ERROR: SEG. FAULT(core dumped)");
pixels[r][c] = (char) avg;
pixels[r][c+1] = (char) avg;
pixels[r][c+2] = (char) avg;
}
}
puts("Done. Check the generated images.");
fwrite(header, sizeof(char) , HEADER_SIZE, outfile1);
fwrite(pixels, sizeof(char) , bmpsize, outfile1);
fclose(infile);
fclose(outfile1);
return 0;
}
I think the problem is with your fread call and how you are setting up the input buffer for the file contents
pixels = malloc(height * sizeof(char*)); //DA part 1
for(i = 0; i < height; i++)
{
pixels[i] = malloc((width * 3) * sizeof(char)); //DA part 2
}
fread(pixels, 1 , bmpsize, infile);
The memory you have allocated in total is bmpsize bytes but the length of pixels is just height bytes - and yet you are passing it to fread as if it were a buffer of bmpsize bytes in length. Each element in pixels is a char* - the address of each is block of dynamically allocated array but this does not mean that you can treat your pixels array as a contiguous block of memory.
These arrays allocated dynamically in your loops are thus not initialised which could be leading to the segfaults when you read from them later in your loop (reading uninitialised variables is undefined behaviour).
This probably explains why your code works when you use a non dynamically allocated 2D array - because such a 2D array is a contiguous in memory.
The answer of mathematician1975 is almost correct, since you are accessing data from outside of the area you've allocated, but the last index of c in the inner loop is not 3*width-1 nor 3*width-3, but it's actually width*3.
You should adapt the inner loop to:
for ( c = 0; c < width*3-3; c += 3)
This way c will go until width*3-3 and then you can do c, c+1 and c+2 and you will visit the last bytes of the lines with c+2.

Syntax not clear about pointers and matrix

i am coding in C and i have to work with png images, so i work with libpng library. In my project i use this structure:
png_bytep *row_pointers; /* <-- to declare the pointer that will contain the image
and this to initialize the pointer to contain the image. */
row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * height);
for(int y = 0; y < height; y++) {
row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png,info));
}
My problem is: after this piece of code my image is copyed in row_pointers and i want to copy it in a png_byte map[x][y] so i can work easly pixel for pixel.
Someone can help me?
Thanks
Ok. That is pointer to pointer!
png_bytep = pointer to png_byte
If you eliminate png_bytep and just use png_byte your code will look like this.
int height = 10;
int width = 20;
png_byte **row_pointers;
row_pointers = (png_byte**)malloc(sizeof(png_byte*) * height); <-- This is basically your number of rows.. ie height of your matrix.
for(int y = 0; y < height; y++)
{
row_pointers[y] = (png_byte*)malloc(sizeof(png_byte)*width); <-- This is representing number of elements in each row.. so width.
}
Assuming your structure have two ints x and y. you must be filing data as below..
for(int i=0;i< height;i++)
{
for (int j=0;j<width;j++)
{
row_pointers[i][j].x = i*j;
row_pointers[i][j].y = i*j;
}
}
Assuming your map also have similar structure. This is how you copy data..
for(int i=0;i< height;i++)
{
for (int j=0;j<width;j++)
{
map[i][j].x = row_pointers[i][j].x;
map[i][j].y = row_pointers[i][j].y;
}
}
Have a look at pnm2png.c in libpng's contrib/pngminus directory.
In this code, "png_pixels" is a simple array that holds all the pixels, and row_pointers is an array of pointers that point to the beginning of each row within png_pixels:
/* row_bytes is the width x number of channels x (bit-depth / 8) */
row_bytes = width * channels * ((bit_depth <= 8) ? 1 : 2);
png_pixels = (png_byte *) malloc (row_bytes * height * sizeof (png_byte))
/* set the individual row_pointers to point at the correct offsets */
for (i = 0; i < (height); i++)
row_pointers[i] = png_pixels + i * row_bytes;
/* now we can go ahead and just read the whole image */
png_read_image (png_ptr, row_pointers);
Once png_read_image completes, you can easily work with your pixels in the png_pixels array.
Notice that there is only one "malloc", which allocates png_pixels. Instead of doing a separate "malloc" for each row, this code calculates the values of the row_pointers.

Weird results when implementing Sobel Filter [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
I have been learning about computer vision and wanted to implement some simple techniques in C. For the first technique, I am doing the Sobel edge detection filter. I understand how it works and so I thought it should be fairly easy to code, but I am getting very weird results.
I am using the following image:
and getting this as a result
New Results!:
It should be noted that I am using the .ppm image format (the links are to jpgs since I could not find an image host that supports .ppm)
Anyways, here is the section of my code that implements Sobel:
/**********************************************************
This program takes in an image file and applies the Sobel
Filter edge detection technique to it.
**********************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "ppmReader.h"
void sobelFilter(){
//Sobel kernels dx (horizontal) and dy (vertical)
int horizFilter[3][3] = {{ 1, 0, -1},
{ 2, 0, -2},
{ 1, 0, -1}};
int vertFilter[3][3] = {{ 1, 2, 1},
{ 0, 0, 0},
{-1, -2, -1}};
int pixVal = 0;
int horizPixVal = 0;
int vertPixVal = 0;
int x, y, i, j;
//Quick check to make sure dimensions are correct
printf("Using a Width of: %d\n", width);
printf("Using a Height of: %d\n\n", height);
//Start filtering process here
for(x = 0; x < width; x++){
for(y = 0; y < height; y++){
pixVal = 0;
horizPixVal = 0;
vertPixVal = 0;
if(!((x == 0) || (x == width-1) || (y == 0) || (y == height-1))){ //If the current pixel is along the border, ignore it and set to zero
for(i = -1; i <= 1; i++){ //because the kernel does not align to it
for(j = -1; j <= 1; j++){
horizPixVal += (int)(image[y + j][x + i][0]) * horizFilter[i + 1][j + 1]; //Only need to focus on one of the RGB values since the output is
vertPixVal += (int)(image[y + j][x + i][0]) * vertFilter[i + 1][j + 1]; //greyscale and all three values are the same
}
}
}
pixVal = sqrt((horizPixVal * horizPixVal) + (vertPixVal * vertPixVal)); //Calculate magnitude
pixVal = sqrt(horizPixVal * horizPixVal);
if(pixVal > 255) pixVal = 255; //Clamp value within 8-bit range
filteredImage[y][x][0] = (unsigned char)pixVal;
}
}
}
Here is the code that reads the .ppm file:
unsigned char image[MAX_IMAGE_HEIGHT][MAX_IMAGE_WIDTH][3];
unsigned char filteredImage[MAX_IMAGE_HEIGHT][MAX_IMAGE_WIDTH][3];
void readPPMImageData(){
char fileName[MAX_NAME];
char imageBuff[MAX_BUFF];
width = 0;
height = 0;
maxColor = 0;
int x;
int y;
FILE* file;
printf("------------------------------------------------------------\n");
printf("Now attempting to read in the .ppm image file data...\n");
printf("------------------------------------------------------------\n\n");
printf("What is the image file name (*.ppm)? : ");
scanf("%s", fileName);
file = fopen(fileName, "rb"); //open the file specified by the user in binary read mode
if(file == NULL){ //but if the file was not found, terminate program
printf("\nThe file %s could not be found! Terminating program...\n", fileName);
exit(1);
}
//The first step is to read in the file type and check it agains P6 (file type of .ppm images)
fgets(imageBuff, MAX_BUFF, file);
if(imageBuff[0] != 'P' || imageBuff[1] != '6'){
printf("\nInvalid image type! Acceptable type is: %s --- Received type is: %c%c\n\n", "P6", imageBuff[0], imageBuff[1]);
}
printf("Magic Number is: %c%c\n", imageBuff[0], imageBuff[1]);
while(width == 0 || height == 0){
fgets(imageBuff, MAX_BUFF, file);
if(imageBuff[0] != '#') {
sscanf(imageBuff, "%d %d", &width, &height);
}
}
printf("Width is: %d\n", width);
printf("Height is: %d\n", height);
//if(feof(file)){
//
//}
while(maxColor == 0){
fgets(imageBuff, MAX_BUFF, file);
if(imageBuff[0] != '#') {
sscanf(imageBuff, "%d", &maxColor);
}
}
printf("Maximum color value is: %d\n", maxColor);
for(x = 0; x < width; x++){
for(y = 0; y < height; y++){
image[y][x][0] = (unsigned char)fgetc(file); //Get Red value
image[y][x][1] = (unsigned char)fgetc(file); //Get Green value
image[y][x][2] = (unsigned char)fgetc(file); //Get Blue value
}
}
printf("Finished reading image data!\n\n");
fclose(file);
}
And here is the code that creates the new .ppm file after filtering:
void createPPMImage(){
char fileName[MAX_NAME];
FILE* file;
int x;
int y;
printf("------------------------------------------------------------\n");
printf("Now attempting to create new .ppm image file...\n");
printf("------------------------------------------------------------\n\n");
printf("What is the name of the output image file (*.ppm)? : ");
scanf("%s", fileName);
printf("Width is: %d\n", width);
printf("Height is: %d\n", height);
printf("Maximum color value is: %d\n", maxColor);
file = fopen(fileName, "wb");
fputs("P6\n", file);
fprintf(file, "%d %d\n", width, height);
fprintf(file, "%d\n", maxColor);
for(x = 0; x < width; x++){
for(y = 0; y < height; y++){
fputc(filteredImage[y][x][0], file); //Write Red value
fputc(filteredImage[y][x][0], file); //Write Green value
fputc(filteredImage[y][x][0], file); //Write Blue value
}
}
printf("Finished creating new filtered image!\n\n");
fclose(file);
}
I'm 100% sure the issue isn't with the reading or writing of the image as I tested those functions without the filter applied and only get issues once I use the above function.
Any help is appreciated because as far as I can see, the indexing/formula seems to be correctly implemented but that is obviously not true.
EDIT: As Dave and others have pointed out, I am no longer 100% sure that the error is within the Sobel function and it appears this is just some indexing mistake I have made when using the .ppm format. I went ahead and posted the code for my .ppm reader/writer functions and the new results I am getting after applying the [y][x][color] scheme propsed by anatolyg below. I am sorry if my post is way too long and if it is please let me know as this is my first post and I am not entirely sure what is proper yet.
Images are usually indexed with y coordinate first and x second, like this:
... image[y + j][x + i] ...
This is a convention that keeps people from getting confused when dealing with images in C. Unfortunately, it kinda contradicts the one that Matlab uses, so I just hope you are doing it all in C.
In addition, PPM format specification says that the red/green/blue values are interleaved, so the "colour plane" must be the last index:
... image[y + j][x + i][0] ...
unless there was some reordering of the input file while loading it into memory. You didn't show code that reads from the file, so it's hard to know whether it did any reordering.
Addition: reading and writing the file should follow raster ordering, that is, finish pixels of one line before proceeding to next line:
for(y = 0; y < height; y++){
for(x = 0; x < width; x++){
...
}
}
It is also recommended to do processing in this manner; this is not an absolute must, but it will reduce confusion, and might make your processing faster in addition (by using CPU cache more effectively).

Issue with fscanf reading 2-d array of doubles from text file

I'm having some trouble with using fscanf in C. I've written a random matrix to a file and am now trying to read the data in the text file into another matrix. It seems to read the number of rows and columns fine, but it returns zeros for the data values. I'm completely stuck, so any help would be appreciated!
My MATRIX stucture is declared as
typedef struct matrep {
unsigned rows, columns;
double *data;
}MATRIX;
My file looks like this:
rows = 5, columns = 10
-99.75 12.72 -61.34 61.75 17.00 -4.03 -29.94 79.19 64.57 49.32
-65.18 71.79 42.10 2.71 -39.20 -97.00 -81.72 -27.11 -70.54 -66.82
97.71 -10.86 -76.18 -99.07 -98.22 -24.42 6.33 14.24 20.35 21.43
-66.75 32.61 -9.84 -29.58 -88.59 21.54 56.66 60.52 3.98 -39.61
75.19 45.34 91.18 85.14 7.87 -71.53 -7.58 -52.93 72.45 -58.08
And this is my matrix_read function:
MATRIX matrix_read(char file_name[15])
{
int i,j, m, n;
MATRIX B;
FILE *filep;
double *ptr = NULL;
double x;
if((filep = fopen("matrixA.txt", "r"))==NULL)
{
printf("\nFailed to open File.\n");
}
if(fscanf(filep, "\n\nrows = %u, columns = %u\n\n", &m, &n) != 2)
{
printf( "Failed to read dimensions\n");
B.data = 0;
B.columns = 0;
B.rows = 0;
}
B.data = (double *)malloc(B.columns*B.rows*sizeof(double));
if(B.data ==0)
{
printf("Failed to allocate memory");
}
fscanf(filep,"\n\nrows = %u, columns = %u\n\n",&m,&n);
rewind(filep);
ptr = B.data;
for (i = 0; i < m; i++)
{
for (j = 0; j < n; j++)
{
if (fscanf(filep, " %5.2lf", &x) != 1)
{
printf("Failed to read element [ %d,%d ]\n", i, j);
B.data = 0;
B.columns = 0;
B.rows = 0;
}
printf("%5.2lf\t", x);
*ptr++ = x;
}
}
B.rows=m;
B.columns=n;
return B;
fclose(filep);
free(ptr);
}
Thanks!
You have several problems, one of them is pointed by #simonc, another possible one:
you rewind after reading columns and rows in filep
rewind() sets the position indicator associated with stream to the beginning of the file, you are reading again rows = 5, columns = 10
Finally:
B.data = (double *)malloc(B.columns*B.rows*sizeof(double)); /* Don't cast malloc */
if(B.data ==0)
{
printf("Failed to allocate memory");
/* You have to return or exit here */
}
As Alter Mann denoted, drop the second
fscanf(filep,"\n\nrows = %u, columns = %u\n\n",&m,&n);
as well as the
rewind(filep);
moreover, " %5.2lf" is not a valid scanf conversion specification (you could read the manual about this) - use "%lf" instead.

fread failing C program

double buf[1000];
double value;
double *ptr = &value;
for(i=0; i < no_of_iterations; i++) {
for(j=0; j < chunkSize; j++) {
num_bytes_read = fread(ptr,1,pcm_sample_size,fptr); //read one sample
if(num_bytes_read == 2) {
sum_sq += (*ptr) * (*ptr); //calculate power of each sample
buf[j] = *ptr;
}
else {
flag = 0;
break;
}
}
if(!flag) {
printf("exiting loop");
break;
}
power = sum_sq/chunkSize;//calculate rms value of signals for chunkSize samples
if(power < threshold) //compare with some value
printf("power is lower than threshold"); //silence-don't write
else { //write
ret = fwrite(buf,1,pcm_sample_size,optr);
if(ret != 1)
printf("error in fwrite %d", ret);
}
}
printf("done");
fclose(fptr);
fclose(optr);
Above is my code for writing some pcm samples to a file depending on some condition but I'm getting fread error.
The control does not enter the if(num_bytes_read==2) block. I think the error is because I want to read pcm samples which are 2 bytes in size and I need somewhere to store it. What datatype can I use to store a 2 byte pcm value(the pcm value is not an int value).
Please advise.
On this line:
num_bytes_read = fread(ptr,1,pcm_sample_size,fptr);//read one sample
ptr is pointing to the address of value so it must be sizeof(double) and 1, as you read in just one value.
The result of an fread is the number of items read, not the number of bytes.
Are you initialising sum_sq where you need to?
To read 2 doubles:
double readbuf[2];
num_items_read = fread( readbuf, sizeof(double), 2, fptr );
if( num_items_read == 2 )
{
covariance_sum += readbuf[0] * readbuf[1];
}
Not sure exactly what you are trying to multiply, but obviously if it is 2 different values it is not a "square". I will let you fix your code to your actual logic.

Resources