tmux - how to display an image in a pane? - python

I'd like to display an animated GIF or any other image in a pane in tmux.
I'm playing with asciimatics to do this, and have modded one of the sample programs (images.py) to:
display a single image
show no error messages on "Ctrl+C"
accept a single command line arg "image filename"
Here's the script I have and the only issue is that it seems to do a slow refresh of the image being displayed ~ every 10 seconds. How do I remove this refresh, since the image is a static image?
image.py
from __future__ import division
from asciimatics.effects import BannerText, Print, Scroll
from asciimatics.renderers import ColourImageFile, FigletText, ImageFile
from asciimatics.scene import Scene
from asciimatics.screen import Screen
from asciimatics.exceptions import ResizeScreenError
import sys
total = len(sys.argv)-1
if (total < 1):
print ("Usage: IMG")
sys.exit(1)
# Parsing args one by one
IMG = str(sys.argv[1])
def demo(screen):
scenes = []
effects = [
Print(screen,
ColourImageFile(
screen, IMG,
screen.height-2,
uni=screen.unicode_aware,
dither=screen.unicode_aware),
0,
stop_frame=200
)
]
scenes.append(Scene(effects))
screen.play(scenes, stop_on_resize=True)
# capture ctrl+c and exit nicely
import signal
import sys
def signal_handler(sig, frame):
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
if __name__ == "__main__":
while True:
try:
Screen.wrapper(demo)
#Screen.wrapper(demo, catch_interrupt=True)
sys.exit(0)
except ResizeScreenError:
sys.exit(0)

I just had to set stop_frame=0 and it works as hoped, as specified in the docs
Example usage
$ python image.py /images/fox.jpg
image.py
from __future__ import division
from asciimatics.effects import BannerText, Print, Scroll
from asciimatics.renderers import ColourImageFile, FigletText, ImageFile
from asciimatics.scene import Scene
from asciimatics.screen import Screen
from asciimatics.exceptions import ResizeScreenError
import sys
total = len(sys.argv)-1
if (total < 1):
print ("Usage: IMG")
sys.exit(1)
# Parsing args one by one
IMG = str(sys.argv[1])
def demo(screen):
scenes = []
effects = [
Print(screen,
ColourImageFile(
screen, IMG,
screen.height-2,
uni=screen.unicode_aware,
dither=screen.unicode_aware),
0,
stop_frame=200
)
]
scenes.append(Scene(effects))
screen.play(scenes, stop_on_resize=True)
# capture ctrl+c and exit nicely
import signal
import sys
def signal_handler(sig, frame):
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
if __name__ == "__main__":
while True:
try:
Screen.wrapper(demo)
#Screen.wrapper(demo, catch_interrupt=True)
sys.exit(0)
except ResizeScreenError:
sys.exit(0)

Related

Subscribing to Image Topic but doesn't output images

I have the following code that I've been struggling to get images from. There's a topic "CompressedImage" that has jpeg images from a camera in my robot. Below is my attempt. Terminal just gives me the versions from print and exits out.
#!/usr/bin/env python
import cv2
import numpy as np
from timeit import default_timer as timer
from std_msgs.msg import Float64
from sensor_msgs.msg import Image, CompressedImage
from cv_bridge import CvBridge, CvBridgeError
import rospy
import sys
print(sys.version)
print(cv2.__version__)
height = 480
width = 640
global_frame = np.zeros((height,width,3), np.uint8)
def camera_callback(data):
bridge = CvBridge()
try:
global_frame = bridge.compressed_imgmsg_to_cv2(data)
except CvBridgeError as e:
print(e)
height, width, channels = global_frame.shape
# print(height)
cv2.imshow("Original", global_frame)
def lane_pose_publisher():
# Set the node name
rospy.init_node('lane_pose_publisher', anonymous=True)
rospy.Subscriber('/camera/image_raw/compressed', CompressedImage, camera_callback, queue_size = 1)
# set rate
rate = rospy.Rate(1000) # 1000hz
if __name__ == '__main__':
try:
lane_pose_publisher()
except rospy.ROSInterruptException:
pass
This is because you are not spinning ROS. Check out the corresponding ROS tutorial to create a subscriber where
# spin() simply keeps python from exiting until this node is stopped
rospy.spin()
is called to ensure ROS can do his job (calling callbacks, ...).
So you should replace your lines
# set rate
rate = rospy.Rate(1000) # 1000hz
with the spinning ones.
Also you should add
cv2.waitKey(1)
after calling
cv2.imshow("Original", global_frame)
to ensure the image gets displayed.

