Я пытаюсь создать программу обнаружения краев, используя приведенный ниже код. Однако я столкнулся с множеством проблем, которые я не знаю, как решить.
#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;
}
Кажется, что программа работает нормально при запуске в devcpp IDE, и все матрицы объявлены как глобальные переменные. Всякий раз, когда я объявляю их внутри основной функции, программа вылетает.
Я попытался запустить программу с помощью Visual Studio, но столкнулся с еще парой проблем. Я получил несколько сообщений об ошибках, в которых говорилось, что fscanf игнорируется, а fprintf небезопасно.
И последнее, но не менее важное: я получил еще одну ошибку, в которой говорилось, что я израсходовал всю доступную память стека.
Любые предложения будут приветствоваться.
РЕДАКТИРОВАТЬ: Многие из вас предположили, что я вызвал переполнение стека. В качестве альтернативы я попытаюсь использовать динамическую память. Моя вторая проблема все еще остается, хотя.
700 * 1244 * 4 * 4 --> 13 923 800 байт.





Определение ваших матриц как локальных переменных с автоматическим хранением использует около 14 МБ пространства стека. Это определенно может вызвать переполнение стека на многих платформах. Рекомендуется размещать данные из кучи.
Компилятор Visual C от Microsoft настроен так, чтобы жаловаться на fscanf и fprintf и вместо этого выступает за использование fscanf_s и fprintf_s. Им удалось получить эту и другие функции, включенные в стандарт C (приложение K), но API был слегка изменен для согласованности (использование size_t вместо UINT для длин массивов), и Microsoft не изменила свою версию. Это различие было несущественным для 32-битных целей, но теперь типы size_t и unsigned различаются на большинстве 64-битных платформ.
Поэтому использование fscanf_s() не рекомендуется для портативных программ. Вы можете отключить предупреждение компилятора, добавив #define _CRT_SECURE_NO_WARNINGS перед включением <stdio.h>.
Однако обратите внимание, что вы не должны игнорировать возвращаемое значение fscanf() для обнаружения недействительных или отсутствующих данных: если преобразование завершается ошибкой, целевая переменная остается неизменной, что приводит к неверным результатам или даже к неопределенному поведению.
Вот модифицированная версия, выделяющая матрицы из кучи:
#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;
}
Обратите внимание, что конечное значение i всегда должно быть XLENGTH.
Вот альтернатива, использующая единую структуру для всех данных, которую легче обрабатывать, чем выделенные 2D-матрицы:
#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;
}
Эй! Только что попробовал ваш код. Кажется, что-то не так с определением динамических матриц. Я получаю следующую ошибку. Значение типа "void " нельзя использовать для инициализации сущности типа "int ()[1244]"
@AlexandrosS: ваш компилятор настроен не на компиляцию программ C, а на C++. void * может быть неявно преобразован в любой тип данных в C, в отличие от C++, где требуется явное приведение. Актерский состав будет (int (*)[COLS]).
Итак, я должен попробовать что-то вроде (int (*) Gradient [COLS]) = calloc (sizeof (* Gradient), ROWS); ? Извините за вопросы, которые могут показаться глупыми, но я впервые делаю что-то подобное.
@AlexandrosS: нет, сначала вы должны попытаться заставить Microsoft IDE учитывать расширение файла .с и скомпилировать свой код как C, а не C++. Если вы не можете этого сделать, используйте int (*Gradient)[COLS] = (int (*)[COLS])calloc(sizeof(*Gradient), ROWS);
@AlexandrosS: я опубликовал альтернативу, используя единую структуру, которую, вероятно, легче понять, чем выделенные 2D-матрицы.
@AlexandrosS: вы можете принять ответ, нажав на серую галочку под его оценкой.
Почти все компиляторы помещают локальные переменные в куча. И стек — это ограниченный ресурс, в Windows по умолчанию он составляет всего один единственный мегабайт. Предполагая 4-байтовый
int, ваши массивы составляют около 13 мегабайт. Это не подойдет. Переменные, определенные вне функций, помещаются в другое место в памяти, где у вас гораздо больше места.