Лапласский фильтр opencv c ++ - PullRequest
0 голосов
/ 27 августа 2018

Я изучал фильтры в OpenCV, но меня немного смущает использование фильтра Лапласа. Мой результат сильно отличается от фильтра Лапласа в библиотеке OpenCV.

Для начала я использую фильтр Гаусса для изображения:

Mat filtroGauss(Mat src){
    Mat gauss = src.clone();
    Mat temp(src.rows+2,src.cols+2,DataType<uchar>::type);

    int y,x;
    for (y=0; y<src.rows; y++){
    for (x=0; x<src.cols; x++) temp.at<uchar>(y+1,x+1) = src.at<uchar>(y,x);
        }

    int mask[lenMask*lenMask];
    mask[0] = mask[2] = mask[6] = mask[8] = 1;
    mask[1] = mask[3] = mask[5] = mask[7] = 2;
    mask[4] = 4;

    int denominatore = 0;
    for (int i=0; i<lenMask*lenMask; i++) denominatore += mask[i];

    int value[lenMask*lenMask];
    for(y=0; y<src.rows; y++){
        for (x=0; x<src.cols; x++){
            value[0] = temp.at<uchar>(y-1,x-1)*mask[0];
            value[1] = temp.at<uchar>(y-1,x)*mask[1];
            value[2] = temp.at<uchar>(y-1,x+1)*mask[2];
            value[3] = temp.at<uchar>(y,x-1)*mask[3];
            value[4] = temp.at<uchar>(y,x)*mask[4];
            value[5] = temp.at<uchar>(y,x+1)*mask[5];
            value[6] = temp.at<uchar>(y+1,x-1)*mask[6];
            value[7] = temp.at<uchar>(y+1,x)*mask[7];
            value[8] = temp.at<uchar>(y+1,x+1)*mask[8];

            int avg = 0;
            for(int i=0; i<lenMask*lenMask; i++)avg+=value[i];
            avg = avg/denominatore;

            gauss.at<uchar>(y,x) = avg;
        }
    }
    return gauss;
}

Тогда я использую функцию Лапласа:

L(y,x) = f(y-1,x) + f(y+1,x) + f(y,x-1) + f(y,x+1) + 4*f(y,x)

Mat filtroLaplace(Mat src){
    Mat output = src.clone();
    Mat temp = src.clone();

    int y,x;
    for (y =1; y<src.rows-1; y++){
        for(x =1; x<src.cols-1; x++){

            output.at<uchar>(y,x) = temp.at<uchar>(y-1,x) + temp.at<uchar>(y+1,x) + temp.at<uchar>(y,x-1) + temp.at<uchar>(y,x+1) -4*( temp.at<uchar>(y,x));
        }
    }
    return output;
    }

И вот окончательный результат из моего кода:


Результат OpenCV:

1 Ответ

0 голосов
/ 27 августа 2018

Давайте немного перепишем функцию, чтобы ее было проще обсудить:

cv::Mat filtroLaplace(cv::Mat src)
{
    cv::Mat output = src.clone();

    for (int y = 1; y < src.rows - 1; y++) {
        for (int x = 1; x < src.cols - 1; x++) {
            int sum = src.at<uchar>(y - 1, x)
                + src.at<uchar>(y + 1, x)
                + src.at<uchar>(y, x - 1)
                + src.at<uchar>(y, x + 1)
                - 4 * src.at<uchar>(y, x);

            output.at<uchar>(y, x) = sum;
        }
    }
    return output;
}

Источник вашей проблемы sum. Давайте рассмотрим его диапазон в рамках этого алгоритма, взяв две крайности:

  • Черный пиксель, окруженный 4 белыми. Это значит 255 + 255 + 255 + 255 - 4 * 0 = 1020.
  • Белый пиксель, окруженный 4 черными. Это значит 0 + 0 + 0 + 0 - 4 * 255 = -1020.

Когда вы выполняете output.at<uchar>(y, x) = sum;, происходит неявное приведение int обратно к unsigned char - биты старших разрядов просто обрезаются, а значение переполняется.

Правильный подход к решению этой ситуации (которую использует OpenCV) заключается в выполнении насыщения перед фактическим приведением. По существу

if (sum < 0) {
    sum = 0;
} else if (sum > 255) {
    sum = 255;
}

OpenCV предоставляет функцию cv::saturate_cast<T>, чтобы сделать это.


Существует дополнительная проблема, заключающаяся в том, что вы не обрабатываете края / столбцы входного изображения - вы просто оставляете их с исходным значением. Поскольку вы не спрашиваете об этом, я оставлю решение для читателя в качестве упражнения.


Код:

cv::Mat filtroLaplace(cv::Mat src)
{
    cv::Mat output = src.clone();

    for (int y = 1; y < src.rows - 1; y++) {
        for (int x = 1; x < src.cols - 1; x++) {
            int sum = src.at<uchar>(y - 1, x)
                + src.at<uchar>(y + 1, x)
                + src.at<uchar>(y, x - 1)
                + src.at<uchar>(y, x + 1)
                - 4 * src.at<uchar>(y, x);

            output.at<uchar>(y, x) = cv::saturate_cast<uchar>(sum);
        }
    }
    return output;
}

Пример ввода:

Выход исправлен filtroLaplace:

Выход cv::Laplacian:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...