๐Ÿฆ„AI/Computer Vision

[Computer Vision/OpenCV] 14. Image Denoising

mingyung 2025. 4. 5. 23:50

์˜ค๋Š˜ ํฌ์ŠคํŒ…์—์„œ๋Š” ๋Œ€ํ‘œ์ ์ธ Degradation model ์ธ salt and pepper ์™€ gaussian noise๋ฅผ ์—†์• ๋Š” denoising๋ฐฉ์‹์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด๊ณ  ์ฝ”๋“œ ์‹ค์Šต์„ ํ•œ๋‹ค.

 

1. Salt & Pepper Noise

Salt and Pepper noise๋Š” ๋ Œ๋คํ•œ ์œ„์น˜์— ์ƒ์„ฑ๋˜๋Š” ์  ํ˜•ํƒœ์˜ ๋…ธ์ด์ฆˆ์ด๋‹ค.

intensity ๊ฐ€ 255 ๋„๋Š” 0์ธ ํ”ฝ์…€์ด ์ƒ์„ฑ๋˜๋Š”๋ฐ, ์ด๋Š” ์ฃผ๋กœ ์„ผ์„œ์˜ ์˜ค๋ฅ˜๋‚˜ ์ „์†ก ์ค‘์— ์ƒ๊ธด ์—ฌ๋Ÿฌ ๋ฌธ์ œ๋กœ ์ธํ•ด ๋ฐœ์ƒํ•œ๋‹ค.

 

๊ทธ๋Ÿผ ์ด ๋…ธ์ด์ฆˆ๋Š” ์–ด๋–ป๊ฒŒ denoisingํ•  ์ˆ˜ ์žˆ์„๊นŒ?

 

1.1. Low-pass Filter

์ด ๋…ธ์ด์ฆˆ์˜ ๊ฒฝ์šฐ  low pass filter๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ณ ์ฃผํŒŒ ์žก์Œ์„ ์ œ๊ฑฐํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ denoising ํ•  ์ˆ˜ ์žˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค๋ฉด, Uniform Averaging Filter๋‚˜ Gaussian Averaging Filter๊ฐ™์€ ๊ฒƒ์œผ๋กœ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ๋‹ค. 

๊ทผ๋ฐ ์ƒ๊ฐ๋ณด๋‹ค effectiveํ•˜์ง€๋Š” ์•Š๋‹ค.

average filter๋กœ gaussian filter๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค.

 

์ด ๋ฐฉ์‹์ด ํšจ๊ณผ์ ์ด์ง€ ์•Š์€ ์ด์œ ๋Š” filter์˜ ํŠน์ง•์„ ์ƒ๊ฐํ•ด๋ณด๋ฉด ์•Œ ์ˆ˜ ์žˆ๋‹ค.

Averaging filter์˜ ๊ฒฝ์šฐ ํ•„ํ„ฐ ๋งˆ์Šคํฌ๋ฅผ ์ด์šฉํ•ด์„œ ๋งˆ์Šคํฌ ๋งŒํผ์˜ ํ”ฝ์…€๊ฐ’๋“ค์˜ ๊ฐ€์ค‘ ํ•ฉ์„ ํ†ตํ•ด์„œ ๊ตฌํ•˜๊ฒŒ ๋œ๋‹ค.

 

๋”ฐ๋ผ์„œ ์—ฌ๊ธฐ์— ๋“ค์–ด๊ฐ€๋Š” ํ”ฝ์…€ ๊ฐ’์ด 0์ด๋‚˜ 255์ฒ˜๋Ÿผ ๊ทน๋‹จ์ ์ธ ๊ฐ’์ด ๊ฐ‘์ž๊ธฐ ๋“ค์–ด๊ฐ€๋ฉด, 

ํ•„ํ„ฐ๋ง์˜ ๊ฒฐ๊ณผ๋„ ๊ทธ๋งŒํผ ํฌ๊ฒŒ ์˜ํ–ฅ์„ ๋ฐ›๋Š”๋‹ค.

 

