Show an image with omxiv direct from memory on RPI

喜欢而已 提交于 2021-02-13 17:27:03

问题


I want to create an image in PILLOW and show it on the screen on the Raspberry Pi with for example omxiv direct from memory without saving it to the memory card, something like this:

Python 2.7:

from PIL import Image
import os

img = Image.new('RGB', size=(150, 50), color=(0, 0, 255))
....
im_file = ????
os.system('omxiv im_file')

Can anybody tell me how to do this?


回答1:


I did some experiments with the framebuffer on my Raspberry Pi 4. Here is what I managed to work out...

You can get the screen resolution using the fbset command like this:

fbset -fb /dev/fb0 

Sample Output

mode "1280x1024"
    geometry 1280 1024 1280 1024 32
    timings 0 0 0 0 0 0 0
    accel true
    rgba 8/16,8/8,8/0,0/0
endmode

That tells me the screen is 1280 px wide and 1024 px high and I need to write 4 bytes per pixel in the order BGRA888.


So, I can do a quick test with ImageMagick to see if I can fill the screen, like this:

# Write to screen buffer - BGRA8888, width=1280, height=1024
convert -size 1280x1024 -depth 8 gradient:lime-magenta  bgra:/dev/fb0

and it fills the screen with a lime-magenta gradient. Excellent!


So, having acquired that knowledge and a smattering of confidence, let's try Python...

#!/usr/bin/env python3

import numpy as np

# Map the screen as Numpy array
# N.B. Numpy stores in format HEIGHT then WIDTH, not WIDTH then HEIGHT!
# c is the number of channels, 4 because BGRA
h, w, c = 1024, 1280, 4
fb = np.memmap('/dev/fb0', dtype='uint8',mode='w+', shape=(h,w,c)) 

# Fill entire screen with blue - takes 29 ms on Raspi 4
fb[:] = [255,0,0,255]

