침식(Erosion)과 팽창(Dilation)은 형태학적 연산의 두 가지 기본 동작입니다. 이름에서 알 수 있듯이, 형태학적(morphological) 연산이란 이미지를 픽셀 값 자체가 아닌 형태(shape)를 기준으로 처리하는 연산들의 집합을 의미합니다.
침식과 팽창의 기본 원리
팽창 연산에서는 이미지 경계에 추가 픽셀이 더해져 밝은 영역이 확장되고, 반대로 침식 연산에서는 이미지 경계의 픽셀이 제거되어 밝은 영역이 축소됩니다. 이때 팽창 과정에서 추가되는 픽셀의 총 개수는 사용되는 구조 요소(Structuring Element), 즉 커널(kernel)의 크기와 모양에 따라 결정됩니다.
형태학적 그래디언트의 정의
형태학적 그래디언트(Morphological Gradient)는 팽창 결과에서 침식 결과를 뺀 차이와 같은 연산입니다. 결과 이미지의 각 픽셀 값은 해당 위치 주변 픽셀들 간의 대비(contrast) 강도를 나타내며, 값이 클수록 밝기 변화가 큰 영역, 즉 가장자리임을 의미합니다.
이러한 특성 덕분에 형태학적 그래디언트는 다음과 같은 용도로 널리 활용됩니다.
- 에지(Edge) 검출: 객체의 경계선을 효과적으로 찾아냅니다.
- 세그멘테이션(Segmentation): 이미지를 의미 있는 영역으로 분할하는 데 도움을 줍니다.
- 객체 윤곽선 추출: 물체의 외곽선(outline)을 명확하게 드러냅니다.
Java 예제 코드
다음 Java 예제는 OpenCV를 사용하여 주어진 이미지의 형태학적 그래디언트를 계산하고, 그 결과를 창에 출력합니다.
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.stage.Stage;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
public class MorphologicalGradient extends Application {
public void start(Stage stage) throws IOException {
// OpenCV 핵심 라이브러리 로드
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
// 이미지 데이터 읽기
String file = "D:\\Images\\morph_input1.jpg";
Mat src = Imgcodecs.imread(file);
// 결과를 저장할 목적 행렬 생성
Mat dst = new Mat(src.rows(), src.cols(), src.type());
// 커널(구조 요소) 행렬 준비
Mat kernel = Mat.ones(5, 5, CvType.CV_32F);
// 이미지에 형태학적 그래디언트 적용
Imgproc.morphologyEx(src, dst, Imgproc.MORPH_GRADIENT, kernel);
// 행렬을 JavaFX WritableImage로 변환
Image img = HighGui.toBufferedImage(dst);
WritableImage writableImage = SwingFXUtils.toFXImage((BufferedImage) img, null);
// 이미지 뷰 설정
ImageView imageView = new ImageView(writableImage);
imageView.setX(10);
imageView.setY(10);
imageView.setFitWidth(575);
imageView.setPreserveRatio(true);
// Scene 객체 설정
Group root = new Group(imageView);
Scene scene = new Scene(root, 595, 400);
stage.setTitle("Morphological Gradient");
stage.setScene(scene);
stage.show();
}
public static void main(String args[]) {
launch(args);
}
}핵심 부분은 Imgproc.morphologyEx() 메서드입니다. 연산 플래그로 Imgproc.MORPH_GRADIENT를 지정하면 OpenCV가 내부적으로 팽창과 침식을 수행한 뒤 그 차이를 계산하여 형태학적 그래디언트 결과를 반환합니다. 여기서는 5×5 크기의 커널을 사용했습니다.
입력 이미지

출력 이미지

출력 이미지를 보면 원본 이미지에서 객체의 가장자리 부분만 밝게 강조된 것을 확인할 수 있습니다. 이것이 바로 형태학적 그래디언트가 에지 검출 및 윤곽선 추출에 유용한 이유입니다.