Image Restoration and Reconstruction

2023. 11. 10. 21:46컴퓨터비전

728x90

Noise

: 영상의 픽셀값에 추가되는 원치 않는 형태의 신호를 의미

 

1. Salt-and pepper noise

: 픽셀값들의 일부가 무작위 값으로 대체되는 경우이다.

salt noise는 픽셀이 하얀색인 경우이고,

pepper noise는 픽셀이 검정색인 경우

2. Gaussian noise

: 원래의 픽셀값이 아닌 오차가 생긴 값이 들어가는 경우이다.

평균이 0이고, 표준 편차가 1인 가우시안 분포를 정상 분포라고도 한다.

 

 

노이즈 제거하기

1. Median Filter

  • non linear filter
  • 픽셀값을 kenel 값들을 정렬한 상태에서 중간값을 선택하는 방식
    -> 중간에서 멀리 떨어진 값들은 선택되지 않아
    salt-and-pepper noise를 제거하는데 효과적으로 사용된다.

2. Mean Filter

  • 픽셀값을 주위 픽셀들의 평균 값으로 대체하는 방식
  • kernel(mask)이 3*3이라면 

해당 픽셀의 주위 값들과 weight를 고려하여 새로운 값으로 변경한다.이것을 convolution이라 하며, Mean filter의 경우 weight가 모두 동일하다.

#include <opencv2/opencv.hpp>
#include <vector>
#include <algorithm>
#include <numeric>

using namespace cv;
using namespace std;

Mat MedianFilter(const Mat& img, int ksize) {
	int center = ksize / 2; //중심 픽셀로부터 커버할 픽셀까지의 거리
	Mat filter = img.clone();

	for (int y = center;y < filter.rows - center;y++) {
		for (int x = center;x < filter.cols - center;x++) {
			vector<uchar> near;
			for (int i = -center;i <= center;i++) {
				for (int j = -center;j <= center;j++) {
					near.push_back(img.at<uchar>(y + i, x + j)); //3*3픽셀들 벡터에 담기
				}
			}
			sort(near.begin(), near.end()); //3*3 픽셀들 정렬
			filter.at<uchar>(y, x) = near[near.size() / 2]; //중간값으로 픽셀값 설정
		}
	}
	return filter;
}

Mat MeanFilter(const Mat& img, int ksize) {
	int center = ksize / 2; //중심 픽셀로부터 커버할 픽셀까지의 거리
	Mat filter = img.clone();
	
	for (int y = center;y < filter.rows - center;y++) {
		for (int x = center;x < filter.cols - center;x++) {
			vector<uchar> near;
			for (int i = -center;i <= center;i++) {
				for (int j = -center;j <= center;j++) {
					near.push_back(img.at<uchar>(y + i, x + j)); //3*3픽셀들 벡터에 담기
				}
			}
			float sum =accumulate(near.begin(), near.end(),0.0); //픽셀값들 누적합 구하기
			filter.at<uchar>(y, x) = sum/near.size(); //평균값으로 픽셀값 설정
		}
	}
	return filter;
}




int main() {
	Mat image = imread("Lena512.jpg",IMREAD_GRAYSCALE);
	//imshow("input", image); //원본 이미지


	Mat noise1(image.size(), CV_8U);
	randn(noise1, 0, 15); //평균이 0,표준편차가 15인 가우시안 분포를 따르는 난수 생성(적은 가우시안 노이즈 생성)
	Mat noise2(image.size(), CV_8U);
	randn(noise2, 0, 30); //평균이 0,표준편차가 15인 가우시안 분포를 따르는 난수 생성(큰 가우시안 노이즈 생성)

	Mat result1, result2;
	add(image, noise1, result1, Mat(), CV_8U); //원본에 가우시안 노이즈 합치기,0~255범위 벗어나지 않도록 합치기
	add(image, noise2, result2, Mat(), CV_8U);

	Mat result3 = image.clone();
	Mat result4 = image.clone();

	int num1 = (int)(image.total() * 0.05); //0.05 확률로 salt&pepper noise 만들기
	for (int i = 0;i < num1;i++) {
		int x = rand() % result3.cols;
		int y = rand() % result3.rows;
		result3.at<uchar>(y, x) = (i % 2) * 255;
	}

	int num2 = (int)(image.total() * 0.1); //0.1 확률로 salt&pepper noise 만들기
	for (int i = 0;i < num2;i++) {
		int x = rand() % result4.cols;
		int y = rand() % result4.rows;
		result4.at<uchar>(y, x) = (i % 2) * 255;
	}

	imshow("gaussian_noise=10", result1); //표준편차가 10인 가우시안 노이즈 
	imshow("gaussian_noise=30", result2); //표준편차가 30인 가우시안 노이즈
	imshow("salt&pepper: 0.05", result3); //0.05확률의 salt&pepper 노이즈
	imshow("salt&pepper: 0.1", result4); //0.1확률의 salt&pepper 노이즈

	//각각에 median_filter 적용
	imshow("median-10", MedianFilter(result1, 3)); 
	imshow("median-30", MedianFilter(result2, 3));
	imshow("median-0.05", MedianFilter(result3, 3));
	imshow("median-0.1", MedianFilter(result4, 3));

	//각각에 mean_filter 적용
	imshow("mean-10", MeanFilter(result1, 3));
	imshow("mean-30", MeanFilter(result2, 3));
	imshow("mean-0.05", MeanFilter(result3, 3));
	imshow("mean-0.1", MeanFilter(result4, 3));

	waitKey(0);
	return 0;
}

 

