【이미지 처리 100개 노크에 도전】Q.19. LoG 필터

16885 단어 C++이미지 처리

사용한 라이브러리



【화상 처리 100개 노크】 독자적인 화상 입출력 클래스를 만든다

Q.19. LoG 필터



LoG 필터(sigma=3, 커널 사이즈=5)를 구현하여 imori_noise.jpg의 에지를 검출하라.
LoG 필터는 Laplacian of Gaussian이며, 가우시안 필터로 이미지를 평활화 한 후 라플라시안 필터로 윤곽을 추출하는 필터입니다.
Laplcian 필터는 2차 미분을 취하기 때문에 노이즈가 강조되는 것을 막기 위해, Gaussian 필터로 노이즈를 미리 억제한다.

컨벌루션 식의 미분을 생각하면, 이 경우 커널을 2층 미분하고 나서 컨벌루션하면 좋은 것을 알 수 있습니다.
int main()
{
    PPM ppm("imori_noise.pnm");
    int width = ppm.Get_width();
    int height = ppm.Get_height();
    PPM ppm2(width, height);

    auto kernel = [&](int i, int j)
    {
        double ret = 0;
        double sigma = 3, pi = 3.141592653589793;;
        if (abs(i) <= 2 && abs(j) <= 2)
        {
            double x = i, y = j;
            ret = (x * x + y * y - sigma * sigma) / (2. * pi * sigma * sigma * sigma * sigma * sigma * sigma) * exp(-(x*x + y*y) / (2. * sigma * sigma));
        }
        return ret;

    };

    auto conv = [&](const std::vector<std::vector<double>>& f)
    {
        std::vector < std::vector < double >> ret(width, std::vector<double>(height));
        for (int j = 0; j < height; j++)
            for (int i = 0; i < width; i++)
            {
                ret[i][j] = 0;
            }
        for (int j = 0; j < height; j++)
            for (int i = 0; i < width; i++)
            {
                double sum = 0;
                for (int di = -2; di <= 2; di++)
                    for (int dj = -2; dj <= 2; dj++)
                    {
                        if (i - di >= 0 && i - di < width && j - dj >= 0 && j - di < height)
                        {
                            ret[i][j] += kernel(di, dj) * f[i - di][j - dj];
                            sum += kernel(di, dj);
                        }
                    }
                ret[i][j] /= sum;
                //std::cout << sum << std::endl;
            }
        return ret;
    };

    std::vector < std::vector < double >> arry(width, std::vector<double>(height));
    for (int j = 0; j < height; j++)
        for (int i = 0; i < width; i++)
        {
            int r = ppm(i, j, 'r');
            int g = ppm(i, j, 'g');
            int b = ppm(i, j, 'b');
            int y = (std::round)(0.2126 * r + 0.7152 * g + 0.0722 * b);
            arry[i][j] = y;
        }
    arry = conv(arry);

    for (int j = 0; j < height; j++)
        for (int i = 0; i < width; i++)
        {
            int val = abs(arry[i][j]);
            if (val > 255) val = 255;
            ppm2(i, j, 'r') = val;
            ppm2(i, j, 'g') = val;
            ppm2(i, j, 'b') = val;

        }

    ppm2.Flush("out.ppm");
    return 0;
}


흐림이 들어 있기 때문에, 너무 엣지가 추출되어 있지 않다. 무엇에 사용하는 거야?
어쨌든 이것으로 필터 지옥에서 벗어났습니다! 여기에서 잠시 히스토그램 조작 같네요.

좋은 웹페이지 즐겨찾기