본문 바로가기
Computer Science/영상처리

(C/C++) Filter (Denoising)

by BaekDaBang 2024. 4. 1.

1. Noise Generation

Y += rand() % Err - (Err >> 1);

 

2. Salt-and-Pepper Noise

if ((rand() % prob) == 0) Y = 255;
else if ((rand() % prob) == 1) Y = 0;
else Y = Y;

 

3. Image Restoration

  • Noise를 줄이기 위한 이미지 전처리(Denoising)
  • 손상된 이미지에서 고품질 이미지를 얻는 작업

 

4. Median Filter

  • 사전정의된 window 내 모든 pixel의 중앙값 제공
  • Salt-and-pepper noise에 효과적

 

5. Mean Filter

  • 사전정의된 window 내 모든 pixel의 평균값 제공
  • 노이즈 감소 및 평활화
// Filter
int f_size = 3;

// mean filter
unsigned char* filter = (unsigned char*)calloc(f_size * f_size, sizeof(unsigned char)); 
for (int i = 0; i < f_size * f_size; i++) {
    filter[i] = 1.0 / (f_size * f_size);
}

 

6. Various Filters

Loss-pass filter (Mean filter, Gaussian filter, Weighted average filter, …)

// Filter
int f_size = 3;

// Gussian Filter : 3x3
double G3_filter[] = {1.0/16, 2.0/16, 1.0/16, 
                      2.0/16, 4.0/16, 2.0/16, 
                      1.0/16, 2.0/16, 1.0/16};
for (int i = 0; i < 9; i++) printf("%lf ", G3_filter[i]);
printf("\n");

// Gussian Filter : 5x5
double G5filter[] = {1/273.0, 4/273.0, 7/273.0, 4/273.0, 1/273.0, 
                     4/273.0, 16/273.0, 26/273.0, 16/273.0, 4/273.0, 
                     7/273.0, 26/273.0, 41/273.0, 26/273.0, 7/273.0, 
                     4/273.0, 16/273.0, 26/273.0, 16/273.0, 4/273.0, 
                     1/273.0, 4/273.0, 7/273.0, 4/273.0, 1/273.0};
for (int i = 0; i < 25; i++) printf("%lf ", G5filter[i]);
printf("\n");

 

7. Combination

한 이미지 내에서 다양한 노이즈에 대한 다중 필터링
이미지에 대한 다중 필터링 (ex: Median Filter, Mean Filter, ...)
A+B 필터, A+B+C 필터, D+C+B+A 필터와 같은 필터 조합

 

8. Boundary Processing

 

9. Filter Design

Filter size와 weight design은 MSE와 PSNR 기반으로 설정한다.

 

10. Experiment

#define _CRT_SECURE_NO_WARNINGS
#include<stdlib.h>
#include<stdio.h>
#include<windows.h>
#include<math.h>

