Algorithm

Image Filtering

H0zzae 2022. 12. 3. 21:52

문제 >

 

이미지 필터링은 이미지에 존재하는 노이즈를 제거하거나 혹은 이미지로부터 유용한 정보를 얻 기 위해 수학적인 연산을 풍하여 새로운 이미지를 만드는 작업이다. 필터링 작업을 위해서는 먼 저 필터(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