# Fill top half with red - takes 15 ms on Raspi 4
fb[:h//2] = [0,0,255,255]

# Fill bottom right quarter with green - takes 7 ms on Raspi 4
fb[h//2:, w//2:] = [0,255,0,255] 

I then tried displaying an image - Lena, of course. So, just for brevity and simplicity, I made Lena exactly the right size and added an alpha channel with ImageMagick:

convert lena.png -resize 1280x1024\! -alpha opaque png32:lena1280.png

Then carried on as follows in the Python session I started above:

from PIL import Image

# Load Lena image
im = Image.open('/home/pi/lena1280.png') 

# Convert from PIL Image to Numpy array
n = np.array(im)

# Blit to screen - takes 30ms
fp[:] = n

Note that you would probably do better using OpenCV to load the image, with cv.imread(...,cv.IMREAD_UNCHANGED), because that will deliver you a Numpy array directly without needing conversion and the BGR ordering will already match that of the frame buffer.


Other useful commands - for my own reference!

# Retrieve EDID settings from monitor and write into a file called "edid"
tvservice -d edid

# Parse the file we just created to see what the attached monitor is capable of
edidparser edid

Sample Output

Enabling fuzzy format match...
Parsing edid...
HDMI:EDID version 1.3, 0 extensions, screen size 38x30 cm
HDMI:EDID features - videodef 0x80 standby suspend active off; colour encoding:RGB444|YCbCr444|YCbCr422; sRGB is default colourspace; preferred format is native; does not support GTF
HDMI:EDID found monitor S/N descriptor tag 0xff
HDMI:EDID found monitor name descriptor tag 0xfc
HDMI:EDID monitor name is DELL_1907FP
HDMI:EDID found monitor range descriptor tag 0xfd
HDMI:EDID monitor range offsets: V min=0, V max=0, H min=0, H max=0
HDMI:EDID monitor range: vertical is 56-76 Hz, horizontal is 30-81 kHz, max pixel clock is 140 MHz
HDMI:EDID monitor range does not support GTF
HDMI:EDID found preferred DMT detail timing format: 1280x1024p @ 60 Hz (35)
HDMI:EDID established timing I/II bytes are A5 4B 00
HDMI:EDID found DMT format: code 4, 640x480p @ 60 Hz in established timing I/II
HDMI:EDID found DMT format: code 6, 640x480p @ 75 Hz in established timing I/II
HDMI:EDID found DMT format: code 9, 800x600p @ 60 Hz in established timing I/II
HDMI:EDID found DMT format: code 11, 800x600p @ 75 Hz in established timing I/II
HDMI:EDID found DMT format: code 16, 1024x768p @ 60 Hz in established timing I/II
HDMI:EDID found DMT format: code 18, 1024x768p @ 75 Hz in established timing I/II
HDMI:EDID found DMT format: code 36, 1280x1024p @ 75 Hz in established timing I/II
HDMI:EDID standard timings block x 8: 0x714F 8180 0101 0101 0101 0101 0101 0101 
HDMI:EDID found DMT format: code 21, 1152x864p @ 75 Hz (4:3) in standard timing 0
HDMI:EDID found DMT format: code 35, 1280x1024p @ 60 Hz (5:4) in standard timing 1
HDMI:EDID filtering formats with pixel clock unlimited MHz or h. blanking unlimited
HDMI:EDID best score mode initialised to DMT (4) 640x480p @ 60 Hz with pixel clock 25 MHz (score 0)
HDMI:EDID best score mode is now DMT (4) 640x480p @ 60 Hz with pixel clock 25 MHz (score 36864)
HDMI:EDID DMT mode (6) 640x480p @ 75 Hz with pixel clock 31 MHz has a score of 11520
HDMI:EDID best score mode is now DMT (9) 800x600p @ 60 Hz with pixel clock 40 MHz (score 57600)
HDMI:EDID DMT mode (11) 800x600p @ 75 Hz with pixel clock 49 MHz has a score of 18000
HDMI:EDID best score mode is now DMT (16) 1024x768p @ 60 Hz with pixel clock 65 MHz (score 94370)
HDMI:EDID DMT mode (18) 1024x768p @ 75 Hz with pixel clock 78 MHz has a score of 29491
HDMI:EDID DMT mode (21) 1152x864p @ 75 Hz with pixel clock 108 MHz has a score of 62324
HDMI:EDID best score mode is now DMT (35) 1280x1024p @ 60 Hz with pixel clock 108 MHz (score 5260929)
HDMI:EDID DMT mode (36) 1280x1024p @ 75 Hz with pixel clock 135 MHz has a score of 49152
HDMI0:EDID preferred mode remained as DMT (35) 1280x1024p @ 60 Hz with pixel clock 108 MHz
HDMI:EDID has only DVI support and no audio support
edidparser exited with code 0

You can turn off/disbale the text cursor in the console like this:

sudo sh -c "TERM=linux setterm -foreground black -clear all >/dev/tty0"

and re-enable it like this:

sudo sh -c "TERM=linux setterm -foreground white -clear all >/dev/tty0"

Keywords: Raspberry Pi, RasPi, framebuffer, fb0, /dev/fb0, Python, Numpy, ImageMagick, direct frame buffer access, edid, HDMI, DVI, monitor capabilities, features, tvservice, edidparser, resolution, bgra8888, blit, bit-blit, cursor




回答2:


The easiest way to do this is to make sure your /tmp filesystem is mounted on tmpfs which is purely memory-based and therefore is not written to your SD card. Note that means that the contents are lost on each reboot.

So, you need to become root and use your favourite editor to edit /etc/fstab, in my case that would be:

sudo vi /etc/fstab

And then you need to add a line like this:

tmpfs   /tmp    tmpfs   defaults,noatime,nosuid 0   0

Then save the file and reboot your RasPi. If you then run df you will see that /tmp is on tmpfs:

df
tmpfs             966620       0    966620   0% /tmp

So, now to your code. If this is a new project, which I guess it must be if you don't know how to get started, please consider using Python3 which has been out 10 years rather than Python2 which is being discontinued in 2 months.

Now you need to use this code:

#!/usr/bin/env python3

from PIL import Image
import sys, os

# Create a new 640x480 magenta image
img = Image.new('RGB', size=(640, 480), color=(255, 0, 255))

filename = '/tmp/image.jpg'
img.save(filename)
os.system('omxiv ' + filename)

Note that you "can" pass an image to omxiv on the command-line:

cat image.jpg | omxiv

or, with a Python program:

WriteImageWithPIL.py | omxiv

But, that produces two problems. Firstly, it no longer reads any keys you type on the keyboard because it is reading from stdin. Secondly, PIL gets upset writing to omxiv like that because it closes the pipe before PIL can flush the data, so you'd probably have to start using stdbuffer in there and that will make big mess.



来源:https://stackoverflow.com/questions/58772943/show-an-image-with-omxiv-direct-from-memory-on-rpi

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!