How to multithread a program and return results to main.py?

I am using Windows and python. The objective is simple, running the main.py starts a speech recognition and once it recognizes what was said returns the text to main.py. The speech recognition program recognizes without any issues, the problem is at multithreading and getting the result back to main.py.
Here is the main.py:
import threading
from speechEngine.recognize import *
from SpeechSynthesis.speech import *
from core.AI import *
spch= "default"
newthread=threading.Thread(target=speechrec())
newthread.start()
while(True):
if(spch == "default"):
print("at default")
continue
else:
print(spch)
result=process(spch)
speak(result)
spch="default"
And here is speech recognition which is called as a new thread:
import argparse
import os
import queue
from typing import Text
import sounddevice as sd
import vosk
import sys
import json
#from vosk import SetLogLevel
#SetLogLevel(-1)
def speechrec():
q = queue.Queue()
"a lot of argument lines have been deleted to increase readability"
try:
if args.model is None:
args.model = "model"
if args.samplerate is None:
device_info = sd.query_devices(args.device, 'input')
args.samplerate = int(device_info['default_samplerate'])
model = vosk.Model(args.model)
with sd.RawInputStream(samplerate=args.samplerate, blocksize = 8000, device=args.device, dtype='int16', channels=1, callback=callback):
rec = vosk.KaldiRecognizer(model, args.samplerate)
while True:
data = q.get()
if rec.AcceptWaveform(data):
vc=rec.FinalResult() #produces raw output of what the user said
vc=json.loads(vc)
vc=vc['text'] #converts the user speech to text format
if vc != '':
global spch
spch = vc
except KeyboardInterrupt:
parser.exit(0)

Python Pygame text overlay printing on top of itself each time

