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.
Related
i'm trying for learning purpose to create manually a png file from with OpenGL
All other CHUNKS are okk (IHDR, pHY, IEND).
firstly, I read pixels by Opengl :
int s_width = glutGet(GLUT_SCREEN_WIDTH), s_height = glutGet(GLUT_SCREEN_HEIGHT);
int pixelArraySize = s_width*s_height*_glColorChannels;
unsigned char *pixelsArrayInfo = (unsigned char*)malloc(pixelArraySize);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadBuffer(GL_FRONT);
glReadPixels(0, 0, (unsigned short)s_width, (unsigned short)s_height, GL_RGB, GL_UNSIGNED_BYTE, pixelsArrayInfo);
then, I created a function of generating scanlines like this:
"each scanline is an array of RGB values in one screen line preceded by '0' "
unsigned char *generateScanlines(unsigned char *pixels, int s_width, int s_height)
{
int eachScanlineLength = 1 + s_width*3;
unsigned char *finalOutput = (unsigned char*)malloc(s_height*eachScanlineLength);
for(int i=0; i<s_height; i++){
finalOutput[i*eachScanlineLength] = 0;
copyElement(finalOutput, pixels, i*eachScanlineLength, (i+1)*eachScanlineLength, i*eachScanlineLength+1);
}
return finalOutput;
}
void copyElement(unsigned char *dest, unsigned char *src, int src_debut, int src_fin, int dest_debut)
{
for(int i=src_debut, j=dest_debut; i<src_fin; i++, j++){
dest[j] = src[i];
}
}
unsigned char *deflateDatas(unsigned char *pixels, int s_width, int s_height, int *deflatedDataLength)
{
unsigned char *deflated = (unsigned char*)malloc(compressBound(s_height*(1 + s_width*3)));
unsigned char *scanlines = invertArray(generateScanlines(pixels, s_width, s_height), s_height*(1 + s_width*3));
z_stream defstream;
defstream.zalloc = Z_NULL;
defstream.zfree = Z_NULL;
defstream.opaque = Z_NULL;
defstream.avail_in = (uInt)(s_height*(1 + s_width*3));
defstream.next_in = (Bytef *)scanlines;
defstream.avail_out = (uInt)(compressBound(s_height*(1 + s_width*3)));
defstream.next_out = (Bytef *)deflated;
deflateInit(&defstream, 0);
deflate(&defstream, Z_FINISH);
deflateEnd(&defstream);
*deflatedDataLength = compressBound(s_height*(1 + s_width*3));
return deflated;
}
then, it seem it work, but when I test it my OpenGL program I get this :
[small png output][1]
also, i created a basic bmp File and it work perfectly
i try to find if it's any error, maybe it's in scanlines generation or misunderstanding with the PNG file format.
the invertArray() code :
unsigned char *invertArray(unsigned char *myArray, int arrayEnd)
{ unsigned char *invertedtableau = (unsigned char*)malloc(arrayEnd*sizeof(unsigned char));
for(int i=0 ; i<=arrayEnd ; i++)
{ invertedtableau[i] = myArray[arrayEnd-i];
}
return invertedtableau; }
SOLUTION
I found where the error comes from, accordind to Mark Adler, the scanlines gemeration method was, wrong.
Also, file was inverted because Opengl is only compatible with bottom left gormat, but png is a top left format, then we need to invert the pixel buffer before generating scanlines(ehat i tried with invertArray() method).
The last error was that the calling of deflate method and storing the deflated length was also wrong.
the whole deflating code :
// generating scanline function
unsigned char *generateScanlines(unsigned char *pixels, int s_width, int s_height, int colorChannel)
{
int eachScanlineLength = 1 + s_width * colorChannel, i = 1, j = 0; // one scanline length
unsigned char *scanlines = (unsigned char *)malloc(s_height * eachScanlineLength); // memory allocation for the scanline output
memset(scanlines, 0, s_height * eachScanlineLength * sizeof(char)); // we set all the output values to 0
// then we copy pixels elements in the output, skipping the fisrt output values, that should ever be 0
for (i = 1, j = 0; i < s_height && j < s_height; i++, j++)
memcpy(scanlines + 1 + (i - 1) * eachScanlineLength, pixels + j * (eachScanlineLength - 1), eachScanlineLength - 1);
memcpy(scanlines + 1 + (i - 1) * eachScanlineLength, pixels + j * (eachScanlineLength - 1), eachScanlineLength - 1);
return scanlines;
}
// deflating IDAT CHUNK data algorithm
unsigned char *deflateDatas(unsigned char *pixels, int s_width, int s_height, int colorChannel, int *deflatedLen)
{
unsigned long inLen = s_height * (1 + s_width * colorChannel), tmpLen = 0; // input len of scanlines datas
unsigned char *scanlines = generateScanlines(pixels, s_width, s_height, colorChannel); // generating scanlines from the pixels
unsigned char *deflatedDatas = NULL; // setting up the deflated datas output
int result = 0;
// initialising zlib
z_stream defstream;
defstream.zalloc = Z_NULL;
defstream.zfree = Z_NULL;
defstream.opaque = Z_NULL;
defstream.avail_in = inLen;
defstream.next_in = (Bytef *)scanlines;
defstream.avail_out = 0;
defstream.next_out = (Bytef *)deflatedDatas;
if ((result = deflateInit(&defstream, Z_DEFAULT_COMPRESSION)) == Z_OK)
{
// calculate the actual length and update zlib structure
unsigned long estimateLen = deflateBound(&defstream, inLen);
deflatedDatas = (unsigned char *)malloc(estimateLen);
if (deflatedDatas != NULL)
{
// updation zlib configuration
defstream.avail_out = (uInt)estimateLen;
defstream.next_out = (Bytef *)deflatedDatas;
// do the compression
deflate(&defstream, Z_FINISH);
tmpLen = (unsigned char *)defstream.next_out - deflatedDatas;
}
}
deflateEnd(&defstream); // end of deflating algorithm
*deflatedLen = tmpLen; // copying the defalted data length to the IDAT->length
free(scanlines);
return deflatedDatas;
}
the bottom left to top left pixelbuffer flipping code :
void flipPixels(unsigned char *pixelsArray, int s_width, int s_heigth, int colorChannel)
{
int totalLength = s_width * s_heigth * colorChannel;
int oneLineLength = s_width * colorChannel;
unsigned char *tmp = (unsigned char *)malloc(totalLength * sizeof(unsigned char));
memcpy(tmp, pixelsArray, totalLength);
for (int i = 0; i < s_heigth; i++)
memcpy(pixelsArray + oneLineLength * i, tmp + totalLength - oneLineLength * (i + 1), oneLineLength);
free(tmp);
}
[1]:
https://i.stack.imgur.com/5khCg.png
We don't see all the relevant code, but first, you seem to be deliberately corrupting your image data by reversing the bytes. Don't do that. Remove the call to invertArray().
Second, you are not returning the size of the compressed data. You are returning the upper-bound estimate of that.
Use deflateBound() (after calling deflateInit()), not compressBound(). Call deflateBound() once (instead of three times) and save the answer in unsigned long bound. Return the size of the compressed data, which is bound - defstream.avail_out.
Lastly, you are not compressing! The second argument to deflateInit() should be Z_DEFAULT_COMPRESSION or something else other than 0, which means no compression.
Your example has an incorrect CRC for the IDAT chunk, so there's something else wrong in the code you don't show for constructing that chunk.
Even if I undo the invertArray() (which itself has another error), what I get is still messed-up image that appears to have a byte deleted on each row.
We can't help you unless you provide all of your code. There are many errors, and you don't know where they are.
We have struct image pointer:
struct image {
uint16_t size_x;
uint16_t size_y;
struct pixel *px;
};
and:
img->px = malloc(sizeof(struct pixel) * height * width);
where pixel:
struct pixel {
uint8_t red;
uint8_t green;
uint8_t blue;
uint8_t alpha;
}
where width & height:
long height = strtol(height_arg, &end_ptr, 10);
long width = strtol(width_arg, &end_ptr, 10);
So, since we use malloc() to allocate memory and it uses size_t for allocating.
Since we multiplying height and width which are long typed to allocate memory, is there integer overflow expected? If, yes then how to handle it?
Later on we iterate over picture and color it:
for (int i = 0; i < img->size_y; i++) {
for (int j = 0; j < img->size_x; j++) {
image_data[i][j].red = palette[0].red;
image_data[i][j].green = palette[0].green;
image_data[i][j].blue = palette[0].blue;
image_data[i][j].alpha = 0xff;
}
}
where
img->size_x = width;
img->size_y = height;
Integer overflow may happen at every point of this program:
strtol("9999999999", &end_ptr, 10) -> will overflow and return LONG_MAX
height * width -> can overflow and return a negative value (since those are signed longs)
sizeof(struct pixel) * height * width
-> can return a bigger value than UNSIGNED_MAX, wrapping around to a smaller value than expected
Malloc can allocate some very large data segments, and may not fail immediately, so you should seriously consider verifying your results before allocating.
Yes, there is a risk.
You can check it like this:
struct pixel *px;
if (height > SIZE_MAX / width || sizeof *px > SIZE_MAX / (width * height)) {
// Handle overflow
}
px = malloc(sizeof *px * width * height);
if(!px) {
// Handle allocation error
}
img->px = px;
I have written some serial code which I would like to optimise as much as possible before I parallelise it using OpenMP. The program reads in a PPM file by iterating through the pixel data in 4x4 cells (variable c), then it finds the average RGB value of each of those 4x4 cells, and then finally writes to a new file by outputing the average colour value, again of each of the 4x4 cells. This creates a sort of mosaic/pixelation effect.
Having performance profiled my code, the main bottlenecks are fscanf and fprintf. I am ignoring execution time to read/write to disk, so these two functions do not matter.
My effort to optimise so far:
Loop jamming: There are two nested FOR loops within the code which have the exact same loop conditions. However, the second set of nested FOR loops requires that the functions needed to calculate the average RGB value are kept outside of that specific set. The average RGB value calculations are then needed for use in the third set of nested FOR loops (which have the same loop conditions as the second set). Because of this, I have struggled to combine the second and third sets of nested FOR loops despite their similarity.
Loop invariant computations: I have tried to move certain operations outside of the loop where possible, but this has proven to be difficult.
To summarise: How can I optimise this program to reduce the execution time as much as possible?
My code:
typedef struct { //struct holding RGB type int
int r, g, b; //12 bytes
} pixelInt;
typedef struct { //struct holding RGB type unsigned char
unsigned char r, g, b; //3 bytes
} pixel;
int c = 4; // Variable of 4x4 grids
int width, height; //image variable declarations
//Raw 1 dimensional store of pixel data - will contain all the data for each pixel in the image
pixel *data = (pixel *)calloc(width * height, sizeof(pixelInt));
//Loop through entire input image
for (int yy = 0; yy < height; yy += c)
{
for (int xx = 0; xx < width; xx += c)
{
//the total colour of cell of size 'c'
pixelInt cell_tot = { 0, 0, 0 }; //zero initialize struct containing mosaic cell pixel totals.
unsigned int counter = 0; //the counter for how many pixels are in a 4x4 cell
int bx = xx + c; //used in loop conditions
int by = yy + c;
// Store each color from the cell into cell_tot struct
for (int y = yy; y < by; y++)
{
for (int x = xx; x < bx; x++)
{
unsigned int index_1d = x + y * width; //calculate 1d index from x-index (x), y-index(y) and width;
unsigned char r, g, b; //maximum vales are 255, i.e. unsigned char data type
fscanf(f, "%hhu %hhu %hhu", &r, &g, &b); //%hhu is unsigned char specifier
//store the pixel value into data array
data[index_1d].r = r;
data[index_1d].g = g;
data[index_1d].b = b;
counter++; //increment counter
//average pixel color of cell
cell_tot.r += r;
cell_tot.g += g;
cell_tot.b += b;
}
}
//average colour of cell found by dividing cell total by loop counter
pixel cell_average;
cell_average.r = cell_tot.r / counter;
cell_average.g = cell_tot.g / counter;
cell_average.b = cell_tot.b / counter;
//Loop through the new image in cells of size c
for (int y = yy; y < by; y++)
{
for (int x = xx; x < bx; x++)
{
unsigned int index_1d = x + y * width; //calculate 1d index from x-index (x), y-index(y) and width;
//Assign average cell value to the pixels in the cell
data[index_1d].r = cell_average.r;
data[index_1d].g = cell_average.g;
data[index_1d].b = cell_average.b;
//Output the average colour value for the image
fprintf(f_output, "%hhu %hhu %hhu \t", data[index_1d].r, data[index_1d].g, data[index_1d].b);
}
fprintf(f_output, "\n"); //Prints new line
}
}
}
On a 1024x1024 image on my machine your code executes in 0.325s. The following code executes in 0.182s:
unsigned w = width/c, h = height/c;
unsigned *accum = (unsigned*)malloc(3*sizeof(unsigned)*w);
char *line = (char*)malloc(12*w);
unsigned denom = c*c;
//Loop through entire input image
for (int yy = 0; yy < h; ++yy)
{
memset(accum, 0, 3*sizeof(unsigned)*w);
// read and accumulate c lines
for(int y = 0; y < c; ++y)
{
for (int xx = 0; xx < w; ++xx)
{
for (int x = 0; x < c; ++x)
{
unsigned char r, g, b;
fscanf(f, "%hhu %hhu %hhu", &r, &g, &b);
accum[3*xx+0] += r;
accum[3*xx+1] += g;
accum[3*xx+2] += b;
}
}
}
// format a line
for(int xx = 0; xx < w; ++xx)
{
char *cell = line + 12*c*xx;
snprintf(cell, 12, "%3u%4u%4u", accum[3*xx]/denom, accum[3*xx+1]/denom, accum[3*xx+2]/denom);
cell[11] = '\t';
for(int x = 1; x < c; ++x)
memcpy(cell + 12*x, cell, 12);
}
// write it out times c
line[12*w-1] = '\n';
for(int y = 0; y < c; ++y)
fwrite(line, 12*w, 1, f_output);
}
The trick here is to format the averaged values only once and then duplicate the formatted strings. Also by acting on one row at a time I have better chances of utilizing the memory caches.
To go beyond that you would need to re-implement the fscanf to parse the integers faster.
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.