Множественные проблемы с алгоритмом Собеля в c

Я пытаюсь создать программу обнаружения краев, используя приведенный ниже код. Однако я столкнулся с множеством проблем, которые я не знаю, как решить.

#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 небезопасно.

И последнее, но не менее важное: я получил еще одну ошибку, в которой говорилось, что я израсходовал всю доступную память стека.

Любые предложения будут приветствоваться.

РЕДАКТИРОВАТЬ: Многие из вас предположили, что я вызвал переполнение стека. В качестве альтернативы я попытаюсь использовать динамическую память. Моя вторая проблема все еще остается, хотя.

Почти все компиляторы помещают локальные переменные в куча. И стек — это ограниченный ресурс, в Windows по умолчанию он составляет всего один единственный мегабайт. Предполагая 4-байтовый int, ваши массивы составляют около 13 мегабайт. Это не подойдет. Переменные, определенные вне функций, помещаются в другое место в памяти, где у вас гораздо больше места.

Some programmer dude 14.05.2022 17:01
Кажется, что программа отлично работает при запуске в devcpp ide, и все матрицы объявляются как глобальные переменные. Всякий раз, когда я объявляю их внутри основной функции, программа вылетает. В последнем случае они попадают в стек. Существует только ограниченное количество места в стеке. В Linux размер стека по умолчанию составляет 8 МБ, но в Windows, IIRC, всего 4 МБ. У вас есть: 700 * 1244 * 4 * 4 --> 13 923 800 байт.
Craig Estey 14.05.2022 17:01
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
59
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Определение ваших матриц как локальных переменных с автоматическим хранением использует около 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 15.05.2022 12:16

@AlexandrosS: ваш компилятор настроен не на компиляцию программ C, а на C++. void * может быть неявно преобразован в любой тип данных в C, в отличие от C++, где требуется явное приведение. Актерский состав будет (int (*)[COLS]).

chqrlie 15.05.2022 12:28

Итак, я должен попробовать что-то вроде (int (*) Gradient [COLS]) = calloc (sizeof (* Gradient), ROWS); ? Извините за вопросы, которые могут показаться глупыми, но я впервые делаю что-то подобное.

AlexandrosS 15.05.2022 12:56

@AlexandrosS: нет, сначала вы должны попытаться заставить Microsoft IDE учитывать расширение файла и скомпилировать свой код как C, а не C++. Если вы не можете этого сделать, используйте int (*Gradient)[COLS] = (int (*)[COLS])calloc(sizeof(*Gradient), ROWS);

chqrlie 15.05.2022 13:12

@AlexandrosS: я опубликовал альтернативу, используя единую структуру, которую, вероятно, легче понять, чем выделенные 2D-матрицы.

chqrlie 15.05.2022 13:20

@AlexandrosS: вы можете принять ответ, нажав на серую галочку под его оценкой.

chqrlie 16.05.2022 00:36

Другие вопросы по теме