Scaling up an image using nearest-neighbor
I see that you're overcomplicating things (walking over the image twice for example).
Here's the code (I am posting the whole program - I made assumptions about Pixel and Image that might not match what you have), but if you copy / paste makeBigger it should work in your code OOTB:
code00.c:
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
typedef uint32_t Pixel;
typedef struct {
uint32_t width, height;
Pixel **pixels;
} Image;
void makeBigger(Image *img, int scale)
{
uint32_t i = 0, j = 0;
Image *tmp = (Image*)malloc(sizeof(Image));
tmp->height = img->height * scale;
tmp->width = img->width * scale;
tmp->pixels = (Pixel**)malloc(sizeof(Pixel*) * tmp->height);
for (i = 0; i < tmp->height; i++) {
tmp->pixels[i] = (Pixel*)malloc(sizeof(Pixel) * tmp->width);
for (j = 0; j < tmp->width; j++) {
tmp->pixels[i][j] = img->pixels[i / scale][j / scale];
}
}
for (i = 0; i < img->height; i++)
free(img->pixels[i]);
free(img->pixels);
img->width = tmp->width;
img->height = tmp->height;
img->pixels = tmp->pixels;
free(tmp);
}
void printImage(Image *img)
{
printf("Width: %d, Height: %d\n", img->width, img->height);
for (uint32_t i = 0; i < img->height; i++) {
for (uint32_t j = 0; j < img->width; j++)
printf("%3d", img->pixels[i][j]);
printf("\n");
}
printf("\n");
}
int main()
{
uint32_t i = 0, j = 0, k = 1;
Image img;
// Initialize the image
img.height = 2;
img.width = 3;
img.pixels = (Pixel**)malloc(sizeof(Pixel*) * img.height);
for (i = 0; i < img.height; i++) {
img.pixels[i] = (Pixel*)malloc(sizeof(Pixel) * img.width);
for (j = 0; j < img.width; j++)
img.pixels[i][j] = k++;
}
printImage(&img);
makeBigger(&img, 2);
printImage(&img);
// Destroy the image
for (i = 0; i < img.height; i++)
free(img.pixels[i]);
free(img.pixels);
printf("\nDone.\n");
return 0;
}
Notes (makeBigger related - designed to replace the content of the image given as argument):
- Construct a temporary image that will be the enlarged one
- Only traverse the temporary image once (populate its pixels as we allocate them); to maintain scaling to the original image and make sure that the appropriate pixel is "copied" into the new one, simply divide the indexes by the scaling factor:
tmp->pixels[i][j] = img->pixels[i / scale][j / scale]
- Deallocate the original image content: since each pixel row is malloced, it should also be freed (
free(img->pixels);
alone will yield memory leaks) - Store the temporary image content (into the original one) and then deallocate it
Output:
[cfati@cfati-5510-0:/cygdrive/e/Work/Dev/StackOverflow/q041861274]> ~/sopr.sh ### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ### [064bit prompt]> ls code00.c [064bit prompt]> gcc -o code00.exe code00.c [064bit prompt]> ./code00.exe Width: 3, Height: 2 1 2 3 4 5 6 Width: 6, Height: 4 1 1 2 2 3 3 1 1 2 2 3 3 4 4 5 5 6 6 4 4 5 5 6 6 Done.
Henke
Updated on October 30, 2021Comments
-
Henke over 2 years
I have been trying to make my program scale up an image. I had some problem to allocate new space for my scaled image, but I think it is fixed. The problem I am having is that the program crashes when I am trying to send back my image from my temporary memory holder.
The loaded image is placed in my
struct
Image
. The pixels are placed inimg->pixels
, the height inimg->height
and the width inimg->width
. But I have no idea why the program crashes when I transfer the pixels from mytmp2
struct
to myimg
struct
while it does not crash when I do the opposite. Here is the code:void makeBigger(Image *img, int scale) { Image *tmp2; tmp2 = (Image*)malloc(sizeof(Image)); tmp2->height = img->height*scale; tmp2->width = img->width*scale; tmp2->pixels = (Pixel**)malloc(sizeof(Pixel*)*tmp2->height); for (unsigned int i = 0; i < img->height; i++) { tmp2->pixels[i] = (Pixel*)malloc(sizeof(Pixel)*tmp2->width); for (unsigned int j = 0; j < img->width; j++) { tmp2->pixels[i][j] = img->pixels[i][j]; } } free(img->pixels); //scaling up the struct's height and width img->height *= scale; img->width *= scale; img->pixels = (Pixel**)malloc(sizeof(Pixel*)*img->height); for (unsigned int i = 0; i < tmp2->height; i++) { img->pixels[i] = (Pixel*)malloc(sizeof(Pixel)*img->width); for (unsigned int j = 0; j < tmp2->width; j++) { img->pixels[i][j] = tmp2->pixels[i+i/2][j+j/2]; } } }
I would be glad if you have any idea of how to make the nearest-neighbor method to work.
EDIT: I am trying to crop the inner rectangle so I can scale it up (zoom).
Image *tmp = (Image*)malloc(sizeof(Image)); tmp->height = img->height / 2; tmp->width = img->width / 2; tmp->pixels = (Pixel**)malloc(sizeof(Pixel*) * tmp->height); for (unsigned i = img->height / 4 - 1; i < img->height - img->height / 4; i++) { tmp->pixels[i] = (Pixel*)malloc(sizeof(Pixel) * tmp->width); for (unsigned j = img->width / 4; j < img->width - img->width / 4; j++) { tmp->pixels[i][j] = img->pixels[i][j]; } } for (unsigned i = 0; i < img->height; i++) { free(img->pixels[i]); } free(img->pixels); img->height = tmp->height; img->width = tmp->width; img->pixels = tmp->pixels; free(tmp);
-
Henke about 7 yearsThis works flawlessly and perfectly. Thank you for this well detailed answer! I hope others can get help from your answer now aswell :)
-
Henke about 7 yearsOh btw, I am trying to zoom into the image now. And my thought is that I first take a piece of the middle and after that make it the same size as the original. But I cant get the middle piece... Do you know what is wrong? I will edit my question.
-
CristiFati about 7 yearsI'm afraid I don't understand the comment (nor did I see any edits to the question). Zooming is what nearest neighbor does (in for scaling factor >1, out for (0..1)). If you want to only scale a part of the image, you have to pass its bounding rectangle, and the
for
loops won't iterate from [0..height
/width
], but from [y1. . y2] / [x1..x2], where y is on theheight
axis, and x on thewidth
one. -
Henke about 7 yearsYeah okey thank you. Sorry about that, but I was in a hurry yesterday, and apparently my edit never saved due to an error when I pasted my code. However, I did try that method, but something goes wrong when I am trying to save the image.
-
Henke about 7 yearsOkey, so I tried to crop the image so I later could upscale it. But I can not do it. I posted the code here.
-
CristiFati about 7 yearsYou're doing the same mistake. Look at how I am traversing the temporary image (2nd bullet): the indexes (
for
loops) should always go through [0..height
/width
], and coordinates translation (between images) should look like:tmp->pixels[i][j] = img->pixels[img->height / 4 + i][img->width / 4 + j];
. -
Henke about 7 yearsHum, I need to keep this in mind... Well thank you again :) Of course it worked.