๊ทธ๋Ÿฌ๋‹ˆ Averaging ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋Š” ํ•„ํ„ฐ๋Š” ํฐ ํšจ๊ณผ๊ฐ€ ์—†๋Š” ๊ฒƒ์ด๋‹ค.

 

1.2. Median Filter

median filter๋ผ๋Š” ๊ฒƒ์€ Aberaging๋ฐฉ์‹๊ณผ ๋‹ค๋ฅด๊ฒŒ,

์ปค๋„ ์œˆ๋„์šฐ๋งŒํผ์˜ ํ”ฝ์…€๊ฐ’๋“ค ์ค‘ ์ค‘์•™๊ฐ’์œผ๋กœ ํ•„ํ„ฐ๋ง ํ•˜๋Š” ๋ฐฉ์‹๋“ค์„ ๋งํ•œ๋‹ค.

 

Salt and Pepper noise๋Š” ๊ทน๋‹จ์ ์ธ ๊ฐ’์„ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์„œ ์•„์›ƒ๋ผ์ด์–ด ๋…ธ์ด์ฆˆ๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ

์ค‘์•™๊ฐ’์„ ํ™œ์šฉํ•˜๋ฉด ์ด๋“ค์„ ๋ฌด์‹œํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— Denoising์— ํฐ ํšจ๊ณผ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

 

1.3. Outlier Rejection Method

Median filter์˜ ๊ฒฝ์šฐ ์ข‹์€ ํšจ๊ณผ๋ฅผ ๋ณด์ด์ง€๋งŒ, ํ•ด๋‹น ํ”ฝ์…€์˜ ๊ฐ’๋“ค์„ ์ •๋ ฌํ•˜๊ณ , ์„ ํƒํ•˜๋Š” ๊ณผ์ •์„ ๊ฑฐ์ณ์•ผ ํ•œ๋‹ค.

๋”ฐ๋ผ์„œ Bruteforce ๋ฐฉ์‹์œผ๋กœ ๋™์ž‘ํ•˜๋ฏ€๋กœ, ๊ดธ์žฅํžˆ ๋А๋ฆฌ๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค. 

์ด ๋‹จ์ ์„ ๋ณด์™„ํ•˜๊ธฐ ์œ„ํ•ด์„œ ๋‚˜์˜จ ๊ฒƒ์ด Outlier Rejection Method์ด๋‹ค.

 

Salt and Pepper์˜ ๊ฒฝ์šฐ ์•„์›ƒ๋ผ์ด์–ด๋ผ๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค. 

์•„์›ƒ๋ผ์ด์–ด ํ”ฝ์…€๋“ค์€ ์ด์›ƒ ํ”ฝ์…€๋“ค๊ณผ ๋‹ฌ๋ฆฌ ๊ต‰์žฅํžˆ ๋‹ค๋ฅธ ํ”ฝ์…€๊ฐ’์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๋Š” ์ ์„ ๊ณ ๋ คํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.

Outlier Rejection  ๋ฐฉ๋ฒ•์€ ํ•„ํ„ฐ๋ง ๋Œ€์ƒ ํ”ฝ์…€(์ค‘์‹ฌ ํ”ฝ์…€)๊ณผ ์ฃผ๋ณ€ ์ด์›ƒ ํ”ฝ์…€๋“ค ๊ฐ„์˜ ํ†ต๊ณ„์  ์ฐจ์ด๋ฅผ ํ™œ์šฉํ•˜์—ฌ,

์ค‘์‹ฌ ํ”ฝ์…€์ด ์ฃผ๋ณ€๊ณผ ์ง€๋‚˜์น˜๊ฒŒ ๋‹ค๋ฅธ ๊ฒฝ์šฐ์—๋งŒ ๋ณด์ •ํ•œ๋‹ค.

 

๊ณผ์ •์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

1. ์ž์‹ ์„ ์ œ์™ธํ•œ ์ฃผ๋ณ€ ํ”ฝ์…€๋“ค์˜ ํ‰๊ท  M์„ ์–ป๋Š”๋‹ค

