더북(TheBook)

11.1.3 마스크 기반 엣지 검출기 구현

이 장에서 구현할 특징값 추출 관련 함수들은 새로운 헤더 파일과 C++ 소스 파일에 작성하도록 하자. 새로 추가할 파일의 이름은 IppFeature.h와 IppFeature.cpp이다. Visual Studio에서 [프로젝트] > [새 항목 추가...] 메뉴를 선택하여 IppFeature.h 파일과 IppFeature.cpp 파일을 각각 추가하자.

엣지 검출 마스크를 이용하여 엣지를 찾는 방법은 앞서 8장에서 배웠던 마스크 연산 방법과 완전히 동일하다. 그러므로 실제 구현은 그리 어렵게 느껴지지 않을 것이다. 먼저 IppFeature.h 파일에 소스 11-1과 같이 세 개의 함수 선언을 추가하자.

소스 11-1 마스크 기반 엣지 검출 함수 선언(IppFilter.h)
#pragma once

#include "IppImage.h"

void IppEdgeRoberts(IppByteImage& img, IppByteImage& imgEdge);
void IppEdgePrewitt(IppByteImage& img, IppByteImage& imgEdge);
void IppEdgeSobel(IppByteImage& img, IppByteImage& imgEdge);

이들 함수는 모두 두 개의 인자를 받는다. 첫 번째 인자 img는 입력 영상이며, 두 번째 인자 imgEdge는 엣지 검출 마스크 연산이 수행된 결과가 저장될 영상이다. imgEdge 영상에 저장되는 엣지 검출 결과는 바이너리 값의 형태(0 또는 255)로 저장되지는 않는다. 만약 엣지 검출 결과를 0 또는 255의 값을 갖는 그레이스케일 영상으로 표현하고 싶다면, 13.1절에서 설명할 이진화 기법을 참고하기 바란다. IppEdgeRoberts, IppEdgePrewitt, IppEdgeSobel 함수의 실제 구현은 소스 11-2에 나타내었다.

소스 11-2 마스크 기반 엣지 검출 구현 함수(IppFeature.cpp)
#include "stdafx.h"
#include "IppFeature.h"

void IppEdgeRoberts(IppByteImage& img, IppByteImage& imgEdge)
{
    int w = img.GetWidth();
    int h = img.GetHeight();

    imgEdge.CreateImage(w, h);

    BYTE** p1 = img.GetPixels2D();
    BYTE** p2 = imgEdge.GetPixels2D();

    int i, j, h1, h2;
    double hval;
    for (j = 1; j < h; j++)
    for (i = 1; i < w - 1; i++)
    {
        h1 = p1[j][i] - p1[j - 1][i - 1];
        h2 = p1[j][i] - p1[j - 1][i + 1];

        hval = sqrt(static_cast<double>(h1 * h1 + h2 * h2));

        p2[j][i] = static_cast<BYTE>(limit(hval + 0.5));
    }
}

void IppEdgePrewitt(IppByteImage& img, IppByteImage& imgEdge)
{
    int w = img.GetWidth();
    int h = img.GetHeight();

    imgEdge.CreateImage(w, h);

    BYTE** p1 = img.GetPixels2D();
    BYTE** p2 = imgEdge.GetPixels2D();

    int i, j, h1, h2;
    double hval;
    for (j = 1; j < h - 1; j++)
    for (i = 1; i < w - 1; i++)
    {
        h1 = -p1[j - 1][i - 1] - p1[j - 1][i] - p1[j - 1][i + 1]
            + p1[j + 1][i - 1] + p1[j + 1][i] + p1[j + 1][i + 1];
        h2 = -p1[j - 1][i - 1] - p1[j][i - 1] - p1[j + 1][i - 1]
            + p1[j - 1][i + 1] + p1[j][i + 1] + p1[j + 1][i + 1];

        hval = sqrt(static_cast<double>(h1 * h1 + h2 * h2));
        p2[j][i] = static_cast<BYTE>(limit(hval + 0.5));
    }
}

void IppEdgeSobel(IppByteImage& img, IppByteImage& imgEdge)
{
    int w = img.GetWidth();
    int h = img.GetHeight();

    imgEdge.CreateImage(w, h);

    BYTE** p1 = img.GetPixels2D();
    BYTE** p2 = imgEdge.GetPixels2D();

    int i, j, h1, h2;
    double hval;
    for (j = 1; j < h - 1; j++)
    for (i = 1; i < w - 1; i++)
    {
        h1 = -p1[j - 1][i - 1] - 2 * p1[j - 1][i] - p1[j - 1][i + 1]
            + p1[j + 1][i - 1] + 2 * p1[j + 1][i] + p1[j + 1][i + 1];
        h2 = -p1[j - 1][i - 1] - 2 * p1[j][i - 1] - p1[j + 1][i - 1]
            + p1[j - 1][i + 1] + 2 * p1[j][i + 1] + p1[j + 1][i + 1];

        hval = sqrt(static_cast<double>(h1 * h1 + h2 * h2));

        p2[j][i] = static_cast<BYTE>(limit(hval + 0.5));
    }
}
신간 소식 구독하기
뉴스레터에 가입하시고 이메일로 신간 소식을 받아 보세요.