Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/image-processing/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 有没有办法合并索引pygame.Surfaces的选项板?_Python_Image Processing_Pygame_Color Mapping_Indexed Image - Fatal编程技术网

Python 有没有办法合并索引pygame.Surfaces的选项板?

Python 有没有办法合并索引pygame.Surfaces的选项板?,python,image-processing,pygame,color-mapping,indexed-image,Python,Image Processing,Pygame,Color Mapping,Indexed Image,我有一个带有索引调色板的表面BaseSurf,我想blit另一个索引颜色表面(我们称之为NewSurf)。BaseSurf的调色板与NewSurf的不同,pygame不会自动将缺少的颜色添加到BaseSurf的调色板中。 因此,我需要某种方法将NewSurf的颜色添加到BaseSurf的调色板中,而不会损坏任何颜色(覆盖由曲面像素实际使用的调色板索引) 当我运行此代码时: screen = pygame.display.set_mode((222,222)) screen.fill((255,2

我有一个带有索引调色板的表面
BaseSurf
,我想
blit
另一个索引颜色表面(我们称之为
NewSurf
)。BaseSurf的调色板与NewSurf的不同,pygame不会自动将缺少的颜色添加到BaseSurf的调色板中。 因此,我需要某种方法将NewSurf的颜色添加到BaseSurf的调色板中,而不会损坏任何颜色(覆盖由曲面像素实际使用的调色板索引)

当我运行此代码时:

screen = pygame.display.set_mode((222,222))
screen.fill((255,255,255))

BaseSurf = pygame.load.image("4samps.png").convert(8)  # indexed with four colours; larger dimensions
NewSurf  = pygame.load.image("another4samps.png").convert(8)  # indexed with four more colours

screen.blit(BaseSurf, (10,10))
screen.blit(NewSurf, (160,43))

BaseSurf.blit(NewSurf, (33,33))

screen.blit(BaseSurf, (50,122))
…这就是我看到的

--编辑:请注意,组合的图形将NewSurf中的颜色近似于BaseSurf使用的任何颜色,即使顺序已关闭。右下角的blob实际上采用一个空值(0,0,0255)作为最接近的匹配颜色

显然,NewSurf(右侧)的索引已转移到BaseSurf,这并不完全是错误的,但也不是我想要的。 如何将NewSurf blit到BaseSurf,在修改后的图像中保留其精确的颜色数据(但保留索引的彩色图像)


我在问这个问题的过程中找到了答案

使用
pygame.Surface.set_palete_at()
,我能够从NewSurf提取调色板数据(使用
NewSurf.get_palete(…)
和一个迭代器清除调色板的空白),并使用
BaseSurf.set_palete_at将其粘贴到BaseSurf调色板的“end”(即最后一个非空白RGBA索引值之后)(第一个索引为空,新值为空)

您可以通过多种方式找到
first\u null\u RGBA\u value
;我使用
next()
get\u调色板()中的“使用中”调色板后面的空值列中找到第一个空值(由
blankRGBA
定义,根据我的经验,它通常是(0,0,0255))
。您还可以使用
get_palete().index(blankRGBA)
获取第一个空白值的索引(如果图形中实际有空白值像素,这是非常危险的!)。稍后我将介绍这些方法及其问题(如我所见)

碰巧的是,我似乎不必重新为NewSurf编制索引,使其索引与BaseSurf调色板中的新位置对齐。我不知道如果重新映射重复的RGB值,会产生什么后果!我想象pygame会从blit’d图像中近似RGB值,以匹配接收图像中最接近的值——如果y,则完全匹配你事先有目的地将NewSurf中的整个调色板粘贴到BaseSurf中

我是这样做的

   ... # initialized and blitted samples as before...
blankRGBA = (0,0,0,255)  # the RGBA value for null values in the index.

destpal   = list(BaseSurf.get_palette())
pallength = len(destpal) - 1 # This is probably always going to be 255, but just to be sure... (minus one 'cuz indices start at zero.)

nextblank = pallength - next((n for n, RGBA in enumerate(destpal[::-1]) if RGBA != blankRGBA), - 1)   
    #  ^ The palette will have a train of null values matching blankRGBA for every unusued index value. If the palette is complete full, it'll raise an error later.
    # This finds the index of the first such value by following the train until it 'starts', then subtracting that index number from the total length (probably 256). I'll explain why destpal.index(blankRGBA) is chancey later...

copypal = list(NewSurf.get_palette())
while True:
    if copypal[-1] == blankRGBA:  # Get rid of NewSurf's null index train, too.
        copypal.pop()
    else:
        print "Popped all trailing blank values from the incoming palette. %d entries remain." % len(copypal)
        break

    if not copypal:
        raise IndexError, "Depleted incoming palette. It was entirely blank entries?! What??"

    # Now that we have the useful section of NewSurf's palette (copypal) and the indices we can replace with it (nextblank), let's apply the new values and reindex NewSurf ahead of blitting it...

for n, newRGBA in enumerate(copypal):  
    if (nextblank + n) > 255: # It's possible the thing will fill up. For now, I'll have it throw an error.
        raise IndexError, "Ran out of palette space at %s! (colour number %d)" % (newRGBA, n)
    BaseSurf.set_palette_at((nextblank + n), newRGBA)  # Add the palette value to BaseSurf. As it happens, blit will reindex the colours on its own.

baseimage.blit(newimage, (33,33))
screen.blit(baseimage, (50, 122))

pygame.display.flip()

我可能还可以从NeXurf的调色板中清除一些类似于<代码> > CopPale=列表(RGB在NexSurf中的RGBA,GETA PaleTeTe)(RGBA!= BLANKRGBA)< /COD>(而不是<代码>),而true;…CopyPal.Popor()/代码>循环。我也可以在BaseSurf的调色板中找到第一个空白,使用<代码> DestPal.索引。(blankRGBA)而不是更复杂的

next()
指令。我之所以不这样做,是因为选项板有可能对图像中的至少一个像素使用了
blankRGBA
值,并且这些像素本来应该是空白的——不太可能(0,0,025)将在图像中的某个位置使用

据推测,如果是这种情况,RGBA索引将位于调色板的开头而不是末尾。如果它们不在最后一个索引的任何位置,它们将是安全的。否则,可能会出现问题


对于可以非常紧密地控制图像数据的情况,这些压缩版本也可以工作。

但是请注意,它们很可能不那么Pythonic,因为它们更难阅读,并且更容易出现某些问题(意外地替换了实际使用的看起来为空的索引值)和未处理的异常(BaseSurf中的调色板空间不足)

使用风险自负

  # init as before...
for newRGBA in tuple(RGBA for RGBA in NewSurf.get_palette() if RGBA != blankRGBA):
    try: swapidx = next(n for n, RGBA in enumerate(BaseSurf.get_palette()) if RGBA == blankRGBA)
    except StopIteration: raise IndexError, "Ran out of palette space!"
    BaseSurf.set_palette_at(swapidx, newRGBA)

BaseSurf.blit(NewSurf, (33,33))
screen.blit(BaseSurf, (50, 122))
这会稍微慢一点,因为
next()
将迭代copypal中每个值的调色板,但是,行更少,这是一件好事

你甚至可以使用这个可怕的、非常不和谐的单音:

[BaseSurf.set_palette_at(swapidx, newRGBA) for swapidx, newRGBA in zip(tuple(n for n, RGBA in enumerate(BaseSurf.get_palette()) if RGBA == blankRGBA), tuple(RGBA for RGBA in NewSurf.get_palette() if RGBA != blankRGBA))]  # PLEASE GOD NO.

请注意,我不推荐这两个简短版本。我只出于学术考虑才将它们包括在内。

为了便于参考,这里的任何解决方案都会引发异常
[pygame]错误:如果其中一个曲面没有索引,则Surface没有要获取的调色板。
BaseSurf
没有索引,您不必担心它,因为它没有调色板。如果没有索引,您将很难使用它。运行类似于
PalSurf=PalSurf.convert(8)的程序
会将PalSurf转换为索引图像,但可能会或可能不会帮助您,具体取决于该曲面上的实际颜色数。您可以通过
尝试跳过整个过程,pygame除外。错误
测试
XSurf.get_调色板()
。我还注意到有一个黑色像素(更像三个)在BaseSurf的右上角,它实际上构成了调色板上的第五种颜色,在调色板更新期间,它必须被覆盖(然后近似于另一个空索引值)。我想。我猜pygame也有一些意外情况。。。