I'm currently wanting to use an old piece of Python code called python slideshow with time and weather (github). I'm using a Raspberry Pi and I've got it all setup and it works perfectly in landscape (normal) mode. This is a slideshow application which has a weather and time overlay developed on Pygame.
I want to use the application in portrait, however when I rotate my screen in the /boot/config.txt using display_rotate=1 (or 3) and restart the slideshow, everything appears to work, the weather overlay appears in the bottom left/right as it should, however as soon as any part of the weather or clock or day update, it prints the text over itself.
Has anyone got an idea of what might be causing this behaviour? I can't see anything in the code. Here's the python file from Git below and I have attached a screenshot of the strange behavour[image showing text overlay issue in the clock in this instance][1]:
Python slideshow with time and weather on github
#!/usr/bin/env python
"""
A pygame program to show a slideshow of all images buried in a given directory.
Originally Released: 2007.10.31 (Happy halloween!)
"""
from __future__ import division
import argparse
import os
import stat
import sys
import time
import datetime
import pygame
from pygame.locals import QUIT, KEYDOWN, K_ESCAPE
#weather
import pyowm
file_list = [] # a list of all images being shown
title = "pgSlideShow | My Slideshow!" # caption of the window...
waittime = 5 # default time to wait between images (in seconds)
def walktree(top, callback):
"""recursively descend the directory tree rooted at top, calling the
callback function for each regular file. Taken from the module-stat
example at: http://docs.python.org/lib/module-stat.html
"""
for f in os.listdir(top):
pathname = os.path.join(top, f)
mode = os.stat(pathname)[stat.ST_MODE]
if stat.S_ISDIR(mode):
# It's a directory, recurse into it
walktree(pathname, callback)
elif stat.S_ISREG(mode):
# It's a file, call the callback function
callback(pathname)
else:
# Unknown file type, print a message
print 'Skipping %s' % pathname
def addtolist(file, extensions=['.png', '.jpg', '.jpeg', '.gif', '.bmp']):
"""Add a file to a global list of image files."""
global file_list # ugh
filename, ext = os.path.splitext(file)
e = ext.lower()
# Only add common image types to the list.
if e in extensions:
print 'Adding to list: ', file
file_list.append(file)
else:
print 'Skipping: ', file, ' (NOT a supported image)'
def input(events):
"""A function to handle keyboard/mouse/device input events. """
for event in events: # Hit the ESC key to quit the slideshow.
if (event.type == QUIT or
(event.type == KEYDOWN and event.key == K_ESCAPE)):
pygame.quit()
def timeSince(lastTime,interval):
if (time.time() - lastTime)>=interval:
return True
else:
return False
def main(startdir="."):
global file_list, title, waittime
lastSwitch=time.time()
lastWeather=time.time()
owm = pyowm.OWM('4cc9ae1d116c7e70c145252ab605f260')
observation = owm.weather_at_place('Ottawa,CA')
w = observation.get_weather()
temperature=(w.get_temperature('celsius'))['temp']
status=w.get_status()
#print w
pygame.init()
# Test for image support
if not pygame.image.get_extended():
print "Your Pygame isn't built with extended image support."
print "It's likely this isn't going to work."
sys.exit(1)
walktree(startdir, addtolist) # this may take a while...
if len(file_list) == 0:
print "Sorry. No images found. Exiting."
sys.exit(1)
modes = pygame.display.list_modes()
print max(modes)
pygame.display.set_mode(max(modes))
screen = pygame.display.get_surface()
screen_width, screen_height= screen.get_size()
pygame.display.set_caption(title)
#pygame.display.toggle_fullscreen()
pygame.display.set_mode(max(modes),pygame.FULLSCREEN)
pygame.mouse.set_visible(0)
#create font
timeFont = pygame.font.Font("indulta/Indulta-SemiSerif-boldFFP.otf", 100)
dateFont = pygame.font.Font("indulta/Indulta-SemiSerif-boldFFP.otf", 60)
weatherFont = pygame.font.Font("indulta/Indulta-SemiSerif-boldFFP.otf", 60)
print str(waittime) +"wait time"
current = 0
num_files = len(file_list)
while(True):
try:
img = pygame.image.load(file_list[current])
img = img.convert()
tempX,tempY=img.get_size()
ratio =tempX/tempY
tempSize=(screen_width,int(screen_width/ratio))
print str(img.get_size())+" to "+ str(tempSize) +"and ratio: "+str(ratio)
# rescale the image to fit the current display
img = pygame.transform.scale(img, tempSize)
screen.blit(img, (0, 0))
#gets current weather
if timeSince(lastWeather,30):
observation = owm.weather_at_place('Ottawa,CA')
w = observation.get_weather()
temperature=(w.get_temperature('celsius'))['temp']
status=w.get_status()
print status
lastWeather=time.time()
print "updateing weather"
#gets the current time and displays it
timeText=datetime.datetime.now().strftime("%I:%M%p")
dateText=datetime.datetime.now().strftime("%B %d, %Y")
weatherText=str(int(temperature))+"`C "+status
timeLabel = timeFont.render(timeText, 1, (255,255,255))
dateLabel = dateFont.render(dateText, 1, (255,255,255))
weatherLabel = weatherFont.render(weatherText, 1, (255,255,255))
timeWidth, timeHeight= timeLabel.get_size()
dateWidth, dateHeight= dateLabel.get_size()
weatherWidth, weatherHeight= weatherLabel.get_size()
screen.blit(weatherLabel, (0, screen_height-weatherHeight))
screen.blit(timeLabel, (screen_width-timeWidth, screen_height-timeHeight-dateHeight))
screen.blit(dateLabel, (screen_width-dateWidth, screen_height-dateHeight))
pygame.display.flip()
input(pygame.event.get())
time.sleep(1/60)
except pygame.error as err:
print "Failed to display %s: %s" % (file_list[current], err)
sys.exit(1)
# When we get to the end, re-start at the beginning
if timeSince(lastSwitch,waittime):
current = (current + 1) % num_files;
lastSwitch=time.time()
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description='Recursively loads images '
'from a directory, then displays them in a Slidshow.'
)
parser.add_argument(
'path',
metavar='ImagePath',
type=str,
default='.',
nargs="?",
help='Path to a directory that contains images'
)
parser.add_argument(
'--waittime',
type=int,
dest='waittime',
action='store',
default=1,
help='Amount of time to wait before showing the next image.'
)
parser.add_argument(
'--title',
type=str,
dest='title',
action='store',
default="pgSlidShow | My Slideshow!",
help='Set the title for the display window.'
)
args = parser.parse_args()
#waittime = args.waittime
title = args.title
main(startdir=args.path)
I have found the answer. Adding the line screen.fill((0,0,0)) just above img = pygame.image.load(file_list[current])has fixed the issue.

Opencv multiprocessing in python - queue sync

