์ค๋ ํฌ์คํ ์์๋ ๋ํ์ ์ธ 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ํ์ง๋ ์๋ค.

์ด ๋ฐฉ์์ด ํจ๊ณผ์ ์ด์ง ์์ ์ด์ ๋ 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 ๋ ธ์ด์ฆ๊ฐ ์ถ๊ฐ๋ ๋ค์์ ๊ด์ธก์ด ์กด์ฌํ ๊ฒฝ์ฐ, ํ๊ท ์ ํตํด ๋ ธ์ด์ฆ๋ฅผ ์ ๊ฑฐํ๊ณ ์๋ณธ ์ด๋ฏธ์ง์ ์๋ ดํ ์ ์๋ค๋ ๊ฒ์ด๋ค.


๊ทธ๋ผ ์ด์ ๊ฐ์ฐ์์ ๊ณ์ด ๋ ธ์ด์ฆ๋ฅผ denoisingํ๋ ํํฐ๋ง ๋ฐฉ๋ฒ์ ์ดํด๋ณด์.
2.1. Averaging Filter ๊ณ์ด
Gaussian filter๋, Uniform mean Filter ๊ฐ์ Averaging filter๋ค์ ์ฌ์ฉํ์ฌ Denoisingํ ์ ์๋ค.
๊ฐ์ฅ ๋จ์ํ๊ฒ ๊ตฌํํ ์ ์์ด์ ์ข์ง๋ง, averaging๊ณผ์ ์ค์์ ์ธ๋ถ ์ ๋ณด๊ฐ ์์ค๋๋ ๊ฒ์ด ๋ง์ ์ ์๋ค.
๋ง์ฝ ํํฐ์ ํฌ๊ธฐ๊ฐ 3x3์ฒ๋ผ ์์ ๊ฒฝ์ฐ๋ผ๋ฉด, denoising์ด ์ ์๋ ์ ์๊ณ ,
๊ทธ๋ ๋ค๊ณ ํํฐ์ ํฌ๊ธฐ๋ฅผ ํค์ฐ๋ฉด ๋๋ฌด Blurred๋๋ค๋ ๊ฒ์ด ํฐ ๋จ์ ์ด๋ค.


2.2. Bilateral Filtering
Uniform ํํฐ๋ ํฝ์ ๊ฐ์ ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ ๋ คํ์ง ์์ง๋ง, ๊ฐ์ฐ์์ ํํฐ๋ ํฝ์ ๊ฐ์ ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ ๋ คํ๋ค๋ ์ ์ด ์ฅ์ ์ด๋ค.
๊ทธ๋ฌ๋ ๊ฐ์ฐ์์ ํํฐ์ ๋ฌธ์ ์ ์ ์ค๋ฒ์ค๋ฌด๋ฉ ํ์์ด ๋ฐ์ํ๋ค๋ ๊ฒ์ด๋ค.
ํฝ์ ๊ฐ์ ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ ๋ คํ์ง๋ง, Intensity์ ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ ๋ คํ์ง๋ ์๊ธฐ ๋๋ฌธ์ด๋ค.
Bilatteral Filtering์ ๊ฐ์ฐ์์ ํํฐ๋ง์ intensity๋ ํจ๊ป ๊ณ ๋ คํ๋ ๋ฐฉ์์ด๋ค.
์ฆ, spatial distance์ intensity distance๋ฅผ ๋ชจ๋ ๊ณ ๋ คํ๋ค.
๋ฐ๋ผ์ ํํฐ๋ง ์ปค๋์ ์์์ ๋ค์๊ณผ ๊ฐ๋ค.

์ฆ, ๊ณต๊ฐ์ ์ผ๋ก ๊ฐ๊น์ธ ์๋ก, ํฝ์ ๋ฐ๊ธฐ๊ฐ ์ ์ฌํ ์๋ก ์ํฅ์ ํฌ๊ฒ ์ฃผ๋ ๋ฐฉํฅ์ผ๋ก ์ค๊ณ๋์๋ค.


+) 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;
}
'๐ฆAI > Computer Vision' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Computer Vision/OpenCV] 16. Edge Detection ๊ณผ Smoothing Tradeoff (0) | 2025.04.10 |
---|---|
[Computer Vision/OpenCV] 15. Segmentation (0) | 2025.04.06 |
[Computer Vision/OpenCV] 13. Image Noise & Degradation (0) | 2025.04.05 |
[Computer Vision/OpenCV] 12. Unsharp Masking (0) | 2025.04.04 |
[Computer Vision/OpenCV] 11. Spatial Filtering (0) | 2025.04.02 |