I'm trying to build an edge detection program using the code below. I have faced a variety of problems though, that I don't know how to solve.
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#define xrows 700
#define ycolumns 1244
int Gradient[xrows][ycolumns];
int Image_input[xrows][ycolumns];
int G_x[xrows][ycolumns];
int G_y[xrows][ycolumns];
int main() {
FILE *fw = fopen("sobel_outt.txt", "w");
FILE *fr = fopen("ny.txt", "r");
int x, y, row, column, num;
int i = 0;
int XLENGTH = 700;
int YLENGTH = 1244;
for (row = 0; row < XLENGTH; row++) {
for (column = 0; column < YLENGTH; column++) {
fscanf(fr, "%d " ",", &num);
Image_input[row][column] = num;
}
}
fclose(fr);
for (x = 0; x < XLENGTH; x += 3) {
i++;
for (y = 0; y < YLENGTH; y += 3) {
if ((x == 0) || (x == XLENGTH - 1) || (y == 0) || (y == YLENGTH - 1)) {
G_x[x][y] = G_y[x][y] = Gradient[x][y] = 0;
} else {
G_x[x][y] = Image_input[x + 1][y - 1]
+ 2 * Image_input[x + 1][y]
+ Image_input[x + 1][y + 1]
- Image_input[x - 1][y - 1]
- 2 * Image_input[x - 1][y]
- Image_input[x - 1][y + 1];
G_y[x][y] = Image_input[x - 1][y + 1]
+ 2 * Image_input[x][y + 1]
+ Image_input[x + 1][y + 1]
- Image_input[x - 1][y - 1]
- 2 * Image_input[x][y - 1]
- Image_input[x + 1][y - 1];
Gradient[x][y] = (abs(G_x[x][y]) + abs(G_y[x][y]));
if (Gradient[x][y] > 255) {
Gradient[x][y] = 255;
}
}
fprintf(fw, "%d,\n", Gradient[x][y]);
}
}
printf("i= %d", i);
fclose(fw);
return 0;
}
The program seems to execute fine when run in the devcpp IDE and all of the matrices are declared as global variables. Whenever I declare them inside the main function, the program crashes.
I tried to run the program using Visual Studio, but I faced a couple more problems. I got some error messages stating that fscanf
is ignored and fprintf
is unsafe.
Last but not least I got another error, stating that I used up all of the stack memory available.
Any suggestions would be welcomed .
EDIT: Many of you suggested that I caused a stack overflow. I will try to use the heap memory as an alternative. My second problem still remains though.
Defining your matrices as local variables with automatic storage uses close to 14MB of stack space. This can definitely cause a stack overflow on many platforms. Allocating the data from the heap is recommended.
Microsoft's Visual C compiler is configured to complain about fscanf
and fprintf
and advocates using fscanf_s
and fprintf_s
instead. They managed to get this and other functions included the C Standard (Annex K) but the API was changed in subtle ways for consistency (using size_t
instead of UINT
for array lengths) and Microsoft did not change their version. This difference was unimportant for 32-bit targets but types size_t
and unsigned
now differ on most 64-bit platforms.
Using fscanf_s()
is therefore not recommended for portable programs. You can disable the compiler warning by adding #define _CRT_SECURE_NO_WARNINGS
before including <stdio.h>
.
Note however that you should not ignore the return value of fscanf()
to detect invalid or missing data: if the conversion fails the destination variable is unchanged, leading to incorrect results or even undefined behavior.
Here is a modified version allocating the matrices from the heap:
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS // disable warnings in fscanf
#endif
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ROWS 700
#define COLS 1244
int main() {
int (*Gradient)[COLS] = calloc(sizeof(*Gradient), ROWS);
int (*Image_input)[COLS] = calloc(sizeof(*Image_input), ROWS);
int (*G_x)[COLS] = calloc(sizeof(*G_x), ROWS);
int (*G_y)[COLS] = calloc(sizeof(*G_y), ROWS);
if (!Gradient || !Image_input || !G_x || !G_y) {
fprintf(stderr, "cannot allocate memory\n");
return 1;
}
FILE *fr = fopen("ny.txt", "r");
if (fr == NULL) {
fprintf(stderr, "cannot open ny.txt: %s\n", strerror(errno));
return 1;
}
FILE *fw = fopen("sobel_outt.txt", "w");
if (fw == NULL) {
fprintf(stderr, "cannot open sobel_outt.txt: %s\n",
strerror(errno));
return 1;
}
int x, y, row, column, num;
int i = 0;
int XLENGTH = ROWS;
int YLENGTH = COLS;
for (row = 0; row < XLENGTH; row++) {
for (column = 0; column < YLENGTH; column++) {
if (fscanf(fr, "%d ,", &num) != 1) {
fprintf(stderr, "cannot read value for Image_input[%d][%d]\n",
row, column);
return 1;
}
Image_input[row][column] = num;
}
}
fclose(fr);
for (x = 0; x < XLENGTH; x += 3) {
i++;
for (y = 0; y < YLENGTH; y += 3) {
if (x == 0 || x == XLENGTH - 1 || y == 0 || y == YLENGTH - 1) {
G_x[x][y] = G_y[x][y] = Gradient[x][y] = 0;
} else {
G_x[x][y] = Image_input[x + 1][y - 1]
+ 2 * Image_input[x + 1][y]
+ Image_input[x + 1][y + 1]
- Image_input[x - 1][y - 1]
- 2 * Image_input[x - 1][y]
- Image_input[x - 1][y + 1];
G_y[x][y] = Image_input[x - 1][y + 1]
+ 2 * Image_input[x][y + 1]
+ Image_input[x + 1][y + 1]
- Image_input[x - 1][y - 1]
- 2 * Image_input[x][y - 1]
- Image_input[x + 1][y - 1];
Gradient[x][y] = abs(G_x[x][y]) + abs(G_y[x][y]);
if (Gradient[x][y] > 255) {
Gradient[x][y] = 255;
}
}
fprintf(fw, "%d,\n", Gradient[x][y]);
}
}
fclose(fw);
printf("i= %d\n", i);
free(Gradient);
free(Image_input);
free(G_x);
free(G_y);
return 0;
}
Note that the final value of i
should always be XLENGTH
.
Here is an alternative using a single structure for all data, easier to handle than allocated 2D matrices:
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ROWS 700
#define COLS 1244
struct sobel {
int Gradient[ROWS][COLS];
int Image_input[ROWS][COLS];
int G_x[ROWS][COLS];
int G_y[ROWS][COLS];
};
int main() {
struct sobel *data = (struct sobel *)calloc(sizeof(*data), 1);
if (!data) {
fprintf(stderr, "cannot allocate memory\n");
return 1;
}
FILE *fr = fopen("ny.txt", "r");
if (fr == NULL) {
fprintf(stderr, "cannot open ny.txt: %s\n", strerror(errno));
return 1;
}
FILE *fw = fopen("sobel_outt.txt", "w");
if (fw == NULL) {
fprintf(stderr, "cannot open sobel_outt.txt: %s\n", strerror(errno));
return 1;
}
int x, y, row, column, num;
int i = 0;
int XLENGTH = ROWS;
int YLENGTH = COLS;
for (row = 0; row < XLENGTH; row++) {
for (column = 0; column < YLENGTH; column++) {
if (fscanf(fr, "%d " ",", &num) != 1) {
fprintf(stderr, "cannot read value for Image_input[%d][%d]\n", row, column);
return 1;
}
data->Image_input[row][column] = num;
}
}
fclose(fr);
for (x = 0; x < XLENGTH; x += 3) {
i++;
for (y = 0; y < YLENGTH; y += 3) {
if (x == 0 || x == XLENGTH - 1 || y == 0 || y == YLENGTH - 1) {
data->G_x[x][y] = data->G_y[x][y] = data->Gradient[x][y] = 0;
} else {
data->G_x[x][y] = data->Image_input[x + 1][y - 1]
+ 2 * data->Image_input[x + 1][y]
+ data->Image_input[x + 1][y + 1]
- data->Image_input[x - 1][y - 1]
- 2 * data->Image_input[x - 1][y]
- data->Image_input[x - 1][y + 1];
data->G_y[x][y] = data->Image_input[x - 1][y + 1]
+ 2 * data->Image_input[x][y + 1]
+ data->Image_input[x + 1][y + 1]
- data->Image_input[x - 1][y - 1]
- 2 * data->Image_input[x][y - 1]
- data->Image_input[x + 1][y - 1];
data->Gradient[x][y] = abs(data->G_x[x][y]) + abs(data->G_y[x][y]);
if (data->Gradient[x][y] > 255) {
data->Gradient[x][y] = 255;
}
}
fprintf(fw, "%d,\n", data->Gradient[x][y]);
}
}
fclose(fw);
printf("i= %d\n", i);
free(data);
return 0;
}