I am a beginner with multiprocessing in Python. I am developing a multiprocessing script for OpenCV, since my computer does not succeed in real-time processing of OpenCV frames.
I aim at loading and processing frames in the main process, and displaying them using a child process. My problem is that I do not understand how to build the display loop from the queued frames. Can someone please help?
My code:
#!/usr/bin/env python
from multiprocessing import Process, Queue
from Queue import Empty
from PIL import Image
import cv2
import cv2.cv as cv
import numpy as np
def image_display(taskqueue):
cv2.namedWindow ('image_display', cv2.CV_WINDOW_AUTOSIZE)
while True:
if taskqueue.get()==None:
continue
else:
image = taskqueue.get()
im = Image.fromstring(image['mode'], image['size'], image['pixels'])
num_im = np.asarray(im)
cv2.imshow ('image_display', num_im)
if __name__ == '__main__':
taskqueue = Queue()
vidFile = cv2.VideoCapture('doppler.wmv')
p = Process(target=image_display, args=(taskqueue,))
p.start()
while True:
flag, image=vidFile.read()
if flag == 0:
break
im = Image.fromarray(image)
im_dict = {
'pixels': im.tostring(),
'size': im.size,
'mode': im.mode,
}
taskqueue.put(im_dict)
p.join()
cv.DestroyAllWindows()
EDIT
Thanks to the answers, I was able to find the problem. Below is a modified script in which I slowed my loops on purpose and added an outqueue for debugging. It appears that although the frames captured with vidFile.read() are indeed passed as numpy arrays through the queue and are then passed unmodified as argument to cv2.imshow(),cv2.imshow() refuses to display the image for an unknown reason. Any help to fix that issue would be immensly appreciated!
modified code:
#!/usr/bin/env python
from multiprocessing import Process, Queue
from Queue import Empty
import cv2
import cv2.cv as cv
import numpy as np
import time
def image_display(taskqueue, outqueue):
cv2.namedWindow ('image_display', cv2.CV_WINDOW_AUTOSIZE)
while True:
try:
outqueue.put('trying')
time.sleep(1)
image = taskqueue.get()
outqueue.put(image)
cv2.imshow('image_display', image)
except:
continue
if __name__ == '__main__':
taskqueue = Queue()
outqueue = Queue()
vidFile = cv2.VideoCapture('doppler.wmv')
p = Process(target=image_display, args=(taskqueue, outqueue))
p.start()
while True:
print outqueue.get()
flag, image=vidFile.read()
if flag == 0:
break
taskqueue.put(image)
time.sleep(0.010)
p.join()
cv.DestroyAllWindows()
This should work (explanation of changes below):
#!/usr/bin/env python
from multiprocessing import Process, Queue
from Queue import Empty
from PIL import Image
import cv2
import cv2.cv as cv
import numpy as np
def image_display(taskqueue):
cv2.namedWindow ('image_display', cv2.CV_WINDOW_AUTOSIZE)
while True:
image = taskqueue.get() # Added
if image is None: break # Added
cv2.imshow ('image_display', image) # Added
cv2.waitKey(10) # Added
continue # Added
if taskqueue.get()==None:
continue
else:
image = taskqueue.get()
im = Image.fromstring(image['mode'], image['size'], image['pixels'])
num_im = np.asarray(im)
cv2.imshow ('image_display', num_im)
if __name__ == '__main__':
taskqueue = Queue()
vidFile = cv2.VideoCapture('doppler.wmv')
p = Process(target=image_display, args=(taskqueue,))
p.start()
while True:
flag, image=vidFile.read()
taskqueue.put(image) # Added
import time # Added
time.sleep(0.010) # Added
continue # Added
if flag == 0:
break
im = Image.fromarray(image)
im_dict = {
'pixels': im.tostring(),
'size': im.size,
'mode': im.mode,
}
taskqueue.put(im_dict)
taskqueue.put(None)
p.join()
cv.DestroyAllWindows()
I tried to make minimal changes to your code by just adding lines (lines containing comments # Added):
1) Just put the image itself (the original NumPy array) on the queue.
2) Pause a little bit in the master process before reading another frame. You need this so as not to overrun the queue, because imshow() in the spawned process may take a bit longer since it's calling X. You might need to increase this value (in seconds) depending on your system.
3) Spawned process has to do the waitKey() after every imshow().
4) Master process puts the special None image on the queue when it's done.

Building web-service to make screenshots of pages

