It's not clear what specific image smoothing algorithm you want to use. SciPy provides some relevant functions, so I've constructed an example using ndimage.gaussian_filter().
Clicking a mouse button will apply the filter, or you can scroll the wheel.
import pygame
from scipy.ndimage import gaussian_filter
# https://docs.scipy.org/doc/scipy/reference/generated/scipy.ndimage.gaussian_filter.html
def smooooooth(screen):
"""Apply a gaussian filter to each colour plane"""
# Get reference pixels for each colour plane and then apply filter
r = pygame.surfarray.pixels_red(screen)
gaussian_filter(r, sigma=72, mode="nearest", output=r)
g = pygame.surfarray.pixels_green(screen)
gaussian_filter(g, sigma=72, mode="nearest", output=g)
b = pygame.surfarray.pixels_blue(screen)
gaussian_filter(b, sigma=72, mode="nearest", output=b)
height = 300
width = 300
pygame.init()
screen = pygame.display.set_mode((width, height), pygame.RESIZABLE)
pygame.display.set_caption("Smooth Image")
clock = pygame.time.Clock()
# draw initial pattern
screen.fill((194, 198, 199)) # fill with gray
# fill top left quadrant with white
screen.fill(pygame.Color("white"), pygame.Rect(0, 0, width // 2, height // 2))
# fill bottom left quadrant with black
screen.fill(pygame.Color("black"), pygame.Rect(width // 2, height // 2, width, height))
count = 0
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONUP:
smooooooth(screen)
count += 1
pygame.display.set_caption(f"Smooth Image {count}")
pygame.display.update()
# limit framerate
clock.tick(30)
pygame.quit()
If you play with the sigma argument to the gaussian_filter function, you might be able to get closer to what you're after. E.g. with sigma 72, two passes looks like this:

I've modified the example code to properly support screen resizing, which will redraw the base pattern and using the + and - keys to increment the sigma value so you can do it interactively. Hold Shift to adjust by ten instead of one.
import pygame
from scipy.ndimage import gaussian_filter
# https://docs.scipy.org/doc/scipy/reference/generated/scipy.ndimage.gaussian_filter.html
def smooooooth(screen, sisgma):
"""Apply a gaussian filter to each colour plane"""
# Get reference pixels for each colour plane and then apply filter
r = pygame.surfarray.pixels_red(screen)
gaussian_filter(r, sigma=sigma, mode="nearest", output=r)
g = pygame.surfarray.pixels_green(screen)
gaussian_filter(g, sigma=sigma, mode="nearest", output=g)
b = pygame.surfarray.pixels_blue(screen)
gaussian_filter(b, sigma=sigma, mode="nearest", output=b)
def draw_grey_squares(screen):
"""Draw the base pattern"""
screen.fill((194, 198, 199)) # fill with grey
# fill top left quadrant with white
screen.fill(pygame.Color("white"), (0, 0, width // 2, height // 2))
# fill bottom left quadrant with black
screen.fill(pygame.Color("black"), (width // 2, height // 2, width, height))
height = 300
width = 300
pygame.init()
screen = pygame.display.set_mode((width, height), pygame.RESIZABLE)
draw_grey_squares(screen)
pygame.display.set_caption("Smooth Image")
clock = pygame.time.Clock()
sigma = 72
count = 0
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.VIDEORESIZE:
# redraw on window resize
width, height = event.w, event.h
draw_grey_squares(screen)
count = 0
elif event.type == pygame.KEYUP:
# support + and - to modify sigma
if event.key in (pygame.K_PLUS, pygame.K_KP_PLUS):
if event.mod & pygame.KMOD_SHIFT:
sigma += 10
else:
sigma += 1
elif event.key in (pygame.K_MINUS, pygame.K_KP_MINUS):
if event.mod & pygame.KMOD_SHIFT:
sigma -= 10
else:
sigma -= 1
sigma = max(sigma, 1) # sigma below one doesn't make sense
elif event.type == pygame.MOUSEBUTTONUP:
smooooooth(screen, sigma)
count += 1
pygame.display.set_caption(f"Smooth Image {count} σ {sigma}")
pygame.display.update()
clock.tick(30) # limit framerate
pygame.quit()
Here's an example with sigma 200:
