Преобразование координат пикселей в координаты кадра

#python #python-3.x #numpy

#python #python-3.x #numpy

Вопрос:

Я использую небольшое окно для обнаружения Марио, которое представлено красным блоком. Однако этот красный блок состоит из 16 на 12 пикселей. Я хочу взять координаты пикселей, которые я нашел, и преобразовать это в обычную систему координат x / y на основе окна, показанного на изображении: Фактический кадр, который должен быть размером 13 на 16 в сетке (НЕ в пикселях).

Так, например, если поле Mario находится в верхнем левом углу экрана, координаты должны быть равны 0,0.

Я также не уверен, как на самом деле создать сетку.

Код, который я использую, выглядит следующим образом:

 import numpy as np
from PIL import Image


class MarioPixels:

def __init__(self):
    self.mario = np.array([

        [[248, 56, 0],
         [248, 56, 0],
         [248, 56, 0],
         [248, 56, 0],
         [248, 56, 0],
         [248, 56, 0],
         [248, 56, 0],
         [248, 56, 0],
         [248, 56, 0],
         [248, 56, 0],
         [248, 56, 0],
         [248, 56, 0],
         [248, 56, 0],
         [248, 56, 0],
         [248, 56, 0],
         [248, 56, 0]
         ]]
    )

    self.height = len(self.mario)  # specify number of pixels for columns in the frame
    self.width = len(self.mario[0])  # specificy number of pixels representing a line in the frame

    print(self.mario.shape)

# find difference in R, G and B values between what's in window and what's on the frame
def pixelDiff(self, p1, p2):
    return abs(p1[0] - p2[0]), abs(p1[1] - p2[1]), abs(p1[2] - p2[2])

def isMario(self, window, pattern):
    total = [0, 0, 0]
    count = 0
    for line in range(len(pattern)):

        lineItem = pattern[line]
        sample = window[line]

        for pixelIdx in range(len(lineItem)):
            count  = 1
            pixel1 = lineItem[pixelIdx]
            pixel2 = sample[pixelIdx]
            d1, d2, d3 = self.pixelDiff(pixel1, pixel2)
            # print(pixelIdx)
            total[0] = total[0]   d1  # sum of difference between all R values found between window and frame
            total[1] = total[1]   d2  # sum of difference between all G values found between window and frame
            total[2] = total[2]   d3  # sum of difference between all B values found between window and frame
            # Mario has a red hat
            # if line == 0 and pixelIdx == 4 and pixel2[0] != 248:
            #    return 1.0

    rscore = total[0] / (
                count * 255)  # divided by count of all possible places the R difference could be calculated
    gscore = total[1] / (
                count * 255)  # divided by count of all possible places the G difference could be calculated
    bscore = total[2] / (
                count * 255)  # divided by count of all possible places the B difference could be calculated

    return (
                       rscore   gscore   bscore) / 3.0  # averaged to find a value between 0 and 1. Num close to 0 means object(mario, pipe, etc.) is there,
    # whereas, number close to 1 means object was not found.

def searchForMario(self, step, state, pattern):

    height = self.height
    width = self.width

    x1 = 0
    y1 = 0
    x2 = width
    y2 = height

    imageIdx = 0
    bestScore = 1.1
    bestImage = None
    bestx1, bestx2, besty1, besty2 = 0, 0, 0, 0

    for y1 in range(0, 240 - height, 8):  # steps in range row, jump by 8 rows
        y2 = y1   height

        for x1 in range(0, 256 - width, 3):  # jump by 3 columns
            x2 = x1   width

            window = state[y1:y2, x1:x2, :]
            score = self.isMario(window, pattern)
            # print(imageIdx, score)
            if score < bestScore:
                bestScore = score
                bestImageIdx = imageIdx
                bestImage = Image.fromarray(window)
                bestx1, bestx2, besty1, besty2 = x1, x2, y1, y2

            imageIdx  = 1

    bestImage.save('testrgb'   str(step)   '_'   str(bestImageIdx)   '_'   str(bestScore)   '.png')

    return bestx1, bestx2, besty1, besty2
  

Ответ №1:

Похоже, что здесь используется пиксельное соотношение сторон, поэтому ширина и высота каждого «блока» в пикселях будут разными.

Судя по вашему коду, ваше пиксельное пространство составляет 256×240 пикселей, но вы говорите, что на самом деле оно представляет собой сетку размером 13×16. Это означает, что каждый блок в x-домене равен (256/13) или около 20 пикселям, а в y-домене (240/16) 15 пикселям. Это означает, что «Mario» размером 16×12 пикселей занимает менее одного полного блока. Глядя на ваше изображение, кажется, что это возможно — кусты и облака также занимают менее одного блока.

Я предлагаю вам сначала убедиться, что сетка 13×16 правильная (просто потому, что она, похоже, не совсем соответствует вашему размеру пикселя, и потому, что размеры шага в ваших диапазонах подразумевают, что блоки на самом деле могут быть размером 3×8 пикселей). Затем вы можете попытаться добавить сетку к пиксельному изображению, просто установив значение каждого пикселя, у которого координата x, в точности делимая на 20, равна (0,0,0) для черного пикселя RGB (а также координата y, в точности делимая на 15 — используйте оператор модуля %). Чтобы получить координаты «блока», просто разделите x-co на 20, а y-co на 15 и округлите в меньшую сторону до ближайшего целого числа (или используйте // для выполнения округления как части деления).

Я предположил, что ваши пиксельные координаты также проходят от верхнего левого угла (0,0) до нижнего правого угла (256, 240).