2. ์ž์‹ ๊ณผ M ์‚ฌ์ด์˜ ์ฐจ์ด๊ฐ€ ์ž„๊ณ„๊ฐ’ D ์ด์ƒ์ด๋ผ๋ฉด ์ด์ƒ์น˜๋ผ๊ณ  ํŒ๋‹จํ•œ๋‹ค.

3. ์ด์ƒ์น˜ ๋ฐ์ดํ„ฐ๋Š” M๊ฐ’์œผ๋กœ ๋Œ€์ฒดํ•œ๋‹ค.

 

 

 

1.4. OpenCv C++ code

์œ„์˜ ์‹คํ—˜์— ์‚ฌ์šฉ๋œ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

๋”๋ณด๊ธฐ
#include <opencv2/opencv.hpp>
#include <iostream>
#include <random>
#include <numeric>

using namespace cv;
using namespace std;


// Salt and Pepper Noise ์ถ”๊ฐ€
void addSaltAndPepperNoise(cv::Mat& image, double amount) {
    srand(42); // ๊ณ ์ • ์‹œ๋“œ

    //์ „์ฒด ํ”ฝ์…€์ˆ˜๋ฅผ ๊ณ ๋ คํ•ด์„œ amount๋งŒํผ์˜ ๋…ธ์ด์ฆˆ ์ถ”๊ฐ€
    int totalPixels = image.rows * image.cols;
    int numSalt = static_cast<int>(amount / 2 * totalPixels);
    int numPepper = static_cast<int>(amount / 2 * totalPixels);

	// Salt ๋…ธ์ด์ฆˆ ์ถ”๊ฐ€
    for (int i = 0; i < numSalt; ++i) {
        int y = rand() % image.rows;
        int x = rand() % image.cols;
        image.at<uchar>(y, x) = 255; // salt
    }

	// Pepper ๋…ธ์ด์ฆˆ ์ถ”๊ฐ€
    for (int i = 0; i < numPepper; ++i) {
        int y = rand() % image.rows;
        int x = rand() % image.cols;
        image.at<uchar>(y, x) = 0; // pepper
    }
}

// Gaussian ํ•„ํ„ฐ๋ง (ํ‰๊ท  ํ•„ํ„ฐ๋ณด๋‹ค ๋” ๋ถ€๋“œ๋Ÿฝ๊ฒŒ ์ฒ˜๋ฆฌ๋จ)
Mat averageFilter(const Mat& input, int ksize) {
    Mat output;
    // sigmaX๋Š” ์ž๋™ ์ถ”์ •๋œ๋‹ค. ksize๋Š” ํ™€์ˆ˜์—ฌ์•ผ ํ•จ
    GaussianBlur(input, output, Size(ksize, ksize), 0);
    return output;
}

// ์ค‘์•™๊ฐ’ ํ•„ํ„ฐ๋ง (Rank-order ํ•„ํ„ฐ์˜ ๋Œ€ํ‘œ์ ์ธ ์˜ˆ)
Mat medianFilter(const Mat& input, int ksize) {
    Mat output;
    medianBlur(input, output, ksize); // ksize๋Š” ํ™€์ˆ˜๋งŒ ๊ฐ€๋Šฅ
    return output;
}
// Outlier Rejection ํ•„ํ„ฐ๋ง
Mat outlierRejectionFilter(const Mat& input, int ksize, int threshold = 35) {
    Mat output = input.clone();
    int half = ksize / 2;

    for (int y = half; y < input.rows - half; ++y) {
        for (int x = half; x < input.cols - half; ++x) {
            std::vector<uchar> neighbors;
            for (int j = -half; j <= half; ++j) {
                for (int i = -half; i <= half; ++i) {
                    if (i == 0 && j == 0) continue; // center ์ œ์™ธ
                    neighbors.push_back(input.at<uchar>(y + j, x + i));
                }
            }
            double mean = accumulate(neighbors.begin(), neighbors.end(), 0.0) / neighbors.size();
            uchar center = input.at<uchar>(y, x);
            if (abs(center - mean) > threshold) {
                output.at<uchar>(y, x) = static_cast<uchar>(mean);
            }
        }
    }

    return output;
}

