Nice programing

내장 된 가우스 함수를 사용하지 않고 이미지를 가우시안 블러 처리하려면 어떻게합니까?

nicepro 2021. 1. 9. 11:39
반응형

내장 된 가우스 함수를 사용하지 않고 이미지를 가우시안 블러 처리하려면 어떻게합니까?


기본 가우시안 흐림 공식을 사용하여 이미지를 흐리게 만들고 싶습니다. Wikipedia 기사를 읽었 지만이를 구현하는 방법을 모르겠습니다.

공식을 사용하여 가중치를 결정하는 방법은 무엇입니까?

MATLAB과 같은 내장 함수를 사용하고 싶지 않습니다.


순진한 가우시안 블러를 작성하는 것은 실제로 매우 쉽습니다. 다른 컨볼 루션 필터와 똑같은 방식으로 수행됩니다. 상자와 가우스 필터의 유일한 차이점은 사용하는 행렬입니다.

다음과 같이 정의 된 이미지가 있다고 가정 해보십시오.

 0  1  2  3  4  5  6  7  8  9
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29
30 31 32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47 48 49
50 51 52 53 54 55 56 57 58 59
60 61 62 63 64 65 66 67 68 69
70 71 72 73 74 75 76 77 78 79
80 81 82 83 84 85 86 87 88 89
90 91 92 93 94 95 96 97 98 99

3x3 상자 필터 행렬은 다음과 같이 정의됩니다.

0.111 0.111 0.111
0.111 0.111 0.111
0.111 0.111 0.111

가우시안 블러를 적용하려면 다음을 수행합니다.

픽셀 11의 경우 픽셀 0, 1, 2, 10, 11, 12, 20, 21, 22를로드해야합니다.

그런 다음 픽셀 0에 3x3 블러 필터의 왼쪽 상단 부분을 곱합니다. 픽셀 1은 상단 가운데, 픽셀 2, 픽셀 3은 오른쪽 상단, 픽셀 10은 왼쪽 가운데 등입니다.

그런 다음 모두 추가하고 결과를 픽셀 11에 씁니다. 보시다시피 Pixel 11은 이제 자체 및 주변 픽셀의 평균입니다.

가장자리 케이스는 조금 더 복잡해집니다. 텍스처 가장자리 값으로 어떤 값을 사용합니까? 한 가지 방법은 다른 쪽을 감싸는 것입니다. 이것은 나중에 바둑판 식으로 배열되는 이미지에 적합합니다. 또 다른 방법은 픽셀을 주변 장소로 밀어 넣는 것입니다.

따라서 왼쪽 상단의 경우 다음과 같이 샘플을 배치 할 수 있습니다.

 0  0  1
 0  0  1
10 10 11

이것이 어떻게 큰 필터 커널 (예 : 5x5 또는 9x9 등)로 쉽게 확장되는지 알 수 있기를 바랍니다.

가우스 필터와 박스 필터의 차이는 행렬에 들어가는 숫자입니다. 가우스 필터는 행과 열에 대한 가우스 분포를 사용합니다.

예 : 임의로 정의 된 필터의 경우 (예 : 가우스는 아니지만 멀지 않은 경우)

0.1 0.8 0.1

첫 번째 열은 동일하지만 위 행의 첫 번째 항목에 곱해집니다.

0.01 0.8 0.1
0.08 
0.01 

두 번째 열은 동일하지만 값은 위의 행에서 0.8로 곱해집니다.

0.01 0.08 0.01
0.08 0.64 0.08
0.01 0.08 0.01

The result of adding all of the above together should equal 1. The difference between the above filter and the original box filter would be that the end pixel written would have a much heavier weighting towards the central pixel (ie the one that is in that position already). The blur occurs because the surrounding pixels do blur into that pixel, though not as much. Using this sort of filter you get a blur but one that doesn't destroy as much of the high frequency (ie rapid changing of colour from pixel to pixel) information.

These sort of filters can do lots of interesting things. You can do an edge detect using this sort of filter by subtracting the surrounding pixels from the current pixel. This will leave only the really big changes in colour (high frequencies) behind.

Edit: A 5x5 filter kernel is define exactly as above.

e.g if your row is 0.1 0.2 0.4 0.2 0.1 then if you multiply each value in their by the first item to form a column and then multiply each by the second item to form the second column and so on you'll end up with a filter of

0.01 0.02 0.04 0.02 0.01
0.02 0.04 0.08 0.04 0.02
0.04 0.08 0.16 0.08 0.04
0.02 0.04 0.08 0.04 0.02
0.01 0.02 0.04 0.02 0.01

taking some arbitrary positions you can see that position 0, 0 is simple 0.1 * 0.1. Position 0, 2 is 0.1 * 0.4, position 2, 2 is 0.4 * 0.4 and position 1, 2 is 0.2 * 0.4.

I hope that gives you a good enough explanation.


Here's the pseudo-code for the code I used in C# to calculate the kernel. I do not dare say that I treat the end-conditions correctly, though:

double[] kernel = new double[radius * 2 + 1];
double twoRadiusSquaredRecip = 1.0 / (2.0 * radius * radius);
double sqrtTwoPiTimesRadiusRecip = 1.0 / (sqrt(2.0 * Math.PI) * radius);
double radiusModifier = 1.0;

int r = -radius;
for (int i = 0; i < kernel.Length; i++)
{
    double x = r * radiusModifier;
    x *= x;
    kernel[i] =
    sqrtTwoPiTimesRadiusRecip * Exp(-x * sqrtTwoPiTimesRadiusRecip);
    r++;
}

double div = Sum(kernel);
for (int i = 0; i < kernel.Length; i++)
{
    kernel[i] /= div;
}

Hope this can help.


To use the filter kernel discussed in the Wikipedia article you need to implement (discrete) convolution. The idea is that you have a small matrix of values (the kernel), you move this kernel from pixel to pixel in the image (i.e. so that the center of the matrix is on the pixel), multiply the matrix elements with the overlapped image elements, sum all the values in the result and replace the old pixel value with this sum.

Gaussian blur can be separated into two 1D convolutions (one vertical and one horizontal) instead of a 2D convolution, which also speeds things up a bit.


I am not clear whether you want to restrict this to certain technologies, but if not SVG (ScalableVectorGraphics) has an implementation of Gaussian Blur. I believe it applies to all primitives including pixels. SVG has the advantage of being an Open standard and widely implemented.


Well, Gaussian Kernel is a separable kernel.
Hence all you need is a function which supports Separable 2D Convolution like - ImageConvolutionSeparableKernel().

Once you have it, all needed is a wrapper to generate 1D Gaussian Kernel and send it to the function as done in ImageConvolutionGaussianKernel().

The code is a straight forward C implementation of 2D Image Convolution accelerated by SIMD (SSE) and Multi Threading (OpenMP).

The whole project is given by - Image Convolution - GitHub.

ReferenceURL : https://stackoverflow.com/questions/1696113/how-do-i-gaussian-blur-an-image-without-using-any-in-built-gaussian-functions

반응형