An earlier thread showed how to use the Windows API function AlphaBlend to blur a picture. Here is another way that also allows you disable bluring of certain colors or pixels.

The code below blurs the picture in the obvious way, by scanning it and replacing each pixel with the average of it and the surrounding pixels.

The method uses a crude Gaussian filter to compute a weighted average of the pixels. The mathematically interesting thing is that instead of doing this in two dimensions with a plane filter, you can do each dimension separately with a line filter, in either order, and the final result will be the same as with the plane filter. Despite the intermediate asymmetrical averaging the end result is symmetrical averaging.

One pass with a plane filter looks at nine pixels per point. Two perpendicular passes looks at only three pixels per point, per pass – or six pixels together. Nine versus six, which is faster even accounting for the extra pass.

Here are the factors I used for the line Gaussian filter:

.25 and .50 and .25

either horizontally or vertically. .50 is for the central pixel, .25 for its two neighbors. I told you it was crude. (A more refined filter would use half a dozen values, again with a peak in the middle, approximating a bell curve.)

Don’t believe doing it twice, once vertically and once horizontally, could work? Here’s a simple example. Suppose your picture is 4x4 pixels, with black (zero) around the edges:
The total sum, representing the total luminance, is 132.

Now hold the filter vertically

1/4

1/2

1/4

and run it over the picture matrix left to right, each row, summing the individual products, replacing the center pixel. You get:
The total sum is still 132.

Now hold the filter horizontally

1/4 1/2 1/4

and run it over
The total sum is still 132.

And if you were a machine it would look blurred.

To make the computation faster, instead of the .25 and .50 Gaussian factors use 1 and 2, then divide by 4 at the end.

Averaging colors must be done color component-wise, and since we need to average three colors for every pixel in the picture, twice, I wrote an assembly routine for it.

The code below blurs the picture in the obvious way, by scanning it and replacing each pixel with the average of it and the surrounding pixels.

The method uses a crude Gaussian filter to compute a weighted average of the pixels. The mathematically interesting thing is that instead of doing this in two dimensions with a plane filter, you can do each dimension separately with a line filter, in either order, and the final result will be the same as with the plane filter. Despite the intermediate asymmetrical averaging the end result is symmetrical averaging.

One pass with a plane filter looks at nine pixels per point. Two perpendicular passes looks at only three pixels per point, per pass – or six pixels together. Nine versus six, which is faster even accounting for the extra pass.

Here are the factors I used for the line Gaussian filter:

.25 and .50 and .25

either horizontally or vertically. .50 is for the central pixel, .25 for its two neighbors. I told you it was crude. (A more refined filter would use half a dozen values, again with a peak in the middle, approximating a bell curve.)

Don’t believe doing it twice, once vertically and once horizontally, could work? Here’s a simple example. Suppose your picture is 4x4 pixels, with black (zero) around the edges:

Code:

. . . . . 60 20 . . 40 12 . . . . .

Now hold the filter vertically

1/4

1/2

1/4

and run it over the picture matrix left to right, each row, summing the individual products, replacing the center pixel. You get:

Code:

. 15 5 . . 40 13 . . 35 11 . . 10 3 .

Now hold the filter horizontally

1/4 1/2 1/4

and run it over

__that__matrix top to bottom, each column, summing the individual products, replacing the center pixel. You get:Code:

3.75 8.75 6.25 1.25 10.00 23.25 16.50 3.25 8.75 20.25 14.25 2.75 2.50 5.75 4.00 .75

And if you were a machine it would look blurred.

To make the computation faster, instead of the .25 and .50 Gaussian factors use 1 and 2, then divide by 4 at the end.

Averaging colors must be done color component-wise, and since we need to average three colors for every pixel in the picture, twice, I wrote an assembly routine for it.

Code:

