I am trying to copy data from a buffer that contains characters into a struct. The buffer only contains data for the blue, green, and red members of the struct - alpha will be set to zero. The code is as follows, but I can't seem to get the loops figured out.
typedef struct __attribute__((packed)){
uint8_t blue;
uint8_t green;
uint8_t red;
uint8_t alpha;
} rgb_pixel_t;
int i, j;
char *buffer;
buffer = malloc(sizeof(rgb_pixel_t) * bmp->dib.width);
bmp_malloc_pixels(bmp);
rgb_pixel_t pixel = {42, 42, 42, 0};
fseek(fp, bmp->header.offset, SEEK_SET);
fread(buffer, sizeof(char), ((bmp->dib.depth / 8) * bmp->dib.width), fp);
for(i = 0; i < 600; ++i) {
for(j = 0; j < 400; ++j) {
bmp_set_pixel(bmp, i, j, pixel); // This isn't right.
}
}
Don't do it that way. Instead of having a char buffer, have a rgb_pixel_t buffer, and read into that:
rgb_pixel_t *pixels = malloc(sizeof(rgb_pixel_t) * bmp->dib.width);
/* ... */
size_t pixels_to_read = bmp->dib.depth / 8 * bmp->dib.width / sizeof(rgb_pixel_t);
fread(pixels, sizeof(rgb_pixel_t), pixels_to_read, fp);
/* ... */
As noted by Drew McGowen in a comment, this will of course not work if the bitmap data doesn't have an alpha channel. Also, there are images that have less bits per pixel, or that doesn't have RGB data at all (instead have index into color table, typically images with 256 colors or less).
You might want to find a library which handle all that for you, and present format-independent API for you to use, instead of having to muck around with the raw image data yourself.
Related
What i am trying to do i resize the a regular pgm image,by a factor of 3--100X100 becomes 33X33,i am using pointer array to store the original image and the resized image, the original image will be 10000 long and the resized image will be 1089 long, I am trying to do get the every 3rd element in the width dimension and skipping two width rows(as height also needs to be reduced),I keep getting a weird blurry image when I write it in a pgm output,i get there might be a little difference as we are rounding height and width,this is just a bit of the code.
enter code here
int k,l,m;
image =(unsigned char*) malloc((width*height) * sizeof(unsigned char));
int thumbHeight=round(height/3);
int thumbWidth =round(width/3);
resizedImage =(unsigned char*) malloc(((resizedWidth*resizedHeight)) * sizeof(unsigned char));
for(l=0;l<resizedHeight;l++){
for(k=0;k<resizedWidth;k++){
*resizedImage= *image;
image++;
image++;
}
//skipping two lines
for (m=0;m<width*2;m++){
image++;
}
}
maybe:
unsigned char *resize(const unsigned char *source, unsigned char *dest, size_t origx, size_t origy, size_t destx)
{
double ratio = (double)destx / origx;
double stepx = (double)origx / destx;
double stepy = (double)origy / (origy * ratio);
for(size_t y = 0; y < origy * ratio; y++)
{
for(size_t x = 0; x < destx; x++)
{
dest[y * destx + x] = source[(ssize_t)((y * stepy) * origx + x * stepx)];
}
}
return dest;
}
But I did not run this so it may be buggy.
I am applying a basic tutorial on image processing in C and I am having problems with this program to convert RGB into grayscale but the output pic is somehow corrupted and although the code runs with no errors, and I cant put my hands on the problem. The code is below.
FILE *fIn = fopen("tiger.bmp","rb"); //Input File name
FILE *fOut = fopen("tiger_gray.bmp","wb"); //Output File name
int i,j,y;
unsigned char byte[54];
if(fIn==NULL)
{
printf("File does not exist.\n");
}
for(i=0;i<54;i++) //read the 54 byte header from fIn
{
byte[i] = getc(fIn);
}
fwrite(byte,sizeof(unsigned char),54,fOut); //write the header back
// extract image height, width and bit Depth from image Header
int height = *(int*)&byte[18];
int width = *(int*)&byte[22];
int bitDepth = *(int*)&byte[28];
printf("width: %d\n",width);
printf("height: %d\n",height );
int size = height*width;
unsigned char buffer[size][3]; //to store the image data
for(i=0;i<size;i++) //RGB to gray
{
y=0;
buffer[i][2]=getc(fIn); //blue
buffer[i][1]=getc(fIn); //green
buffer[i][0]=getc(fIn); //red
y=(buffer[i][0]*0.3) + (buffer[i][1]*0.59) + (buffer[i][2]*0.11); //conversion formula of rgb to gray
putc(y,fOut);
putc(y,fOut);
putc(y,fOut);
}
fclose(fOut);
fclose(fIn);
There were two major problems in your code.
You had the width and height reversed.
You were not accounting for
the required padding at the end of every row to make it a multiple
of 4 bytes.
You were also allocating a large buffer that you did not need based on how the rest of the code was written. Generally I'd prefer to read/process either one full row at a time or even the full image at once, but to do that you want to use malloc or calloc because the data may be larger than the available stack. In this case, to keep things simple, I just process one pixel at a time.
I also got rid of getc/putc because I prefer fread/fwrite and you're never really dealing with 1 byte at a time.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
FILE *fIn = fopen("tiger.bmp", "rb");
FILE *fOut = fopen("tiger_gray.bmp", "wb");
if (!fIn || !fOut)
{
printf("File error.\n");
return 0;
}
unsigned char header[54];
fread(header, sizeof(unsigned char), 54, fIn);
fwrite(header, sizeof(unsigned char), 54, fOut);
int width = *(int*)&header[18];
int height = abs(*(int*)&header[22]);
int stride = (width * 3 + 3) & ~3;
int padding = stride - width * 3;
printf("width: %d (%d)\n", width, width * 3);
printf("height: %d\n", height);
printf("stride: %d\n", stride);
printf("padding: %d\n", padding);
unsigned char pixel[3];
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
fread(pixel, 3, 1, fIn);
unsigned char gray = pixel[0] * 0.3 + pixel[1] * 0.58 + pixel[2] * 0.11;
memset(pixel, gray, sizeof(pixel));
fwrite(&pixel, 3, 1, fOut);
}
fread(pixel, padding, 1, fIn);
fwrite(pixel, padding, 1, fOut);
}
fclose(fOut);
fclose(fIn);
return 0;
}
I'm using this code to write the file:
FILE *f = fopen("out/solution.raw", "wb");
int i, j;
//SIZE = 512
for(i = 0; i < SIZE; i++)
{
fwrite(matrix[i], 1, SIZE, f);
}
fclose(f);
The problem is that when I open the file, it 3 '0' between the numbers, here are 2 screenshots to help you understand what I mean:
This is what I should be getting:
And this is what I'm getting:
As you can see my code is correctly writing each number, but there are three 0 between each number and I have no idea why.
I've also tried this:
fwrite(matrix[i], sizeof(matrix[i][0]), SIZE, f);
But none seems to work, any help would be greatly appreciated.
my matrix is declared as a 2D array of ints, as I need to do some operations with those numbers:
matrix = (int**)malloc(SIZE * sizeof(int*));
for (i = 0; i < SIZE; i++)
{
matrix [i] = (int*)malloc(SIZE * sizeof(int*));
}
I've tried your solution but I can't assign an unsiged char to an int, so I've tried casting it and I get this warning:
cast from pointer to integer of different size.
unsigned char to_write;
for(i = 0; i < SIZE; i++)
{
to_write = (unsigned char)matrix[i];
fwrite(&to_write, 1, 1, f);
}
(code used)
After that this is what I'm getting:
And btw, my data is unsigned.
matrix[i] is a pointer on 32-bit integers. Even if you assign values that hold in 8 bits, that doesn't "compress" the data when you're writing to a binary stream (plus you probably don't write the 512 values but only 512/4 = 128 values)
Your machine is little endian, so you get the LSB first, then 3 zeros, for each value.
So change the type of matrix[i] from int32_t * to char * or unsigned char * depending on what you need, make sure your values are in 8-bit range, and you can use fwrite like you're planning to.
If you cannot change the data type of matrix, use a loop to convert the values
for(i = 0; i < SIZE; i++)
{
uint8_t to_write = matrix[i]; // assign/truncate for 0/255 range
fwrite(&to_write, 1, 1, f);
}
if your data is signed, you have to use int8_t. But in that case, you're not going to be able to write a0 as 160.
EDIT: your edit shows the real type of matrix. matrix[i] is a pointer on data, so you need to use a double loop to dump it, else you're copying the address of the array, not the value
for(i = 0; i < SIZE; i++)
{
const int *row = matrix[i];
for(j = 0; j < SIZE; j++)
{
uint8_t to_write = row[j]; // assign/truncate for 0/255 range
fwrite(&to_write, 1, 1, f);
}
}
I want to crop 1 pixel from all sides of image.
My code works well in some margins but does not work well in some margins (ex. widthleft=widthright=heightup=heightdown=1).
I should use C not C++.
IplImage* edgecuter_v3(unsigned int height, unsigned int width,
IplImage* p_in_img_grey) {
unsigned int widthleft, widthright, heightup, heightdown, heighteff;
unsigned int widtheff;
widthleft = 1;
widthright = 1;
heightup = 1;
heightdown = 1;
widtheff = width - widthleft - widthright;
heighteff = height - heightup - heightdown;
IplImage *p_out_img;
unsigned char *p_in_img_data;
p_in_img_data = (unsigned char *) p_in_img_grey->imageData;
unsigned char (*p_char_array_in)[width];
p_char_array_in = (unsigned char (*)[width]) p_in_img_data;
p_out_img = cvCreateImage(cvSize(widtheff, heighteff), IPL_DEPTH_8U, 1);
unsigned char *p_out_img_data;
p_out_img_data = (unsigned char *) p_out_img->imageData;
unsigned char (*p_char_array_out)[widtheff];
p_char_array_out = (unsigned char (*)[widtheff]) p_out_img_data;
unsigned int row_indx;
unsigned int col_indx;
for (row_indx = 0; row_indx < heighteff ; row_indx++) {
for (col_indx = 0; col_indx < widtheff; col_indx++) {
p_char_array_out[row_indx ][col_indx ] =
p_char_array_in[row_indx+heightup][col_indx+widthleft];
}
}
cvNamedWindow("one", CV_WINDOW_AUTOSIZE);
cvShowImage("one", p_out_img);
cvWaitKey(0);
return p_out_img;}
I sweep index with other methods and assignments like but not work.
p_char_array_out[row_indx ][col_indx ] =
p_char_array_in[row_indx+heightup][col_indx+widthleft];
thanks lot
I found the solution. maybe useful for others.
Acording to this link 32bit boundary "If the number of cols * pixel size isn't a multiple of 4 then each row if the image will be padded"
The right way for sweep is to use "widthStep" not "width" for considering pad
widthStep_r = p_in_img->widthStep;
This function is throwing an access violation when reading raw pixel values and I can't figure out why.
Can consider this as the only part of my code running, I've run this solo with the same result.
string filenames[]={"firstclick.raw", "secondclick.raw","thirdclick.raw","fourthclick.raw","fifthclick.raw","sixthclick.raw","seventhclick.raw","eighthclick.raw"};
FILE *file;
int height= 750, width = 453, bbp=3;
unsigned char ****images;
images = (unsigned char ****)malloc(sizeof(unsigned char ***)*8);
for(int j = 0; j<8; j++){
images[j] = (unsigned char ***)malloc(sizeof(unsigned char**)*height);
for(int i = 0; i<height; i++){
images[j][i]= (unsigned char **)malloc(sizeof(unsigned char*)*width);
for(int k = 0; k<bbp; k++)
images[j][i][k]= (unsigned char *)malloc(sizeof(unsigned char)*bbp);
}
}
for (int i = 0; i<8; i++){
if (!(file=fopen(filenames[i].c_str(),"rb"))){
cout << "Cannot open file: "<<filenames[i].c_str() <<endl;
exit(1);
}
fread(images[i], sizeof(unsigned char), height*width*bbp, file);
fclose(file);
}
The problem here is you've allocated each element of your array as a separate array (somewhere else in memory, whose location is kept as a pointer). But when you read in, you assume that it's a single contiguous block. You will overwrite all those pointers, and overflow the buffer to boot.
If you want images to be a set of discrete blocks of memory, allocate like this:
unsigned char ** images;
int i;
images = malloc( sizeof(unsigned char *) * 8 );
for( i = 0; i < 8; i++ ) {
images[i] = malloc( width * height * bpp );
}
Note that sizeof(unsigned char) is defined by the standard to always be 1. You don't need to multiply by sizeof(unsigned char) all the time.
Now, to get a pixel address in an image, you need to multiply out (usually row-major):
unsigned char * pixel = images[i] + (y * width + x) * bpp;
unsigned char r = pixel[0];
unsigned char g = pixel[1];
unsigned char b = pixel[2];
when you allocate the memory blocks in different locations in memory an fread on that structure will not work.
instead allocate one big block then set the pointers to point inside the block, that way you can use fread on it.