int main() {
    // ๊ทธ๋ ˆ์ด์Šค์ผ€์ผ ์ด๋ฏธ์ง€ ๋กœ๋“œ
    cv::Mat img = cv::imread("lena.jpg", cv::IMREAD_GRAYSCALE);
    if (img.empty()) {
        std::cerr << "์ด๋ฏธ์ง€๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค." << std::endl;
        return -1;
    }

    // ๋…ธ์ด์ฆˆ ์ถ”๊ฐ€
    Mat noisy = img.clone();
    addSaltAndPepperNoise(noisy, 0.10); // 10% ๋…ธ์ด์ฆˆ

    // ํ•„ํ„ฐ๋ง
    Mat avgFiltered = averageFilter(noisy, 3);
    Mat medFiltered = medianFilter(noisy, 3);
    Mat outlierFiltered = outlierRejectionFilter(noisy, 3);

    // ๊ฒฐ๊ณผ ์ถœ๋ ฅ
    imshow("Original", img);
    imshow("Noisy", noisy);
    imshow("Average Filter", avgFiltered);
    imshow("Median Filter", medFiltered);
    imshow("Outlier Rejection", outlierFiltered);
    waitKey(0);

    return 0;
}

 

2. Gaussian Noise

Gaussian Noise๋Š” ์ด๋ฏธ์ง€์— ์ถ”๊ฐ€๋˜๋Š” ํ™•๋ฅ ์  ๋…ธ์ด์ฆˆ ์ค‘ ํ•˜๋‚˜๋กœ,

ํ”ฝ์…€ ๊ฐ’์— ์ •๊ทœ๋ถ„ํฌ(๊ฐ€์šฐ์‹œ์•ˆ ๋ถ„ํฌ)๋ฅผ ๋”ฐ๋ฅด๋Š” ๋ฌด์ž‘์œ„ ๊ฐ’์ด ๋”ํ•ด์ง€๋Š” ํ˜•ํƒœ์ด๋‹ค.

 

+) AWGN

์ด ์ค‘์—์„œ๋„ ํ‰๊ท ์ด 0์ด๊ณ , ๋ชจ๋“  ํ”ฝ์…€์— ๋…๋ฆฝ์ ์œผ๋กœ ๋™์ผํ•œ ํ™•๋ฅ ๋กœ ๋…ธ์ด์ฆˆ๊ฐ€ ์ ์šฉ๋˜๋Š”

Additive White Gaussian Noise (AWGN) ๋ชจ๋ธ์€ ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ๊ฐ€์ •์ด๋‹ค.

AWGN ์˜ ์ค‘์š”ํ•œ ํŠน์„ฑ์€ ํ‰๊ท ์ด 0์ด๋ผ๋Š” ์ ์ด๋‹ค.

์ด ์„ฑ์งˆ์€ ๋™์ผํ•œ ์ด๋ฏธ์ง€์— ์„œ๋กœ ๋‹ค๋ฅธ Gaussian ๋…ธ์ด์ฆˆ๊ฐ€ ์ถ”๊ฐ€๋œ ์—ฌ๋Ÿฌ ๊ด€์ธก๊ฐ’์ด ์กด์žฌํ•  ๊ฒฝ์šฐ,

๊ทธ ํ‰๊ท ์„ ์ทจํ•จ์œผ๋กœ์จ ๋…ธ์ด์ฆˆ๋ฅผ ์ƒ์‡„์‹œํ‚ค๊ณ  ์›๋ณธ ์ด๋ฏธ์ง€๋ฅผ ๋ณต์›ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค.

 

์˜ˆ๋ฅผ ๋“ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

100์žฅ์˜ ์ด๋ฏธ์ง€ I+๊ฐ€์šฐ์‹œ์•ˆ ๋…ธ์ด์ฆˆ ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋‹ค๊ณ  ํ•˜์ž. ์ด๋ฅผ ์ˆ˜์‹์œผ๋กœ ํ‘œํ˜„ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

 