Im building an online service that can make screenshots of web-pages and return it to user like an image. How it works:
1) I create virtual framebuffer for X server - for further dont create real windows
2) note in environment variables what display is to use
3) create child process (otherwise previous point will not make effect)
4) in child process create webkit.WebView(), "show" the window and load web-page
5) when I get notification about page is fully loaded - I make screenshot and save it to the file (it is only on this step of project, also - how to return it to user's browser? I know about Content type: image/png, but further - gtk.gdk.Pixbuf.save(stdout_file_name)? )
So! The problem! If I run it from the console python parent.cgi - everything is perfect, but if I open parent.cgi (server runs apache2) in web browser - then in real browser page trying to load infinitely, and in processes on server I see Xvfb appeared and plus three(it is obviously and correct) python process:
python return_picture.cgi
python /home/argon/www/wool/cgi-bin/parent.cgi
bash/sh -c python return_picture.cgi
The code:
parent.cgi:
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import gtk,webkit,gobject,sys,os,time,subprocess,logging
import cgitb,cgi
import signal
cgitb.enable()
logging.basicConfig(format = u'%(levelname)-8s [%(asctime)s] %(message)s', level = logging.INFO, filename = u'mylog.log')
logging.critical('ONE MORE TIME')
print "Content-Type: text/html;charset=utf-8"
print '' #it is importantly required
class writer(object):
def write(self, data):
logging.critical(data)
sys.stdout = writer()
sys.stderr = writer()
class XServer():
def __init__(self, silence_xvfb=True, display='1', screen='0', xvfb_timeout=3):
self.pidfile = '/tmp/.X%s-lock' % display
redirect = '> /dev/null 2>&1'
redirect = ''
if not silence_xvfb:
redirect = ''
cmd = ' '.join(['Xvfb', ':'+display, '-screen', screen, '1600x1200x24', redirect])
if(os.path.isfile(self.pidfile)):
self._kill_xvfb()
#os.system(cmd+' &')
subprocess.Popen(cmd+' &', shell=True) #works througth filenodes thats why it is impossible to redirect to log - overriding of file.write() does not make sense
print 'XVFB STARTED'
self.xvfb = True
start = time.time()
while(True):
diff = time.time() - start
if(diff > xvfb_timeout):
raise SystemError("Timed-Out waiting for Xvfb to start - {0} sec".format(xvfb_timeout))
if(os.path.isfile(self.pidfile)):
break
else:
time.sleep(0.05)
os.putenv('DISPLAY', ':%s' % display)
def _kill_xvfb(self):
pid = int(open(self.pidfile).read().strip())
os.kill(pid, signal.SIGINT)
print 'KILLED'
def __del__(self):
# Kill the frame buffer
if(self.xvfb):
self._kill_xvfb()
xserver = XServer()
logging.debug('lets create child')
child = subprocess.Popen("python return_picture.cgi",shell=True,stdout=subprocess.PIPE)
s=child.stdout.readline()
print 'there again'
return_picture.cgi:
#! /usr/bin/env python
# -*- coding: utf-8 -*-
from blessings import Terminal
import gtk,webkit,gobject,sys,os,time,signal,logging
import cgitb,cgi
cgitb.enable()
t = Terminal()
logging.basicConfig(format = u'%(levelname)-8s [%(asctime)s] %(message)s', level = logging.DEBUG, filename = u'mylog.log')
class writer(object):
def write(self, data):
logging.critical(data)
sys.stdout = writer()
sys.stderr = writer()
logging.debug('IN CHILD')
#print "Content-Type: image/png"
#print "Content-Type: text/html;charset=utf-8"
#print '' #it is importantly required
#print 'hello'
web=webkit.WebView()
win=gtk.Window()
index = 0
finished = False
def finished_cb(web_view,sig,res):
global finished
global index
index += 1
#print index,': ',
status = web_view.get_property("load-status").value_name
logging.debug(str(index)+': '+status)
if "FINISH" in status and not finished:
finished = True
gobject.timeout_add(500,drawWindow)
print 'timeout'
return
sig2= "resource-load-finished"
web.connect(sig2, finished_cb)
url = 'http://google.com/'
web.open(url)
win.add(web)
def drawWindow():
width, height = win.get_size()
pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8, width, height)
screenshot = pixbuf.get_from_drawable(win.window, win.get_colormap(),
0, 0, 0, 0, width, height)
ret = screenshot.subpixbuf(0,0,300,20)
ret = screenshot
stdot_filename = os.readlink('/proc/self/fd/0')
print stdot_filename
#screenshot.save(stdot_filename, 'png')
gtk.main_quit()
screenshot.save('screenshot.png', 'png')
print 'screenshot saved'
win.show_all()
gtk.main()
You should decouple the requests for screenshots from their generation.
Have the webpage insert the URLs to take screenshots of into a queue. Have a process pulling items out of this queue and running the screenshot generation script.
This way the web browser doesn't wait for the screenshot process to run (which may just fail anyway), you can handle duplicate requests easily, and you don't overwhelm your server launching more WebKit instances than it can run at the same time.
That's how I do it at http://bookmarkly.com

Categories