-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprocess.c
More file actions
366 lines (320 loc) · 11.1 KB
/
Copy pathprocess.c
File metadata and controls
366 lines (320 loc) · 11.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
/* This coursework specification, and the example code provided during the
* course, is Copyright 2024 Heriot-Watt University.
* Distributing this coursework specification or your solution to it outside
* the university is academic misconduct and a violation of copyright law. */
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
/* The RGB values of a pixel. */
struct Pixel
{
int red;
int green;
int blue;
};
/* An image loaded from a file. */
struct Image
{
/* TODO: Question 1 */
int height;
int width;
struct Pixel *pixel;
};
/* Free a struct Image */
void free_image(struct Image *img)
{
/* TODO: Question 2a */
free(img->pixel); // free the memory allocated for the pixel
free(img); // free the memory allocated to the structure
}
/* Opens and reads an image file, returning a pointer to a new struct Image.
* On error, prints an error message and returns NULL. */
struct Image *load_image(const char *filename)
{
/* Open the file for reading */
// Opening the file using 'rb' because the data is in binary
FILE *f = fopen(filename, "rb");
if (f == NULL)
{
fprintf(stderr, "File %s could not be opened.\n", filename);
return NULL;
}
/* Allocate the Image object, and read the image from the file */
/* TODO: Question 2b */
struct Image *img = (struct Image *)malloc(sizeof(struct Image));
// Allocate memory to store image structure
char img_format[6]; // Variable to store the image format
fscanf(f, "%s", img_format); // read the image format from the file
fscanf(f, "%d %d", &img->width, &img->height); // read the image dimentions from the file
int size = img->width * img->height; // calculate the size of image by multiplying height and width
img->pixel = malloc(sizeof(struct Pixel) * size); // allocate memory for the pixels
for (int i = 0; i < size; i++)
{
// Read the red, green, blue values of the image pixels
if (fread(&(img->pixel[i].red), sizeof(__uint8_t), 1, f) != 1 ||
fread(&(img->pixel[i].green), sizeof(__uint8_t), 1, f) != 1 ||
fread(&(img->pixel[i].blue), sizeof(__uint8_t), 1, f) != 1)
{
printf("Error: Could not read pixel data from file.\n");
return NULL;
}
}
/* Close the file */
fclose(f);
if (img == NULL)
{
fprintf(stderr, "File %s could not be read.\n", filename);
return NULL;
}
return img;
}
/* Write img to file filename. Return true on success, false on error. */
bool save_image(const struct Image *img, const char *filename)
{
/* TODO: Question 2c */
// we open the file to write in 'wb' because the data is in binary
FILE *f = fopen(filename, "wb");
if (f == NULL)
{
fprintf(stderr, "File %s could not be opened.\n", filename);
return NULL;
}
// calculating the size of the image
int size = img->width * img->height;
// writing the image format to the file
int written = fprintf(f, "HS8 ");
// writing the image dimentions to the file
fprintf(f, "%d %d\n", img->width, img->height);
for (int i = 0; i < size; i++)
{
// write the pixel data into the file
fwrite(&img->pixel[i].red, sizeof(__uint8_t), 1, f);
fwrite(&img->pixel[i].green, sizeof(__uint8_t), 1, f);
fwrite(&img->pixel[i].blue, sizeof(__uint8_t), 1, f);
}
fclose(f);
// checking if the writing was successful using if condition
if (written < 0)
{
return false;
}
else
{
return true;
}
}
/* Allocate a new struct Image and copy an existing struct Image's contents
* into it. On error, returns NULL. */
struct Image *copy_image(const struct Image *source)
{
/* TODO: Question 2d */
struct Image *copy = malloc(sizeof(struct Image)); // allocate memory for the new image structure
int size = source->width * source->height;
copy->width = source->width; // copy width from the source image
copy->height = source->height; // copy heigt from the source image
copy->pixel = malloc(sizeof(struct Pixel) * size); // allocate memory for the pixels
for (int i = 0; i < size; i++)
{
// copy all the pixel data from the source image to the copy image
copy->pixel[i].red = source->pixel[i].red;
copy->pixel[i].green = source->pixel[i].green;
copy->pixel[i].blue = source->pixel[i].blue;
}
return copy;
}
/* Perform your first task.
* (TODO: Write a better comment here, and rename the function.
* You may need to add or change arguments depending on the task.)
* Returns a new struct Image containing the result, or NULL on error. */
struct Image *apply_NOISE(const struct Image *source, int noise)
{
struct Image *img = copy_image(source); // copy the source image to a new image to add noise
int size = source->width * source->height;
for (int i = 0; i < size; i++)
{
// generate random noise for red, blue and green
int red_noise = (rand() % (2 * noise + 1) - noise);
int green_noise = (rand() % (2 * noise + 1) - noise);
int blue_noise = (rand() % (2 * noise + 1) - noise);
// printf("Generated noise: R=%d, G=%d, B=%d\n", red_noise, green_noise, blue_noise);
// add the generated random noise to the red, green and blue pixels
img->pixel[i].red += red_noise;
img->pixel[i].green += green_noise;
img->pixel[i].blue += blue_noise;
// clamp the pixel values so it doesn't go out of the bound
if (img->pixel[i].red < 0)
{
img->pixel[i].red = 0;
}
if (img->pixel[i].red > 255)
{
img->pixel[i].red = 255;
}
if (img->pixel[i].green < 0)
{
img->pixel[i].green = 0;
}
if (img->pixel[i].green > 255)
{
img->pixel[i].green = 255;
}
if (img->pixel[i].blue < 0)
{
img->pixel[i].blue = 0;
}
if (img->pixel[i].blue > 255)
{
img->pixel[i].blue = 255;
}
// printf("Resulting pixel: R=%d, G=%d, B=%d\n", img->pixel[i].red, img->pixel[i].green, img->pixel[i].blue);
}
return img;
}
/* Perform your second task.
* (TODO: Write a better comment here, and rename the function.
* You may need to add or change arguments depending on the task.)
* Returns true on success, or false on error. */
bool apply_COMP(const struct Image *ref_img, const struct Image *in_img)
{
/* TODO: Question 4 */
// using variables to count the identical and different pixels
int identical_pixels = 0;
int different_pixels = 0;
int ref_size = ref_img->height * ref_img->width; // calculating the size of the reference image
int in_size = in_img->height * in_img->width; // calculating the size of input image
int min_size;
int remaining;
// finding the smaller image from refernce and input
if (ref_size < in_size)
{
min_size = ref_size;
}
else
{
min_size = in_size;
}
for (int i = 0; i < min_size; i++)
{
// loop through pixels in both images and compare if the RGB values are equl
if (ref_img->pixel[i].red == in_img->pixel[i].red &&
ref_img->pixel[i].green == in_img->pixel[i].green &&
ref_img->pixel[i].blue == in_img->pixel[i].blue)
{
// if the values are equal add to identical pixels
identical_pixels++;
}
else
{
// if the values are not equal add it to the different pixels
different_pixels++;
}
}
// If one image is larger than other count the remaining pixels and add them to different pixels
if (min_size == ref_size)
{
remaining = (in_size - ref_size);
different_pixels += remaining;
}
else
{
remaining = (ref_size - in_size);
different_pixels += remaining;
}
// Print how many identical and different pixels are there
printf("Identical pixels: %d \n", identical_pixels);
printf("Different pixels: %d \n", different_pixels);
return true;
}
int main(int argc, char *argv[])
{
/* Initialise the random number generator, using the time as the seed */
/* TODO: Remove this if you don't need to use rand() */
srand(time(NULL));
/* Check command-line arguments */
if (argc < 5 || argc % 2 != 1)
{
fprintf(stderr, "Usage: process REFERENCE_IMAGE INPUTFILE1 OUTPUTFILE1 [INPUTFILE2 OUTPUTFILE2 ...] NOISE\n");
return 1;
}
/*Allocating an array*/
int img_num = (argc - 3) / 2; // calculate the number of input images
struct Image *array = malloc(img_num * sizeof(struct Image)); // allocate memory for an array of pointers
if (array == NULL)
{
fprintf(stderr, "Memory allcation failed\n");
return 1;
}
/* Load the reference image */
for (int i = 0; i < img_num; i++)
{
// load the input images into the array
array[i] = *load_image(argv[2 + 2 * i]);
if (&array[i] == NULL)
{
fprintf(stderr, "Loading image from %s failed.\n", argv[2 + 2 * i]);
// free memory for the images that are already loaded
for (int j = 0; j < i; j++)
{
free_image(&array[j]);
}
free(array);
return 1;
}
}
// load the reference image
struct Image *reference_img = load_image(argv[1]);
if (reference_img == NULL)
{
return 1;
}
// get the noise from the command line args
int noise = atoi(argv[argc - 1]);
// process each input image
for (int i = 0; i < img_num; i++)
{
// apply noise to the input image
struct Image *out_img = apply_NOISE(&array[i], noise);
if (out_img == NULL)
{
fprintf(stderr, "First process failed.\n");
// free memory for the images that are already loaded
for (int j = 0; j < img_num; j++)
{
free_image(&array[j]);
}
free(array);
return 1;
}
// compare the images to the reference image
if (!apply_COMP(reference_img, &array[i]))
{
fprintf(stderr, "Second process failed.\n");
// free memory for the images that are already loaded
for (int j = 0; j < img_num; j++)
{
free_image(&array[j]);
}
free(array);
free_image(out_img);
return 1;
}
// save the noise image to the output file
if (!save_image(out_img, argv[2 * i + 3]))
{
fprintf(stderr, "Saving image to %s failed.\n", argv[2 * i + 3]);
free_image(out_img);
for (int j = 0; j < img_num; j++)
{
free_image(&array[j]);
}
free(array);
return 1;
}
free_image(out_img);
}
// free the allocated memory to prevent leaks
free(array);
return 0;
}