문제 >
이미지 필터링은 이미지에 존재하는 노이즈를 제거하거나 혹은 이미지로부터 유용한 정보를 얻 기 위해 수학적인 연산을 풍하여 새로운 이미지를 만드는 작업이다. 필터링 작업을 위해서는 먼 저 필터(filter) 혹은 커널(kernel)이라고 부르는 정방행렬(크기가 n x n인 행렬)을 정의한다. 이 때 n은 주로 홀수이며 3 혹은 5를 많이 사용한다. 이 행렬의 각 원소의 값은 필터링의 목적 에 따라 여러가지 값을 가지게 된다. 예를 들어. 전체 이미지를 흐리게 만드는 블러링(blurring) 에 주로 많이 사용되는 평균 필터(averaging filter)로 많이 사용되는 크기가 3x 3인 정방형렬은 다음과 같다.
그 다음으로는 다음 그림과 같이 이 필터의 중심을 이미지의 어떤 픽셀과 일치시켜 필터와 겹쳐진 이미지 영역내의 각 픽셀값과 필터의 각 원소의 값을 곱하고 모두 더한 값을 필터가 적용된 새로운 이미지의 픽셀 값으로 만든다.
이렇게 한 픽셀에 필터를 적용하여 새로운 값을 계산하는 연산을 이미지의 모든 픽셀에 적용시켜 새로운 이미지를 만든다. 이때 다음 그림과 같이 필터를 적용시킬 픽셀이 이미지의 가장자리에 있는 경우에는 필터와 연산해야 할 픽셀이 존재하지 않는 경우가 있다. 이 경우에는 그 픽셀 값을 가장 가까운 이미지의 픽셀 값으로 연산한다. 예를 들어, 다음 그림과 같이 필터를 적용해 야 할 픽셀이 이미지의 가장 왼쪽 위 픽셀인 경우에는 일부 필터 영역이 이미지를 벗어나게 된다. 이 경우에는 픽셀 p1, p2, p4를 이미지에서 가장 가까운 픽셀 p의 값으로 계산하고 또한 픽셀 p3, p6는 각각 가장 가까운 픽셀 p5, p7 의 값으로 계산한다.
계산된 픽셀 값이 실수 인 경우에는 소수점 이하는 버린 정수로 만든다.
입력 >
입력은 t개의 테스트 케이스로 주어진다. 입력의 첫 번째 줄에 테스트 케이스의 개수를 나타내는 정수가 주어진다. 각 테스트 케이스에 해당하는 입력의 첫 줄에 해당하는 흑백 영상의 크기를 나타내는 두 정수 hw(3 <= h,w <= 30)가 입력된다. 첫 번째 정수 h는 이 영상의 세로 크기(세로 픽셀 수)이며, 두 번째 정수 w는 이 영상의 가로 크기(가로 픽셀 수)이다. 두 정수 사이에는 한 개의 공백을 둔다. 각 테스트 케이스의 두 번째 줄부터 h개의 줄에는 영상의 가장 위 행부터 가장 아래 행까지 순차적으로 한 줄에 하나의 행에 저장된 픽셀 값을 나타내는 정수가 입력된다. 각 줄에는 영상의 하나의 행에 저장된 픽셀 값을 가장 원쪽 픽셀부터 가장 오른쪽 꼭셀까지 순차적으로 입력된다. 각 픽셀값의 범위는 0~255 이다. 픽셀 값을 나타내는 정수들 사이에는 한 개의 공백이 있으며, 잘못된 데이터가 입력되는 경우는 없다.
출력 >
출력은 입력되는 테스트 케이스의 순서대로 다음 줄에 이어서 각 테스트 케이스의 결과를 출력한다. 각 테스트 케이스의 출력되는 첫 줄부터 입력되는 이미지의 형식과 같은 형식이 되도록 평균 필터가 적용된 이미지를 출력한다. 출력되는 이미지의 모든 픽셀값은 0~255 범위의 정수여야 한다.
입출력 예시
입력 | 출력 |
2 3 3 1 2 3 4 5 6 7 8 9 5 6 90 125 222 136 127 100 27 46 38 190 212 245 0 100 55 48 255 100 5 37 66 255 255 255 44 59 99 255 255 255 |
3 3 2 3 3 4 5 5 6 7 7 5 6 78 109 137 156 152 150 56 78 106 142 157 164 27 41 92 152 201 213 32 51 108 171 214 220 37 56 131 199 255 255 |
풀이 >
모서리 값을 처리하기 까다로우니까 배열에 패딩을 씌워서 배열을 원래 크기보다 +2 시켜서 값을 처리하기로 했다.
1 | 2 | 3 |
4 | 5 | 6 |
7 | 8 | 9 |
↓
1 | 1 | 2 | 3 | 3 |
1 | 1 | 2 | 3 | 3 |
4 | 4 | 5 | 6 | 6 |
7 | 7 | 8 | 9 | 9 |
7 | 7 | 8 | 9 | 9 |
vector<vector<int> > img; //기존 입력받을 img 배열
vector<vector<int> > padding; //패딩을 씌울 배열
vector<vector<int> > filtered; //이미지 필터링 처리된 배열
int column, row;
//필터링 된 배열을 출력할 함수
void printImg(){};
//배열에 패딩을 씌울 함수
void mkPadding(){};
//필터링 처리 할 함수
void filter(){};
int main(){
int t;
cin>>t;
while(t--){
//사용할 벡터 초기화
img.clear();
padding.clear();
filtered.clear();
cin>>column >>row;
//img 배열에 저장
for(int i=0;i<column;i++){
vector<int> v;
for(int j=0;j<row;j++){
int n;
cin>>n;
v.push_back(n);
}
img.push_back(v);
}
mkPadding();
filter();
printImg();
}
}
기존 배열에 패딩을 씌우는 함수
void mkPadding(){
for(int i=0;i<=column+1;i++){ //기존 column 보다 +2 만큼 크기를 키워줌
vector<int> v;
for(int j=0;j<=row+1;j++){ //기존 row 보다 +2 만큼 크기를 키워줌
if (j==0){ //패딩의 왼쪽 세로줄 처리
//i>=column ? column-1 : i-1<0? 0: i-1
//삼항 연산자 처리를 통해 값이 기존 img 배열의 인덱스가 벗어나지 않도록 함
v.insert(v.begin() + 0, img[i>=column ? column-1 : i-1<0? 0: i-1][0]);
}else if (j==row+1){ //패딩의 오른쪽 세로줄 처리
v.push_back(img[i>=column ? column-1 : i-1<0? 0: i-1][row-1]);
}else {
v.push_back(img[i>=column ? column-1 : i-1<0? 0: i-1][j-1]);
}
}padding.push_back(v);
}
}
filter를 적용시킴.
p1 | p2 | p3 |
p4 | p5 | p6 |
p7 | p8 | p9 |
avg = ( p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9 ) / 9
나눈 후 소수점 이하는 버린 정수로 값을 정하므로 9로 나눈 후 나온 정수값만 저장한다.
void filter(){
int cnt=0;
for(int i=1;i<=column;i++){
vector<int> v;
for(int j=1;j<=row;j++){
int avg=0;
int sum = padding[i-1][j-1] + padding[i-1][j] + padding[i-1][j+1] + padding[i][j-1] + padding[i][j] + padding[i][j+1] + padding[i+1][j-1] + padding[i+1][j] + padding[i+1][j+1];
avg = sum/9;
v.push_back(avg);
}
filtered.push_back(v);
}
}
문제 해결 완료 ~
처음에 패딩값을 씌운다는 생각을 못하면 if 문과 삼항연산자 노가다로 풀어야 할 뻔 했다.
패딩을 열심히 입자.
'Algorithm' 카테고리의 다른 글
Josephus Problem (1) | 2022.12.11 |
---|---|
Kolakoski sequence (1) | 2022.12.11 |
Canonical Cycle (0) | 2022.12.05 |
Golomb sequence (0) | 2022.12.03 |