Хобрук: Ваш путь к мастерству в программировании

Результат лапласовской резкости выглядит серовато-С++

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

Вот моя работа на данный момент

     img = imread("moon.png", 0);
     Mat convoSharp() {

    //creating new image
    Mat res = img.clone();
    for (int y = 0; y < res.rows; y++) {
        for (int x = 0; x < res.cols; x++) {
            res.at<uchar>(y, x) = 0.0;
        }
    }

    //variable declaration
    //change -5 to -4 for original result.
    int filter[3][3] = { {0,1,0},{1,-4,1},{0,1,0} };
    //int filter[3][3] = { {-1,-2,-1},{0,0,0},{1,2,1} };
    int height = img.rows;
    int width = img.cols;
    int **temp = new int*[height];
    for (int i = 0; i < height; i++) {
        temp[i] = new int[width];
    }
    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
            temp[i][j] = 0;
        }
    }
    int filterHeight = 3;
    int filterWidth = 3;
    int newImageHeight = height - filterHeight + 1;
    int newImageWidth = width - filterWidth + 1;
    int i, j, h, w;

    //convolution
    for (i = 0; i < newImageHeight; i++) {
        for (j = 0; j < newImageWidth; j++) {
            for (h = i; h < i + filterHeight; h++) {
                for (w = j; w < j + filterWidth; w++) {
                    temp[i][j] += filter[h - i][w - j] * (int)img.at<uchar>(h, w);
                }
            }
        }
    }

    //find max and min
    int max = 0;
    int min = 100;
    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
            if (temp[i][j] > max) {
                max = temp[i][j];
            }
            if (temp[i][j] < min) {
                min = temp[i][j];
            }
        }
    }

    //clamp 0 - 255
    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
            res.at<uchar>(i, j) = 0 + (temp[i][j] - min)*(255 - 0) / (max - min);
        }
    }

    //empty the temp array
    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
            temp[i][j] = 0;
        }
    }

    //img - res and store it in temp array
    for (int y = 0; y < res.rows; y++) {
        for (int x = 0; x < res.cols; x++) {
            //int a = (int)img.at<uchar>(y, x) - (int)res.at<uchar>(y, x);
            //cout << a << endl;
            temp[y][x] = (int)img.at<uchar>(y, x) - (int)res.at<uchar>(y, x);

        }
    }

    //find the new max and min
    max = 0;
    min = 100;
    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
            if (temp[i][j] > max) {
                max = temp[i][j];
            }
            if (temp[i][j] < min) {
                min = temp[i][j];
            }
        }
    }

    //clamp it back to 0-255
    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
            res.at<uchar>(i, j) = 0 + (temp[i][j] - min)*(255 - 0) / (max - min);
            temp[i][j] = (int)res.at<uchar>(i, j);
        }
    }



    return res;
}

И вот результат

Результат

как вы можете видеть в моем коде выше, я уже нормализовал значение пикселя до 0-255. я до сих пор не знаю, что здесь пошло не так. Кто-нибудь здесь может объяснить, почему так?


  • Вам нужно решение на C++ или C? Не делайте этого дважды, у каждого языка свой подход. 10.10.2018
  • любой язык подойдет! 10.10.2018
  • Пожалуйста, не делай этого, это очень расстраивает. Если вы хотите С++, это нормально. Если вам нужен C, это тоже нормально. Выберите один, это поможет сосредоточить усилия на поиске решения. C++ обязательно включает C, это неявно, но двойная маркировка подразумевает что-то еще. 10.10.2018
  • Например: int **temp = new int*[height]; — это C++, но также, вероятно, плохой план, поскольку std::vector или std::array — это то, что вы обычно используете здесь. Если это должно быть C, то new не может быть и речи. Тег [C] предназначен для тех, кто хочет ответить на вопросы C, а не C++, так что имейте это в виду. 10.10.2018
  • хорошо, дружище, спасибо за вклад, я буду иметь это в виду в следующий раз, когда буду что-то публиковать 10.10.2018
  • Здесь стоит подумать о создании более минимального примера для тестирования. Например, изображение размером 3x3 или 5x5 пикселей в основном может быть протестировано, форма ввода и вывода должна быть достаточно фиксированной. Это очень субъективный тест, затрудняющий понимание сути проблемы. Один из подходов, помогающих взломать этот орех, состоит в том, чтобы разбить ваш код на более конвейерную форму, используя либо дизайн шаблоны или даже разделить его на функции, более ориентированные на миссию. Прямо сейчас это либо работает, либо нет, вы не можете проверить часть этого. 10.10.2018
  • Почему вы используете свой собственный временный массив изображений? У вас есть OpenCV, просто создайте другое изображение (вы можете использовать int вместо char для пикселей) и используйте его. Это также даст вам более простые способы очистки, масштабирования и т. д., чем каждый раз вручную писать 2D-циклы. 10.10.2018
  • Если вы используете new, вам также необходимо использовать delete. В настоящее время у вас происходит утечка памяти. 10.10.2018