์ด 100์žฅ์˜ ๋…ธ์ด์ฆˆ ์ด๋ฏธ์ง€๋ฅผ ํ‰๊ท ์„ ๋‚ธ๋‹ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋  ๊ฒƒ์ด๋‹ค.

 

๊ทผ๋ฐ ๋…ธ์ด์ฆˆ N ์€ ํ‰๊ท ์ด 0์ธ ๊ฐ€์šฐ์‹œ์•ˆ ๋ถ„ํฌ๋ฅผ ๋”ฐ๋ฅด๋ฏ€๋กœ,  ์ € ๋…ธ์ด์ฆˆ ๋ถ€๋ถ„์€ ๊ทผ์‚ฌ์ ์œผ๋กœ 0 ์ด ๋  ๊ฒƒ์ด๋‹ค.

 

๋”ฐ๋ผ์„œ ๊ฐ™์€ ์ด๋ฏธ์ง€์— Gaussian ๋…ธ์ด์ฆˆ๊ฐ€ ์ถ”๊ฐ€๋œ ๋‹ค์ˆ˜์˜ ๊ด€์ธก์ด ์กด์žฌํ•  ๊ฒฝ์šฐ, ํ‰๊ท ์„ ํ†ตํ•ด ๋…ธ์ด์ฆˆ๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  ์›๋ณธ ์ด๋ฏธ์ง€์— ์ˆ˜๋ ดํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. 

 

AWGN์„ ์ถ”๊ฐ€ํ–ˆ๋‹ค. ์•„๋ž˜์˜ denoising์— ์ด ๋…ธ์ด์ฆˆ ์ด๋ฏธ์ง€๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๋‹ค.

 

 

๊ทธ๋Ÿผ ์ด์ œ ๊ฐ€์šฐ์‹œ์•ˆ ๊ณ„์—ด ๋…ธ์ด์ฆˆ๋ฅผ denoisingํ•˜๋Š” ํ•„ํ„ฐ๋ง ๋ฐฉ๋ฒ•์„ ์‚ดํŽด๋ณด์ž.

 

2.1. Averaging Filter ๊ณ„์—ด

Gaussian filter๋‚˜, Uniform mean Filter ๊ฐ™์€ Averaging filter๋“ค์„ ์‚ฌ์šฉํ•˜์—ฌ Denoisingํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ฐ€์žฅ ๋‹จ์ˆœํ•˜๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์–ด์„œ ์ข‹์ง€๋งŒ, averaging๊ณผ์ • ์ค‘์—์„œ ์„ธ๋ถ€ ์ •๋ณด๊ฐ€ ์†์‹ค๋˜๋Š” ๊ฒƒ์ด ๋งŽ์„ ์ˆ˜ ์žˆ๋‹ค. 

๋งŒ์•ฝ ํ•„ํ„ฐ์˜ ํฌ๊ธฐ๊ฐ€ 3x3์ฒ˜๋Ÿผ ์ž‘์€ ๊ฒฝ์šฐ๋ผ๋ฉด, denoising์ด ์ž˜ ์•ˆ๋  ์ˆ˜ ์žˆ๊ณ ,

๊ทธ๋ ‡๋‹ค๊ณ  ํ•„ํ„ฐ์˜ ํฌ๊ธฐ๋ฅผ ํ‚ค์šฐ๋ฉด ๋„ˆ๋ฌด Blurred๋œ๋‹ค๋Š” ๊ฒƒ์ด ํฐ ๋‹จ์ ์ด๋‹ค.

์™„์ชฝ์•„ ๊ฐ€์šฐ์‹œ์•ˆ ๋…ธ์ด์ฆˆ ์ ์šฉ ์ด๋ฏธ์ง€, ์˜ค๋ฅธ์ชฝ์ด Denoising๊ฒฐ๊ณผ์ด๋‹ค.

 

 

 

 

2.2. Bilateral Filtering