%bluemask = &h00FF0000 'nominally blue, might be red %greenmask = &h0000FF00 %redmask = &h000000FF 'nominally red, might be blue 'We don't care which is which because we will replace each 'component in its place. 'Like (c1 + c2*2 +c3)/4 only must do each color component separately. 'Note: This alters c1, used to give out result. Macro Function GaussianAverage 'eax 'blue accumulator 'ebx 'green 'ecx 'red '-------------- ! mov eax,c1 'get blues and add-up in eax ! and eax,%bluemask ! shr eax,16 ! mov edx,c2 ! and edx,%bluemask ! shr edx,15 'not 16, so double ! add eax,edx ! mov edx,c3 ! and edx,%bluemask ! shr edx,16 ! add eax,edx 'divide by 4 ! bt eax,1 'check bit #1, set carry flag if 1 ! jc RoundUpA ! shr eax,2 ! jmp short SkipA RoundUpA: ! shr eax,2 ! inc eax SkipA: 'restore red position ! shl eax,16 '-------------- ! mov ebx,c1 'greens ! and ebx,%greenmask ! shr ebx,8 ! mov edx,c2 ! and edx,%greenmask ! shr edx,7 'not 8, so double ! add ebx,edx ! mov edx,c3 ! and edx,%greenmask ! shr edx,8 ! add ebx,edx ! bt ebx,1 ! jc RoundUpB ! shr ebx,2 ! jmp short SkipB RoundUpB: ! shr ebx,2 ! inc ebx SkipB: ! shl ebx,8 '-------------- ! mov ecx,c1 'reds ! and ecx,%redmask ! mov edx,c2 ! and edx,%redmask ! shl edx,1 'double ! add ecx,edx ! mov edx,c3 ! and edx,%redmask ! add ecx,edx ! bt ecx,1 ! jc RoundUpC ! shr ecx,2 ! jmp short SkipC RoundUpC: ! shr ecx,2 ! inc ecx SkipC: '-------------- ! mov edx,eax 'assemble color, edx = eax + ebx + ecx ! add edx,ebx ! add edx,ecx ! mov c1,edx 'give out result End Macro = c1 '------------------------------------------------------------- %dswin = 480 Function PBMain Local winC As Dword 'display window handle Local bmpC As Dword 'bitmap handle Local A$ 'string to hold picture Local B$ 'string to hold blurred picture Local Aptr As Dword Ptr 'pointer into A$ Local Bptr As Dword Ptr 'pointer into B$ Local i As Long 'index counter Local c1, c2, c3 As Long 'linear frame about pixel of interest Console Set Loc 50+%dswin,50 'move console window out of the way Graphic Window "", 50,50, %dswin,%dswin To winC 'window used for display Console Set Focus 'give focus back to console Graphic Attach winC,0, ReDraw 'draw some random lines Randomize Timer For i = 1 To 10 Graphic Line (%dswin*Rnd,%dswin*Rnd)-(%dswin*Rnd,%dswin*Rnd), %Red Graphic Line (%dswin*Rnd,%dswin*Rnd)-(%dswin*Rnd,%dswin*Rnd), %Blue Graphic Line (%dswin*Rnd,%dswin*Rnd)-(%dswin*Rnd,%dswin*Rnd), %Green Graphic Line (%dswin*Rnd,%dswin*Rnd)-(%dswin*Rnd,%dswin*Rnd), %Black Next Sleep 1 'this sleep is necessary for some reason, Graphic ReDraw 'otherwise redraw only works at random on my 'system and even then it occassionally misses. Print "Press any key to blur window at left." WaitKey$ Graphic Bitmap New %dswin,%dswin To bmpC 'create bitmap Graphic Attach bmpC, 0 :Graphic Copy winC,0 'copy display window to bitmap Graphic Get Bits To A$ 'get bitmap into a string B$ = A$ 'make a copy to hold blur 'Assume picture is a uniform color for several pixels in from the edges. 'In that case wrap-around averaging at left and right edges won't matter, 'and we can ignore the top and bottom edges. 'First pass - from left to right. Skip top row Aptr = StrPtr(A$) + 8 + %dswin*4 'pointer into original bitmap Bptr = StrPtr(B$) + 8 + %dswin*4 'pointer into blurred bitmap For i = 1 To %dswin*%dswin - %dswin*2 'and skip bottom row c1 = @Aptr[-%dswin] 'above pixel c2 = @Aptr 'at pixel c3 = @Aptr[ %dswin] 'below pixel GoSub GetGaussianAverage Incr Aptr Incr Bptr Next A$ = B$ 'update source string to horizontally blurred picture 'Second pass - from top to bottom. Skip beginning left edge. Aptr = StrPtr(A$) + 8 + 4 Bptr = StrPtr(B$) + 8 + 4 For i = 1 To %dswin*%dswin - 2 'and skip ending right edge c1 = @Aptr[-1] 'to left of pixel c2 = @Aptr 'at pixel c3 = @Aptr[ 1] 'to right of pixel GoSub GetGaussianAverage Incr Aptr Incr Bptr Next Graphic Attach winC,0 Graphic Set Bits B$ 'update display window Graphic ReDraw Print "Press any key to exit." WaitKey$ Exit Function '------------- GetGaussianAverage: 'macro in gosub so line labels not duplicated @Bptr = GaussianAverage Return End Function

## Comment