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

Time:03-13

I've been working on a piece of code that compares two images and tells me if they are similar, it also tells me which pixels are different in the image, after this it plots them into a pygame screen so that I can see which parts of the image are moving more clearly. The only problem is that it seems as if pygame cannot handle it or something and it crashes, no errors appear.

code:

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()

image1:

enter image description here

image2:

enter image description here

CodePudding user response:

Pygame didn't crash. You know how defining a Pygame window without calling the pygame.event.get() method would cause problems, right? Well, when you put

    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))

into the while loop that's supposed to constantly call the pygame.event.get() method, you are dramatically slowing down the looping process.

To see this with your eyes, add a print() statement into the loop, and see how slow it prints:

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()

One fix is to move the pygame.event.get() call into the nested for loop (as well as the pygame.display.update() call if you want to see the updating):

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()

CodePudding user response:

Use 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}")

If you don't want to import 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}")

Minimal example:

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()
  • Related