Как представить массив numpy в Pygame surface?

Я пишу код, часть которого читает Источник изображения и отображает его на экране для взаимодействия с пользователем. Мне также нужны заостренные данные изображения. Я использую следующее, Чтобы прочитать данные и отобразить их в pyGame

def image_and_sharpen_array(file_name):
    #read the image data and return it, with the sharpened image
    image = misc.imread(file_name)

    blurred = ndimage.gaussian_filter(image,3)
    edge = ndimage.gaussian_filter(blurred,1)
    alpha = 20
    out = blurred + alpha*(blurred - edge)
    return image,out

#get image data
scan,sharpen = image_and_sharpen_array('foo.jpg')
w,h,c = scan.shape


#setting up pygame
pygame.init()
screen = pygame.display.set_mode((w,h))

pygame.surfarray.blit_array(screen,scan)
pygame.display.update()

и изображение на экране поворачивается и переворачивается. Это связано с различиями между misc.imread и pyGame? Или это из-за чего-то неправильного в моем коде?

есть ли другой способ сделать это? Этот большинство решений, которые я читал, включали сохранение фигуры, а затем чтение ее с помощью `pyGame".

4 ответов


каждый lib имеет свой собственный способ интерпретации массивов изображений. Под "вращением" вы, наверное, подразумеваете транспонирование. Вот так PyGame показывает массивы numpy. Есть много способов сделать его "правильным". На самом деле есть много способов даже появится блок, который дает вам полный контроль над представлением канала и так далее. В pygame версии 1.9.2 это самый быстрый рендеринг массива, который я когда-либо мог достичь. (Примечание Для более ранней версии это не будет работать!). Эта функция заполнит поверхность с массивом:

def put_array(surface, myarr):          # put array into surface
    bv = surface.get_view("0")
    bv.write(myarr.tostring())

Если это не работает, используйте это, должно работать везде:

# put array data into a pygame surface
def put_arr(surface, myarr):
    bv = surface.get_buffer()
    bv.write(myarr.tostring(), 0)

вы, вероятно, все еще получаете не то, что хотите, поэтому он транспонирован или поменял цветовые каналы. Идея состоит в том, чтобы управлять массивами в той форме, которая соответствует этому поверхностному буферу. Чтобы узнать, что такое правильный порядок каналов и порядок осей, используйте openCV библиотека (cv2.imread (filename)). С openCV вы открываете изображения в порядке BGR как стандарт, и он имеет много функций преобразования. Если я правильно помню, при записи непосредственно в буфер поверхности BGR является правильным порядком для 24 бит и BGRA для 32-битной поверхности. Таким образом, вы можете попытаться поместить массив изображений, который вы получаете из файла с этой функцией и blit на экран.

есть и другие способы рисования массивов, например, здесь весь набор вспомогательных функций http://www.pygame.org/docs/ref/surfarray.html
Но я бы не рекомендовал использовать его, так как поверхности не предназначены для прямого управления пикселями, вы, вероятно, потеряетесь в рекомендациях. Небольшой совет: для сигнализации тест использовать картинку, как это. Поэтому вы сразу увидите, что что-то не так, просто загрузите как массив и попробуйте сделать рендеринг.

enter image description here


мое предложение-использовать pygame.transform модуль. Есть flip и rotate методы,которые вы можете использовать, однако ваше преобразование. Посмотри документы по этому делу.

моя рекомендация-сохранить выходное изображение на новый Surface, а затем примените преобразования и blit к дисплею.

temp_surf = pygame.Surface((w,h))
pygame.surfarray.blit(temp_surf, scan)

'''transform temp_surf'''

screen.blit(temp_surf, (0,0))

Я понятия не имею, почему это происходит. Вероятно, это связано с порядком, в котором оси передаются из 2d-массива в pygame Surface.


Я думал, что technico предоставил хорошее решение-просто немного полагаться на информацию. Предполагая, что get_arr () - это функция, возвращающая массив пикселей:

pixl_arr = get_arr()
pixl_arr = numpy.swapaxes(pixl_arr, 0, 1)
new_surf = pygame.pixelcopy.make_surface(pixl_arr)
screen.blit(new_surf, (dest_x, dest_y))

кроме того, если вы знаете, что изображение всегда будет иметь одни и те же размеры (как при итерации кадров видео или gif-файла), было бы более эффективно повторно использовать одну и ту же поверхность:

pixl_arr = get_arr()
pixl_arr = numpy.swapaxes(pixl_arr, 0, 1)
pygame.pixelcopy.array_to_surface(old_surf, pixl_arr)
screen.blit(old_surf, (dest_x, dest_y))

YMMV, но пока это работает хорошо для меня.


Я часто использую numpy swapaxes() способ: В этом случае нам нужно только инвертировать оси x и y (оси 0 и 1) перед отображением нашего массива :

return image.swapaxes(0,1),out