Uniform ํ•„ํ„ฐ๋Š” ํ”ฝ์…€๊ฐ„์˜ ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ ๋ คํ•˜์ง€ ์•Š์ง€๋งŒ, ๊ฐ€์šฐ์‹œ์•ˆ ํ•„ํ„ฐ๋Š” ํ”ฝ์…€๊ฐ„์˜ ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ ๋ คํ•œ๋‹ค๋Š” ์ ์ด ์žฅ์ ์ด๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ๊ฐ€์šฐ์‹œ์•ˆ ํ•„ํ„ฐ์˜ ๋ฌธ์ œ์ ์€ ์˜ค๋ฒ„์Šค๋ฌด๋”ฉ ํ˜„์ƒ์ด ๋ฐœ์ƒํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

ํ”ฝ์…€๊ฐ„์˜ ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ ๋ คํ•˜์ง€๋งŒ, Intensity์˜ ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ ๋ คํ•˜์ง€๋Š” ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

Bilatteral Filtering์€ ๊ฐ€์šฐ์‹œ์•ˆ ํ•„ํ„ฐ๋ง์— intensity๋„ ํ•จ๊ป˜ ๊ณ ๋ คํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค. 

์ฆ‰, spatial distance์™€ intensity distance๋ฅผ ๋ชจ๋‘ ๊ณ ๋ คํ•œ๋‹ค. 

๋”ฐ๋ผ์„œ ํ•„ํ„ฐ๋ง ์ปค๋„์˜ ์ˆ˜์‹์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

 

์ฆ‰, ๊ณต๊ฐ„์ ์œผ๋กœ ๊ฐ€๊นŒ์šธ ์ˆ˜๋ก, ํ”ฝ์…€๋ฐ๊ธฐ๊ฐ€ ์œ ์‚ฌํ•  ์ˆ˜๋ก ์˜ํ–ฅ์„ ํฌ๊ฒŒ ์ฃผ๋Š” ๋ฐฉํ–ฅ์œผ๋กœ ์„ค๊ณ„๋˜์—ˆ๋‹ค.

 

์™„์ชฝ์˜ ๋…ธ์ด์ฆˆ๋ฅผ Bilateral filter๋ฅผ ์ ์šฉํ•ด ์ œ๊ฑฐํ•˜๋Š” ์˜ˆ์‹œ.

 

+) Gaussian filter vs Bilateral filter

๋‘ ํ•„ํ„ฐ์˜ ํŠน์ง•์„ ๋น„๊ตํ•˜๋ฉด ๋‹ค๋ฆ„๊ณผ ๊ฐ™๋‹ค.

 

๊ฐ€์šฐ์‹œ์•ˆ ํ•„ํ„ฐ๋Š”

๊ฑฐ๋ฆฌ ๊ธฐ๋ฐ˜ ๊ฐ€์ค‘ ํ‰๊ท ์„ ์‚ฌ์šฉํ•œ๋‹ค.

๋…ธ์ด์ฆˆ ์ œ๊ฑฐ ์„ฑ๋Šฅ์ด ๋†’์ง€๋งŒ, ์—ฃ์ง€ ๋ณด์กด ๋Šฅ๋ ฅ์ด ๋–จ์–ด์ง„๋‹ค.

 

Bilateral filter๋Š” 

๊ฑฐ๋ฆฌ์™€ ๋ฐ๊ธฐ ๊ธฐ๋ฐ˜ ๊ฐ€์ค‘ ํ‰๊ท  ํ•„ํ„ฐ์ด๋‹ค.

๋…ธ์ด์ฆˆ ์ œ๊ฑฐ ์„ฑ๋Šฅ๋„ ๋†’๊ณ , ์—ฃ์ง€๋„ ์ž˜ ๋ณด์กดํ•˜๋Š” ๊ท ํ˜•์žกํžŒ ํ•„ํ„ฐ๋ง ๋ฐฉ์‹์ด๋‹ค.

๋‹ค๋งŒ ๊ฑฐ๋ฆฌ์— ์ถ”๊ฐ€๋กœ ๋ฐ๊ธฐ ๊ฑฐ๋ฆฌ๊นŒ์ง€ ๊ณ„์‚ฐํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์—ฐ์‚ฐ๋ณต์žก๋„๊ฐ€ ๋งค์šฐ ํฌ๋‹ค

 