Ответы:


1

Серость вызвана тем, что, как предложил Макс в своем ответе, вы масштабируете диапазон 0-255, а не зажимаете (как ваши комментарии в коде предполагают).

Однако это не все проблемы в вашем коде. Выход оператора Лапласа содержит отрицательные значения. Вы красиво храните их в файле int. Но затем вы масштабируете и копируете в char. Не делай этого!

Вам нужно добавить результат Лапласа без изменений к вашему изображению. Таким образом, некоторые пиксели вашего изображения станут темнее, а некоторые светлее. Это то, что заставляет края казаться более четкими.

Просто пропустите некоторые циклы в своем коде и оставьте тот, который выполняет temp = img - temp. Этот результат вы можете свободно масштабировать или ограничивать выходным диапазоном и приводить к char.

Чтобы зафиксировать, просто установите любые значения пикселей ниже 0 на 0, а любые значения выше 255 на 255. Не вычисляйте минимальное/максимальное значение и масштабируйте, как вы это делаете, потому что таким образом вы уменьшаете контраст и создаете сероватое размытие на изображении.

Ваш недавний вопрос очень похож (хотя проблема в коде была другой), снова прочитайте мой ответ, он предлагает способ еще больше упростить ваш код, чтобы img-Laplace стало одной сверткой.

10.10.2018

2

Проблема в том, что вы зажимаете и масштабируете изображение. Посмотрите на нижнюю левую границу луны: рядом с очень темными пикселями есть очень яркие пиксели, а рядом с яркими — несколько серых пикселей. Ваш фильтр повышения резкости действительно будет всплескивать на этой яркой границе и увеличивать максимум. Точно так же черные пиксели будут уменьшены еще больше.

Затем вы определяете минимум и максимум и масштабируете все изображение. Это обязательно означает, что все изображение потеряет контрастность при отображении в предыдущей шкале серого, потому что ваш фильтр выдал значения пикселей выше 255 и ниже 0.

Смотрим внимательно на границу луны на выходном изображении:

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

Есть черный ореол (новый 0) и яркий острый край (новый 255). (Масштабирование изображения в браузере сделало его менее четким на этом снимке экрана, посмотрите исходный результат). Все остальное было раздавлено масштабированием, поэтому то, что раньше было черным (0), теперь стало темно-серым.

10.10.2018
Новые материалы

Учебные заметки JavaScript Object Oriented Labs
Вот моя седьмая неделя обучения программированию. После ruby ​​и его фреймворка rails я начал изучать самый популярный язык интерфейса — javascript. В отличие от ruby, javascript — это более..

Разбор строк запроса в vue.js
Иногда вам нужно получить данные из строк запроса, в этой статье показано, как это сделать. В жизни каждого дизайнера/разработчика наступает момент, когда им необходимо беспрепятственно..

Предсказание моей следующей любимой книги 📚 Благодаря данным Goodreads и машинному обучению 👨‍💻
«Если вы не любите читать, значит, вы не нашли нужную книгу». - J.K. Роулинг Эта статья сильно отличается от тех, к которым вы, возможно, привыкли . Мне очень понравилось поработать над..

Основы принципов S.O.L.I.D, Javascript, Git и NoSQL
каковы принципы S.O.L.I.D? Принципы SOLID призваны помочь разработчикам создавать надежные, удобные в сопровождении приложения. мы видим пять ключевых принципов. Принципы SOLID были разработаны..

Как настроить Selenium в проекте Angular
Угловой | Селен Как настроить Selenium в проекте Angular Держите свое приложение Angular и тесты Selenium в одной рабочей области и запускайте их с помощью Mocha. В этой статье мы..

Аргументы прогрессивного улучшения почти всегда упускают суть
В наши дни в кругах веб-разработчиков много болтают о Progressive Enhancement — PE, но на самом деле почти все аргументы с обеих сторон упускают самую фундаментальную причину, по которой PE..

Введение в Джанго Фреймворк
Схема «работать умно, а не усердно» В этой и последующих статьях я познакомлю вас с тем, что такое фреймворк Django и как создать свое первое приложение с помощью простых и понятных шагов, а..