Adaptive Filters

: 이미지의 특성에 맞게 적용하는 필터

 

 

다음과 같이 변수들을 정의할 때,

  • 2번 변수가 0이라면 : 노이즈가 없는 상태이므로 그냥 g(x,y) 반환하면 된다.
  • 4번 변수가 2번 변수에 비해 높은경우라면 : edge가 존재할 것.
    ->원래 영상의 변화가 커서 필터를 세게 적용하면 안된다.
    -> g(x,y)에 가까운 값 반환
  • 4번 변수와 2번 변수가 같은 경우라면
    : S(x,y) 윈도우 내에 전체 영상에 부가된 noise와 동일한 분포로 포함되어 있다.
    -> 필터를 강하게 적용해도 된다.
    -> 평균을 구해 노이즈 감쇠

 

Adaptive Median Filter

 

Level A:

A1=Z(median) - Z(min)

A2=Z(median) - Z(max)

if A1>0,A2<0이라면 Level B로 이동 //이걸 만족하면 median값이 노이즈가 아닌것으로 판단

else 윈도우 사이즈 키우기 //아니라면 일단 좀더 넓은 범위에서 탐색해보기

if 윈도우 크기 <= 윈도우 크기최대치라면  Level A 반복

else Z(xy) 반환 //픽셀값을 median값으로 대체

 

Level B:

B1=Z(xy) - Z(min)

B2=Z(xy) - Z(max)

if B1>0, B2<0이라면 Z(xy)반환 //노이즈가 없는 상태이므로 자기자신 반환

else Z(median) 반환 //노이즈가 있는 상태이므로 중간값 반환

왼쪽부터 a:salt-and-pepper noise, b: 7*7 median filter로 복원한 것, c: S(max)=7인 adaptive median filter로 복원한 것.

확실히 3번째가 엣지 디테일을 많이 살려 복원한다.

 

 

Inverse Filter

g(x,y)는 degraded image

f(x,y)는 original image

n(x,y)는 noise

h(x,y)는 filter일 때

 

Spatial domain: g(x,y)=f(x,y)*h(x,y)+n(x,y)

-> Frequency domain : G(u,v)=F(u,v)H(u,v) +N(u,v)

 

F^(u,v)(복원된 영상) = G(u,v)/H(u,v) = F(u,v)+N(u,v)/H(u,v)

: H값이 작을 때는 노이즈값이 커서 괜찮은데

H값이 커질 때는 노이즈값이 작아져서 값이 이상해짐

-> lowpass filter로 해결가능

왼쪽 위에서부터 시계방향으로 a:full filter, b: 반지름 40, c: 반지름 70, d: 반지름 85

통과 filter의 반지름이 커질수록 이상한값이 나온다.

 

 

728x90

'컴퓨터비전' 카테고리의 다른 글

Feature Detection and Matching  (0) 2023.11.14
Edge Detection  (0) 2023.11.12
(opencv) visual studio에 적용하기  (0) 2023.11.01
Filtering in the Frequency Domain  (1) 2023.10.18
Filtering  (1) 2023.10.18