๋‘ ํ•„ํ„ฐ์— spatial sigma๋ฅผ ๋™์ผํ•˜๊ฒŒ ๋‘˜ ๊ฒฝ์šฐ ๋‘˜์˜ denoising์€ ๋‹ค์Œ์ฒ˜๋Ÿผ ๋œ๋‹ค.

๋ฏธ์„ธํ•˜๊ฒŒ bilateral ์ชฝ์ด ๋” ์„ ๋ช…ํ•˜๋‹ค

 

 

2.3. OpenCV C++ Code

์œ„์˜ ์‹ค์Šต์€ ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด์„œ ์ˆ˜ํ–‰๋˜์—ˆ๋‹ค.

๋”๋ณด๊ธฐ
#include <opencv2/opencv.hpp>
#include <iostream>
#include <random>

using namespace std;

// Gaussian Noise ์ถ”๊ฐ€ ํ•จ์ˆ˜
void addGaussianNoise(cv::Mat& image, double mean = 0.0, double stddev = 20.0) {
    cv::Mat noise(image.size(), CV_32FC1);
    cv::randn(noise, mean, stddev); // ํ‰๊ท , ํ‘œ์ค€ํŽธ์ฐจ

    cv::Mat image32f;
    image.convertTo(image32f, CV_32FC1); // float ๋ณ€ํ™˜
    image32f += noise;

    cv::Mat noisyImage;
    cv::normalize(image32f, image32f, 0, 255, cv::NORM_MINMAX); // ๊ฐ’ ๋ฒ”์œ„ ์ •๊ทœํ™”
    image32f.convertTo(noisyImage, CV_8UC1); // ๋‹ค์‹œ uchar๋กœ

    image = noisyImage.clone();
}

// ๋ฉ”์ธ ํ•จ์ˆ˜
int main() {
    // ๊ทธ๋ ˆ์ด์Šค์ผ€์ผ ์ด๋ฏธ์ง€ ๋กœ๋“œ
    cv::Mat img = cv::imread("lena.jpg", cv::IMREAD_GRAYSCALE);
    if (img.empty()) {
        cerr << "์ด๋ฏธ์ง€๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค." << endl;
        return -1;
    }

    // ์›๋ณธ ๋ณต์‚ฌ ํ›„ Gaussian ๋…ธ์ด์ฆˆ ์ถ”๊ฐ€
    cv::Mat noisy = img.clone();
    addGaussianNoise(noisy);

    // ์„ค์ •๊ฐ’ (๊ณต๊ฐ„ ์‹œ๊ทธ๋งˆ)
    int kernelSize = 5;         // Gaussian ์ปค๋„ ํฌ๊ธฐ (ํ™€์ˆ˜)
    double sigmaSpace = 2.0;    // ๊ณต๊ฐ„ ์‹œ๊ทธ๋งˆ (๋‘ ํ•„ํ„ฐ์— ๋™์ผ ์ ์šฉ)
    double sigmaColor = 75.0;   // Bilateral ํ•„ํ„ฐ์˜ ๋ฐ๊ธฐ ์‹œ๊ทธ๋งˆ


    // Gaussian ํ•„ํ„ฐ ์ ์šฉ
    cv::Mat gaussianFiltered;
    cv::GaussianBlur(noisy, gaussianFiltered, cv::Size(kernelSize, kernelSize), sigmaSpace);

    // Bilateral ํ•„ํ„ฐ ์ ์šฉ
    cv::Mat bilateralFiltered;
    cv::bilateralFilter(noisy, bilateralFiltered, kernelSize, sigmaColor, sigmaSpace);

    // ๊ฒฐ๊ณผ ์ถœ๋ ฅ
    cv::imshow("Original", img);
    cv::imshow("Gaussian Noise", noisy);
    cv::imshow("Gaussian Filter", gaussianFiltered);
    cv::imshow("Bilateral Filter", bilateralFiltered);

    cv::waitKey(0);
    return 0;
}