본문 바로가기

IT/OPENCV

[OPENCV] 8. 이미지 프로세싱(3) - 모폴로지 연산

반응형

☞ 메인보드 : Jetson Nano Developer Kit

운영 체제 : Ubuntu 18.04 - JetPack 4.4.1

☞ IDE : Visual Studio Code

☞ 언어 : C++

 

 

 

 


목차

1. 모폴로지란?

2. 침식과 팽창

3. 열기와 닫기

 

 

 


 

 

 

① 모폴로지란?

모폴로지(Mophology)는 형태학을 나타내는 말이다. 형태학은 생물의 구조와 형태에 대해 연구하는 학문인데 왜 이미지 프로세스에 포함이 되는가? 라는 생각이 들 것이다. 형태학과 마찬가지로 모폴로지는 영상(이미지) 내의 구조와 형태에 대해 분석한다. 특히 0과 1로 이루어진 이진 상태에서 형태 변화를 주기 위해서 사용한다. 영상에 존재하는 엣지나 덩어리 형태(집합)의 픽셀을 추출하고, 노이즈 제거와 같이 이미지 프로세싱이 진행되면서 발생되는 불확실한 영역을 단순화하여 작업 진행을 매끄럽게한다는 장점이 있다.

 

 

 


② 침식과 팽창

 

기본적인 모폴로지 기법으로는 침식(erosion)과 팽창(dilation) 두 가지가 있다. 침식 연산은 3 x 3의 정방형 구조의 마스크에서 객체의 (모든 방향) 가생이를 깎아내거나 주요 객체로 부터 독립된 소수의 픽셀을 제거한다. 이미지 내의 객체가 배경에 비해 축소된다. 반대로 팽창 연산은 객체의 빈 구멍을 채워넣고 객체의 크기를 확장시키면서 뚜렷하게 만들거나 독립된 것들을 하나의 객체로 만들 때 사용한다.

 

 

※ 침식

 

void erode( InputArray src, OutputArray dst, InputArray kernel, Point anchor = Point(-1,-1), int iterations = 1, int borderType = BORDER_CONSTANT, const Scalar& borderValue = morphologyDefaultBorderValue() );

 

 

 

※ 팽창

 

void dilate( InputArray src, OutputArray dst, InputArray kernel, Point anchor = Point(-1,-1), int iterations = 1, int borderType = BORDER_CONSTANT, const Scalar& borderValue = morphologyDefaultBorderValue() );

 

 

 

※ 소스 코드

 

#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>

int main(){
    cv::Mat src;

    src = cv::imread("road2.jpg", cv::IMREAD_COLOR);
    cv::resize(src, src, cv::Size(src.cols/2, src.rows/2));
    if(src.empty()){
        std::cout << "Can't Open Image" << std::endl;
        return -1;
    }

    cv::Mat gray, binary;
    cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY);
    cv::threshold(gray, binary, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);

    cv::Mat erosion, dilation;
    cv::erode(binary, erosion, cv::Mat());
    cv::dilate(binary, dilation, cv::Mat());

    cv::imshow("erosion", erosion);
    cv::imshow("dilation", dilation);
    cv::waitKey(0);

    return 0;

}

 

 

 

 

※ 실행 결과

 

 

원본 (왼쪽) , 바이너리(오른쪽)
침식(왼쪽) , 팽창(오른쪽)

 

 


③ 열기와 닫기

침식과 팽창 기법 이외에도 소개되는 두 가지 방법은 열기(opening)와 닫기(closing)이다. 열기와 닫기는 앞서 설명한 침식과 팽창 연산을 반복적으로 수행하는 기법이다. 열기는 침식 후 팽창 연산을 수행하고, 닫기는 팽창 후 침식을 수행한다. 순서만 바꾸어 연산한 것이 무슨 차이인지 모르겠으나 실제로 같은 이미지나 영상을 사용하여도 결과는 분명히 다르게 나타난다. 열기는 가생이의 돌출한 픽셀들이 정리되고 소형의 객체들을 제거한다. 닫기는 객체 내부 구멍이 채워진다. 크기는 침식, 팽창을 한 번씩 수행하기 때문에 큰 변화는 없다.

 

 

※ 열기와 닫기

 

void morphologyEx( InputArray src, OutputArray dst, int op, InputArray kernel, Point anchor = Point(-1,-1), int iterations = 1, int borderType = BORDER_CONSTANT, const Scalar& borderValue = morphologyDefaultBorderValue() );

 

int op 자리에서 모폴로지 연산을 골라 넣을 수 있다. [ 열기 -> cv::MORPH_OPEN , 닫기 -> cv::MORPH_CLOSE ]

iterations 는 반복 횟 수를 의미한다. 기본 값은 한 번으로 설정되어 있으며, 더 정밀한 변화를 위해서 사용하지만 너무 많이 사용하면 이미지가 손상될 수 있으니 주의하기 바란다.

 

 

 

 

※ 소스 코드

 

#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>

int main(){
    cv::Mat src;

    src = cv::imread("road2.jpg", cv::IMREAD_COLOR);
    cv::resize(src, src, cv::Size(src.cols/2, src.rows/2));
    if(src.empty()){
        std::cout << "Can't Open Image" << std::endl;
        return -1;
    }

    cv::Mat gray, binary;
    cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY);
    cv::threshold(gray, binary, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);

    cv::Mat opening, closing;
    cv::morphologyEx(binary, opening, cv::MORPH_OPEN, cv::Mat());
    cv::morphologyEx(binary, closing, cv::MORPH_CLOSE, cv::Mat());

    cv::imshow("binary", binary);
    cv::imshow("opening", opening);
    cv::imshow("closing", closing);
    cv::waitKey(0);

    return 0;

}

 

 

 

 

 

※ 실행 결과

 

 

 

침식(왼쪽) , 팽창(오른쪽)
열기(왼쪽) , 닫기(오른쪽)

 

 

 

 

 

 

 

 

 

반응형