int main()
{
    BITMAPFILEHEADER bmpFile, bmpFile2;
	BITMAPINFOHEADER bmpInfo, bmpInfo2;
	FILE* inputFile1 = NULL;
	inputFile1 = fopen("AICenterY_Noise.bmp", "rb");

    fread(&bmpFile, sizeof(BITMAPFILEHEADER), 1, inputFile1);
	fread(&bmpInfo, sizeof(BITMAPINFOHEADER), 1, inputFile1);

    int width = bmpInfo.biWidth;
	int height = bmpInfo.biHeight;
	int size = bmpInfo.biSizeImage;
	int bitCnt = bmpInfo.biBitCount;
	int stride = (((bitCnt / 8) * width) + 3) / 4 * 4,max;
    printf("width, height, size, bitCnt, stride : ");
	printf("%d, %d, %d, %d, %d\n", width, height, size, bitCnt, stride);

    unsigned char* inputImg1 = NULL, * outputImg1 = NULL;
    inputImg1 = (unsigned char*)calloc(size, sizeof(unsigned char));
	outputImg1 = (unsigned char*)calloc(size, sizeof(unsigned char));
    fread(inputImg1, sizeof(unsigned char), size, inputFile1);

    unsigned char* Y1 = (unsigned char*)calloc(width * height, sizeof(unsigned char));
    
    // Original Copy
    for (int j = 0; j < height; j++) 
    {
		for (int i = 0; i < width; i++) 
        {
			Y1[j * width + i] = inputImg1[j * stride + 3 * i];
		}
	}

    // Padding
    // (1) 변수 선언
    int padding = 1;
    int p_width = width + padding * 2;
	int p_height = height + padding * 2;
	int p_size = p_width * p_height;

    unsigned char* p_Y1 = (unsigned char*)calloc(p_width * p_height, sizeof(unsigned char)); 

    // (2) 원본 이미지 값 입력
    for (int j = 0; j < height; j++) {
		for (int i = 0; i < width; i++) {
			p_Y1[(j + padding) * p_width + (i + padding)] = Y1[j * width + i];
		}
	}

    // (3) Padding 값 입력
    // 꼭짓점
    for (int j = 0; j < padding; j++) {
		for (int i = 0; i < padding; i++) {
            p_Y1[(height + padding + j) * p_width + i] = Y1[(height - 1) * width]; // 좌측 상단
            p_Y1[(height + padding + j) * p_width + (width + padding + i)] = Y1[height * width - 1];   // 우측 상단
			p_Y1[j * p_width + i] = Y1[0]; // 좌측 하단
            p_Y1[j * p_width + (width + padding + i)] = Y1[width - 1];   // 우측 하단
		}
	}
    // 모서리
	for (int p = 0; p < padding; p++) {
		for (int i = 0; i < width; i++) {
            p_Y1[p * p_width + (i + padding)] = Y1[i];  // 상
            p_Y1[(p + width + padding) * p_width + (i + padding)] = Y1[(height - 1) * width + i];   // 하
		}
	}
	for (int p = 0; p < padding; p++) {
		for (int j = 0; j < height; j++) {
			p_Y1[(j + padding) * p_width + p] = Y1[j * width];  // 좌
            p_Y1[(j + padding) * p_width + (width + padding) + p] = Y1[(j + 1) * width - 1]; // 우
		}
	}

  	// Filter
	int f_size = 3;

	// (1) mean filter
	unsigned char* filter = (unsigned char*)calloc(f_size * f_size, sizeof(unsigned char)); 
	for (int i = 0; i < f_size * f_size; i++) {
		filter[i] = 1.0 / (f_size * f_size);
	}

	// (2) Gussian Filter : 3x3
	double G3_filter[] = {1.0/16, 2.0/16, 1.0/16, 
                          2.0/16, 4.0/16, 2.0/16, 
                          1.0/16, 2.0/16, 1.0/16};
	for (int i = 0; i < 9; i++) printf("%lf ", G3_filter[i]);
	printf("\n");

    // (3) Gussian Filter : 5x5
	double G5filter[] = {1/273.0, 4/273.0, 7/273.0, 4/273.0, 1/273.0, 
                         4/273.0, 16/273.0, 26/273.0, 16/273.0, 4/273.0, 
                         7/273.0, 26/273.0, 41/273.0, 26/273.0, 7/273.0, 
                         4/273.0, 16/273.0, 26/273.0, 16/273.0, 4/273.0, 
                         1/273.0, 4/273.0, 7/273.0, 4/273.0, 1/273.0};
	for (int i = 0; i < 25; i++) printf("%lf ", G5filter[i]);
    printf("\n");

    // (4) Filtering
	double* sumf;
	unsigned char* Y2 = (unsigned char*)calloc(width * height, sizeof(unsigned char));
    
	for (int j = 0; j < height; j++) {
		for (int i = 0; i < width; i++) {
			sumf = 0;
			for (int k = 0; k < f_size; k++) {
				for (int l = 0; l < f_size; l++) {
					sumf += G3_filter[k * f_size + l] * p_Y1[(j + k) * p_width + (i + l)];
				}
			}
			Y2[j * width + i] = sumf;
		}
		
	}

    // Evaluation
    double mse = 0, psnr;

    for (int j = 0; j < height; j++) {
        for (int i = 0; i < width; i++) {
            mse += (double)((Y2[j * width + i] - Y1[j * width + i]) * (Y2[j * width + i] - Y1[j * width + i]));
        }
    }
    mse /= (width * height);
    psnr = mse != 0.0 ? 10.0 * log10(255 * 255 / mse) : 99.99;
    printf("MSE = %.2lf\nPSNR = %.2lf dB\n", mse, psnr);

    // Output
	for (int j = 0; j < height; j++) {
		for (int i = 0; i < width; i++) {
			outputImg1[j * stride + 3 * i + 0] = (unsigned char)(Y2[j * width + i]>255 ? 255 : (Y2[j * width + i]< 0 ? 0 : Y2[j * width + i]));
			outputImg1[j * stride + 3 * i + 1] = (unsigned char)(Y2[j * width + i] > 255 ? 255 : (Y2[j * width + i] < 0 ? 0 : Y2[j * width + i]));
			outputImg1[j * stride + 3 * i + 2] = (unsigned char)(Y2[j * width + i] > 255 ? 255 : (Y2[j * width + i] < 0 ? 0 : Y2[j * width + i]));
		}
	}

    FILE* outputFile1 = fopen("Output.bmp", "wb");
	fwrite(&bmpFile, sizeof(BITMAPFILEHEADER),1,outputFile1);
	fwrite(&bmpInfo, sizeof(BITMAPINFOHEADER), 1, outputFile1);
	fwrite(outputImg1, sizeof(unsigned char), size, outputFile1);
 
    // Free
    free(inputImg1);
    free(outputImg1);
    free(Y1);
    free(Y2);
    free(p_Y1);
    fclose(inputFile1);
    fclose(outputFile1);
}

 

'Computer Science > 영상처리' 카테고리의 다른 글

(C/C++) Histogram  (0) 2024.04.02
(C/C++) Quality Evaluation(PSNR)  (0) 2024.03.27
(C/C++) Pixel Operation  (0) 2024.03.27
(C/C++) Color Model  (0) 2024.03.27
(C/C++) Image Format  (0) 2024.03.27