C++ Алгоритм Floodfill аварийно завершает работу в Xcode

У меня есть простая функция заполнения, за исключением того, что она вылетает из-за слишком большого количества освобождений во время работы.

#include <vector>
cv::Mat fillLayer(cv::Mat filledEdge, int y, int x, int oldColor, float newColor){
    cv::Size shape = filledEdge.size();
    int h = shape.height;
    int w = shape.width;

    std::vector<int> theStackx = {x};
    std::vector<int> theStacky = {y};


    while (theStacky.size() > 0){
        y = theStacky.back();
        x = theStackx.back();
        theStacky.pop_back();
        theStackx.pop_back();

        if (x == w){
            continue;
        }
        if (x == -1){
            continue;
        }
        if (y == -1){
            continue;
        }
        if (y == h){
            continue;
        }

        if (filledEdge.at<float>(y, x) != oldColor){
            continue;
        }

        filledEdge.at<float>(y, x) = newColor;

        //up
        theStacky.push_back(y + 1);
        theStackx.push_back(x);
        //down
        theStacky.push_back(y - 1);
        theStackx.push_back(x);
        //right
        theStacky.push_back(y);
        theStackx.push_back(x + 1);
        //left
        theStacky.push_back(y);
        theStackx.push_back(x - 1);
    }
    return filledEdge;

}

Функция, которая проходит через заливку, называется fillSurface. который проходит через все пиксели в мате и заполняет их другим цветом для каждой заливки

fillSurface(cv::Mat filledEdge, int oldColor) {
    std::vector<float> layers; //list all the different colors in mat
    cv::Size shape = filledEdge.size();
    int h = shape.height;
    int w = shape.width;
    float newColor;
    // run through all the pixels in Mat
    for(int y = 0; y!= h; y++){
        for(int x = 0; x!= w; x++){
            // only run floodfill if current pixel is oldColor
            if (filledEdge.at<float>(y, x) == oldColor){
                //newColor is random float to fill in to floodfill
                newColor = static_cast <float> ((rand()) / (static_cast <float> (RAND_MAX/253)) + 1); 
                // add newColor to list of layers
                layers.push_back(newColor);
                //run flood fill replacing old color with new color
                filledEdge = fillLayer(filledEdge, y, x, oldColor, newColor);

            }
        }
    }
}

Это ошибка, которую я получаю:

Incorrect checksum for freed object 0x7fea0d89dc00: probably modified after being freed.

Отладка, которую я сделал, заключается в том, чтобы установить точку останова на malloc_error_break(), чтобы увидеть, где именно я получаю перерыв. Это приводит к функции заполнения заливки.

введите здесь описание изображения

Мне интересно, можно ли это как-то исправить. Если нет, то что было бы лучшей альтернативой?


person Cristian    schedule 15.11.2018    source источник
comment
Пожалуйста, отредактируйте свой вопрос, чтобы показать нам, какую отладку вы выполнили. Я ожидаю, что вы запустили свой минимально воспроизводимый пример в Valgrind или аналогичном средстве проверки и исследовали его с помощью отладчика. такие как GDB, например. Убедитесь, что вы также включили полный набор предупреждений компилятора. Что инструменты сказали вам, и какую информацию они упускают? И прочтите статью Эрика Липперта Как отлаживать небольшие программы. .   -  person Toby Speight    schedule 15.11.2018
comment
Ваш код неполный; в частности, отсутствует функция main() и по крайней мере одна функция #include. Пожалуйста, отредактируйте свой код, чтобы он минимально воспроизводимый пример вашей проблемы (включая все необходимые входные данные, но желательно без них), то мы можем попытаться воспроизвести и решить ее. Вы также должны прочитать Как спросить.   -  person Toby Speight    schedule 15.11.2018
comment
Также было бы интересно узнать, насколько велика матрица fillEdge в вашем неудачном тестовом примере. И вам было бы полезно учесть, что вы объявили и инициализировали переменные h и w, но никогда их не использовали. Почему вы не использовали их после того, как создали? Вы, должно быть, думали, что они будут хороши для чего-то. Какие? Возможно, размышление об этом поможет вам увидеть проблему, и это поможет вам решить проблему сбоя.   -  person davidbak    schedule 15.11.2018
comment
Приношу извинения за путаницу, я отредактировал вопрос, добавив отладку и дополнительные сведения о коде. Спасибо   -  person Cristian    schedule 15.11.2018


Ответы (1)


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

Ошибка выполнения гласит: «Неверная контрольная сумма для освобожденного объекта...: вероятно, изменена после освобождения».

Первый намек, который дает вам, заключается в том, что подобные проверки кучи обычно выполняются только тогда, когда происходят операции с кучей, а не когда происходит повреждение. В вашем коде нет явных операций с кучей (например, new или delete). Использование кучи здесь происходит из хорошо документированных и хорошо протестированных структур данных из стандартной библиотеки (vector) и cv (Mat).

Вторая подсказка - probably modified after being freed, но она неполная - другая возможность - код пишется за его пределами - либо переполнение буфера, либо неправильная индексация массива, либо что-то в этом роде.

И этот последний бит подводит нас к документации CV для класса Mat, в которой нигде не упоминается, что произойдет, если вы плохо проиндексируете Mat. В нем есть предупреждения о том, что вы обращаетесь к нужному типу элемента, иначе что-то может пойти не так. И эти вещи вместе могут быть очень сильным намеком на то, что если вы неправильно получите доступ к мату, могут произойти плохие вещи. Типа, если ты пишешь, возможно, повреждение памяти.

Эти вещи вместе, наряду с моим комментарием выше о том, что вы объявляете переменные h и w, но не используете их, и поэтому, для чего именно вы думаете, что будете использовать h и w, должны помочь вам понять, как куча был поврежден до такой степени, что система выполнения жаловалась на это.

Спойлер (для получения наилучших результатов читайте только после решения проблемы):

Запись вне границ Mat, потому что вы никогда не проверяете границы ваших индексов, чтобы они не превышали лимиты, и, по-видимому, Mat::at тоже не проверяет (по крайней мере, в документации не говорится, что это так - вы можете проверить это с помощью эксперимент).

person davidbak    schedule 15.11.2018
comment
Я добавил ограничения, чтобы убедиться, что пиксель (y, x) не выходит за пределы мата (поэтому я определил h и w). До сих пор я предполагаю, что сценарий дает сбой из-за массового использования заливки, которая запускает pop_back() на большом динамическом векторе (что приводит к повреждению данных). это звучит как возможность? - person Cristian; 15.11.2018
comment
Изображение, на котором я работаю, имеет разрешение 224 x 224, в котором скрипт иногда дает сбой, а иногда работает. - person Cristian; 15.11.2018
comment
Не должно быть никаких проблем с добавлением или удалением элементов из вектора, особенно примитивного типа, пока у вас не закончится память в вашем процессе - и это будет выглядеть по-другому (будет выдано исключение нехватки памяти). Я вижу ваш измененный код. Я бы попросил вас подтвердить, экспериментируя или документируя, что вы подписываете свои элементы в правильном порядке. Хотя это не должно иметь значения для квадратного изображения, это будет иметь значение для прямоугольников. Я вижу, вы передаете oldcolor в fillLayer() как int, newcolor как число с плавающей запятой. Что это означает? - person davidbak; 15.11.2018