为什么 pygame 在我尝试将单个像素绘制到屏幕上以获取图像时崩溃

Why does pygame crash when I try to plot individual pixels to the screen for an image

我一直在编写一段代码来比较两个图像并告诉我它们是否相似,它还告诉我图像中哪些像素不同,之后它将它们绘制成 pygame 屏幕,以便我可以更清楚地看到图像的哪些部分在移动。唯一的问题是,似乎 pygame 无法处理它或其他东西,它崩溃了,没有出现错误。

代码:

import cv2
import pygame
from pygame.locals import *

lib = 'Map1.png'
lib2 = 'Map2.png'
lib3 = []
coordenatesx = []
coordenatesy = []

Read = list(cv2.imread(lib).astype("int"))
Read2 = list(cv2.imread(lib2).astype("int"))

counter = 0

for i in range(len(Read)):#y coords
    for j in range(len(Read[i])):#x coords
        blue = list(Read[i][j])[0]
        green = list(Read[i][j])[1]
        red = list(Read[i][j])[2]
        blue2 = list(Read2[i][j])[0]
        green2 = list(Read2[i][j])[1]
        red2 = list(Read2[i][j])[2]
        difference = (blue+green+red)-(blue2+green2+red2)
        lib3.append(difference)
        if difference <= 10 and difference >= -10:
            counter+=1
            coordenatesx.append(j)
            coordenatesy.append(i)


if counter >= (i*j)*0.75:
    print('They are similar images')
    print('They are different by:', str((counter / (i * j)) * 100), '%')
else:
    print('They are different')
    print('They are different by:', str((counter / (i * j)) * 100), '%')

pygame.init()

screen = pygame.display.set_mode((500,500))

while 1:
    screen.fill((20))
    for event in pygame.event.get():
        if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
            pygame.quit()
    for l in range(len(coordenatesx)):
        for v in range(len(coordenatesy)):
            pygame.draw.rect(screen, (blue, red, green), pygame.Rect(coordenatesx[l], coordenatesy[v], 1, 1))
    pygame.display.update()

图片 1:

图片2:

Pygame 没有崩溃。您知道如何在不调用 pygame.event.get() 方法的情况下定义 Pygame window 会导致问题,对吗?好吧,当你把

    for l in range(len(coordenatesx)):
        for v in range(len(coordenatesy)):
            pygame.draw.rect(screen, (blue, red, green), pygame.Rect(coordenatesx[l], coordenatesy[v], 1, 1))

进入本应不断调用 pygame.event.get() 方法的 while 循环,您正在显着减慢循环过程。

为了亲眼看到这一点,在循环中添加一个 print() 语句,看看它打印的速度有多慢:

while 1:
    screen.fill((20))
    print("Looping...")
    for event in pygame.event.get():
        if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
            pygame.quit()
    for l in range(len(coordenatesx)):
        for v in range(len(coordenatesy)):
            pygame.draw.rect(screen, (blue, red, green), pygame.Rect(coordenatesx[l], coordenatesy[v], 1, 1))
    pygame.display.update()

一个解决方法是将 pygame.event.get() 调用 移动到 嵌套 for 循环 (以及 pygame.display.update() 如果您想查看更新,请致电):

while 1:
    screen.fill((20))
    for l in range(len(coordenatesx)):
        for v in range(len(coordenatesy)):
            for event in pygame.event.get():
                if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
                    pygame.quit()
            pygame.draw.rect(screen, (blue, red, green), pygame.Rect(coordenatesx[l], coordenatesy[v], 1, 1))
            pygame.display.update()

使用cv2/OpenCV and NumPy. Compute the absolute difference of the images with numpy.absolute. Sum the color channels and count the non-zero pixels with numpy.count_nonzero:

import cv2
import numpy

Read = cv2.imread('Map1.png').astype("int")
Read2 = cv2.imread('Map2.png').astype("int")

diff = numpy.absolute(Read - Read2).astype("uint8")
gray = numpy.sum(diff, axis=2)
count = numpy.count_nonzero(gray)
print(f"{count} / {gray.size}")

如果您不想导入 NumPy:

diff = abs(Read - Read2)
gray = (diff[:,:,0] + diff[:,:,1] + diff[:,:,2])
diff = diff.astype("uint8")
count = sum([c > 0 for r in gray for c in r])
print(f"{count} / {gray.size}")

最小示例:

import cv2
import numpy
import pygame
from pygame.locals import *

lib = 'Map1.png'
lib2 = 'Map2.png'

Read = cv2.imread(lib).astype("int")
Read2 = cv2.imread(lib2).astype("int")

diff = numpy.absolute(Read - Read2).astype("uint8")
gray = numpy.sum(diff, axis=2)
count = numpy.count_nonzero(gray)
print(f"{count} / {gray.size}")

pygame.init()
screen = pygame.display.set_mode((500,500))
clock = pygame.time.Clock()

def cv2ImageToSurface(cv2Image):
    if cv2Image.dtype.name == 'uint16':
        cv2Image = (cv2Image / 256).astype('uint8')
    size = cv2Image.shape[1::-1]
    if len(cv2Image.shape) == 2:
        cv2Image = np.repeat(cv2Image.reshape(size[1], size[0], 1), 3, axis = 2)
        format = 'RGB'
    else:
        format = 'RGBA' if cv2Image.shape[2] == 4 else 'RGB'
        cv2Image[:, :, [0, 2]] = cv2Image[:, :, [2, 0]]    
    surface = pygame.image.frombuffer(cv2Image.flatten(), size, format)
    return surface.convert_alpha() if format == 'RGBA' else surface.convert()

diff_surf = cv2ImageToSurface(diff)

run = True
while run:
    clock.tick(100)
    screen.fill((20))
    for event in pygame.event.get():
        if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
            run = False
   
    screen.fill(0)
    screen.blit(diff_surf, diff_surf.get_rect(center = screen.get_rect().center))
    pygame.display.update()

pygame.quit()