python - cv2.blur 中的深色边框

标签 python numpy opencv pygame pygame-surface

我在 python 上有这段代码,我将其用作游戏中的 Bloom 效果,但我注意到它在粒子周围有这种奇怪的黑色阴影

Effect in White Background Effect in Grey  Background

效果是这样的^

可以看到,粒子上有一些阴影,在白色背景上很明显,而在灰色背景下则很微妙

我想知道是否有办法消除/减少这种奇怪的效果

这是绽放的代码(阴影来自此处):

def Bloom(canvas: pygame.Surface):
    size = canvas.get_size()
    canvas_color = pygame.surfarray.array2d(canvas)
    canvas_rgba = canvas_color.view(dtype=np.uint8).reshape((*canvas_color.shape, 4))

    newCanvas = pygame.Surface(size, pygame.SRCALPHA)


    cv2.blur(canvas_rgba, ksize=(9, 9), dst=canvas_rgba)

    
    pygame.surfarray.blit_array(newCanvas, canvas_color)

    return newCanvas

任何帮助都会很棒:3

编辑:删除了黑色背景的图像(没有理由在那里)

最佳答案

问题不在于“bloom”算法,而在于将表面blit到目标的方式。
不仅 Alpha channel 模糊,颜色 channel 也模糊。因此你必须blit带有特殊标志 BLEND_PREMULTIPLIEDSurface:

bloom_surf = Bloom(source_surf)
screen.blit(bloom_surf, (x, y), pygame.BLEND_PREMULTIPLIED)

也可以通过将颜色 channel 除以 Alpha channel 来在 Bloom 函数中取消此效果:

r' = r / a
g' = g / a
b' = b / a
a' = a

每个颜色 channel 都以 [0, 255] 范围内的字节进行编码。这使得转换变得有点棘手:

def BloomNoPremultipliedAlpha(canvas: pygame.Surface):
    size = canvas.get_size()
    canvas_color = pygame.surfarray.array2d(canvas)
    canvas_rgba = canvas_color.view(dtype=np.uint8).reshape((*canvas_color.shape, 4))
    newCanvas = pygame.Surface(size, pygame.SRCALPHA)
    cv2.blur(canvas_rgba, ksize=(25, 25), dst=canvas_rgba)

    canvas_rgba[:,:,0:3] = canvas_rgba[:,:,0:3] * 255.0 / canvas_rgba[:,:,[3,3,3]]

    pygame.surfarray.blit_array(newCanvas, canvas_color)
    return newCanvas

请参阅以下演示差异的最小示例:


左:布卢姆;中心:Bloom + BLEND_PREMULTIPLIED;右:BloomNoPremultipliedAlpha

import pygame, cv2 
import numpy as np

def Bloom(canvas: pygame.Surface):
    size = canvas.get_size()
    canvas_color = pygame.surfarray.array2d(canvas)
    canvas_rgba = canvas_color.view(dtype=np.uint8).reshape((*canvas_color.shape, 4))
    newCanvas = pygame.Surface(size, pygame.SRCALPHA)
    cv2.blur(canvas_rgba, ksize=(25, 25), dst=canvas_rgba)
    pygame.surfarray.blit_array(newCanvas, canvas_color)
    return newCanvas

def BloomNoPremultipliedAlpha(canvas: pygame.Surface):
    size = canvas.get_size()
    canvas_color = pygame.surfarray.array2d(canvas)
    canvas_rgba = canvas_color.view(dtype=np.uint8).reshape((*canvas_color.shape, 4))
    newCanvas = pygame.Surface(size, pygame.SRCALPHA)
    cv2.blur(canvas_rgba, ksize=(25, 25), dst=canvas_rgba)

    canvas_rgba[:,:,0:3] = canvas_rgba[:,:,0:3] * 255.0 / canvas_rgba[:,:,[3,3,3]]

    pygame.surfarray.blit_array(newCanvas, canvas_color)
    return newCanvas

pygame.init()
window = pygame.display.set_mode((800, 300))
clock = pygame.time.Clock()

background = pygame.Surface(window.get_size())
ts, w, h, c1, c2 = 100, *window.get_size(), (160, 160, 160), (96, 96, 96)
tiles = [((x*ts, y*ts, ts, ts), c1 if (x+y) % 2 == 0 else c2) for x in range((w+ts-1)//ts) for y in range((h+ts-1)//ts)]
[pygame.draw.rect(background, color, rect) for rect, color in tiles]

surface = pygame.Surface((250, 250), pygame.SRCALPHA)
pygame.draw.circle(surface, (255, 255, 255), surface.get_rect().center, 100)
surface1 = Bloom(surface)
surface2 = Bloom(surface)
surface3 = BloomNoPremultipliedAlpha(surface)

run = True
while run:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False 

    window.blit(background, (0, 0))
    window.blit(surface1, surface1.get_rect(center = (150, 150)))
    window.blit(surface2, surface2.get_rect(center = (400, 150)), special_flags = pygame.BLEND_PREMULTIPLIED)
    window.blit(surface3, surface1.get_rect(center = (650, 150)))
    pygame.display.flip()
    clock.tick(60)

pygame.quit()
exit()

关于python - cv2.blur 中的深色边框,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69977901/

相关文章:

查找素数的 Python 程序 (3.5)

image-processing - OpenCV:如何知道HaarTraining的进度状态

python - 按值查找元素 Selenium/Python

python - 当我在 Python 中裁剪图像时,它返回 'NoneType'

python - 导入错误: cannot import name 'ellipkm1'

python - 带有数组和标量的 Numpy 数学?

numpy - Keras 数组输入错误

opencv - 图像中的对象检测

python - 使用 Python 在 OpenCV 中存储

python - 尝试并排除(TypeError)