Python OpenCV: Returning cvBridge Image from ROS - python

I recently just started OpenCv so apologies for any dumb questions.
So my ultimate aim is to stream video from my ZED camera on to a VR headset & I've not had any luck in Unity or UnReal as relevant plugins fail to work on my Linux machine. I need to be able to isolate the dual cameras from my ZED device but right now only ROS allows me to access the individual topics of either cam.
So I used a ZED wrapper to publish image data on to a ROS node and found code to interact with ROS messages from here.
The code works perfectly and I am able to display a stream of images captured on my monitor. But my issue is how do I basically save these images into a buffer/queue?
I modified the example to code to try to return the images converted by cvBridge but I'm not having any luck getting the returned image to show on screen. Think it may be because Image is initialised to None at first and so cv2.imshow() cannot display an empty picture. But how do I check if the rest of the images are being returned correctly? Here is my code:
import cv2
import rospy
from sensor_msgs.msg import Image
from cv_bridge import CvBridge, CvBridgeError
from Queue import Queue
class ImageConverter(object):
def __init__(self, object):
self.topic=object
self.bridge= CvBridge()
self.image_queue = Queue(maxsize=100)
self.image_sub = rospy.Subscriber(self.topic, Image, self.callback, queue_size=100)
self.image=None
def callback(self, data):
try:
cv_image=self.bridge.imgmsg_to_cv2(data, "bgr8")
except CvBridgeError as e:
print(e)
else:
self.image = cv_image
self.image_queue.put(cv_image)
def get_image(self):
try:
image = self.image_queue.get(block=False)
except:
image = self.image
cv2.imshow("Image window", image)
cv2.waitKey(3)
def subscribe(position):
ic= ImageConverter(position)
ic.get_image()
rospy.init_node('image_converter', anonymous=True)
try:
rospy.spin()
except KeyboardInterrupt:
print ("goodbye")
cv2.destroyAllWindows()
I have had such a difficult time trying to figure out how to do this all so any help would be very much appreciated. Thanks!

Your call back function has the following code:
try:
cv_image=self.bridge.imgmsg_to_cv2(data, "bgr8")
except CvBridgeError as e:
print(e)
else:
self.image = cv_image
self.image_queue.put(cv_image)
I think your else statement is a typo and may not be getting executed.

Related

OpenCV Python on Raspberry can't open camera by index. Device is busy

I am trying to stream the video feed of my FLIR Lepton to a webpage. I got myself some code that I don't yet fully understand. I am new to Flask. However, I got the camera working in VLC and a simple python script that captures 200 frames and saves them to a video file.
As stated in the title, I use OpenCV to do all of this, but I seem unable to "get" the camera. When trying to connect to the website, I get the "could not read" printout. I should also add that I am also experiencing problems, although different issues, with the PiCam module when trying the same thing.
What makes this even more mysterious is that the camera seems to go into captivity. The LED starts to flash, much as it would be when capturing video in the "simple" script.
This is the source of the file I am experiencing problems with:
from flask import Flask, render_template, Response
import cv2
from flirpy.camera.lepton import Lepton
fcamera = Lepton()
app = Flask(__name__)
camera = cv2.VideoCapture(1) # use 0 for web camera
# for cctv camera use rtsp://username:password#ip_address:554/user=username_password='password'_channel=channel_number_stream=0.sdp' instead of camera
# for local webcam use cv2.VideoCapture(0)
def gen_frames(): # generate frame by frame from camera
while True:
# Capture frame-by-frame
success, frame = camera.read() # read the camera frame
if not success:
print("could not read")
break
else:
ret, buffer = cv2.imencode('.jpg', frame)
frame = buffer.tobytes()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n') # concat frame one by one and show the result
#app.route('/video_feed')
def video_feed():
#Video streaming route. Put this in the src attribute of an img tag
return Response(gen_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')
#app.route('/')
def index():
"""Video streaming home page."""
return render_template('index.html')
if __name__ == '__main__':
app.run(debug=True)
And this is the simple file that runs without problems:
from flirpy.camera.lepton import Lepton
import matplotlib.pyplot as plt
import cv2 as cv
from time import sleep
cap = cv.VideoCapture(1)
fourcc = cv.VideoWriter_fourcc(*'XVID')
out = cv.VideoWriter('output.avi', fourcc, 20.0, (int(cap.get(3)), int(cap.get(4))))
i = 0
while cap.isOpened():
ret, frame = cap.read()
if not ret:
print("Can't receive frame (stream end?). Exiting ...")
break
# write the flipped frame
out.write(frame)
if i > 200:
break
i = i + 1
# Release everything if the job is finished
cap.release()
out.release()
I did not attempt to use any of these scripts simultaneously. Also, VLC is not running.
Thanks for any help!
javamaster10000

Python - Multiprocessing with function

I am fairly new to Python and Computer Vision but I've managed to setup a basic script to open my CCTV camera's at home. It works great but I have a slight issue is is that it loops over each camera one after the other, so instead of the camera image updating every second, it updates around every 5 seconds - the time it takes to complete a loop.
What I want is to be able to use multiprocessing / multi threading so that when I call the function for each of my cameras it open ins a new pool, running parallel to each other, therefore updating each camera every second.
As you can see in the below code I call each of the cameras using the same function, but with different argurments. I've read up on Process and have tried a few variations but I don't seem to be able to get it working.
I'm sure its a simple one and it would be great if someone could point me in the right direction.
Here's the code:
# import libraries
from threading import Thread
import imutils
import cv2, time
import argparse
import numpy as np
import datetime
from imutils.video import WebcamVideoStream
from multiprocessing import Process
stream = WebcamVideoStream('rtsp://mylink1./' ).start() # To open any valid video file stream/network stream. In this case 'test.mp4' file.
stream2 = WebcamVideoStream('rtsp://mylink2./' ).start()
stream3 = WebcamVideoStream('rtsp://mylink3./' ).start()
stream4 = WebcamVideoStream('rtsp://mylink4./' ).start()
stream5 = WebcamVideoStream('rtsp://mylink5./' ).start()
def checkimage(stream,camname):
global lastmessage
try:
frame = stream.read()
(h, w) = frame.shape[:2]
cv2.imshow(camname, frame)
print('[INFO]Checked ' + str(camname) + ' at ' + datetime.datetime.now().strftime("%H:%M:%S") + '...')
except AttributeError:
pass
# infinite loop
while True:
checkimage(stream,"Back Door Camera")
checkimage(stream2,"Conservatory Camera")
checkimage(stream3,"Front Door Camera")
checkimage(stream4,"Garage Camera")
checkimage(stream5,"Shed Camera")
key = cv2.waitKey(1) & 0xFF
# check for 'q' key-press
if key == ord("q"):
if 'q' key-pressed break out
break
cv2.destroyAllWindows()
# close output window
stream.stop()
# safely close video stream.
Thanks in advance!
Chris

How to display picture Server side with Flask and OpenCV?

I have a Flask server that shows a black image via OpenCV on a monitor. When arrives an HTTP request, it must show on the same window another image, which name arrives via parameter. After another request arrives on the endpoint "/destroy", a black images must be shown in the same window. I don' understand why this code doesn't work, do you have any suggestion? For not blocking the server, I need to use two different process in the endpoint, is this the correct way to use them?
#show black image before the server starts
image = cv2.imread("black.jpg",1)
screen = screeninfo.get_monitors()[1]
cv2.moveWindow("image", screen.x - 1, screen.y - 1)
cv2.imshow("image",image)
cv2.waitKey(1)
def imageShower(name):
#get name parameter and shows image with that name
image = cv2.imread(name+".jpg",1)
cv2.imshow("image",image)
cv2.waitKey(1)
def imageDestroyer():
#return to black image
image = cv2.imread("black.jpg",1)
cv2.imshow("image",image)
cv2.waitKey(1)
#at endpoint / start process that invokes imageShower()
#app.route('/')
def showImg():
#store image name arrived via parameter
name = request.args.get('name')
#start process
p = Process(target=imageShower(name))
p.start()
#return back to front-end
return "image showed"
#return black image on endpoint "/destroy"
#app.route('/destroy')
def destroy():
#start process
pd = Process(target=imageDestroyer)
pd.start()
#return back to front-end
return "returned to black"

How to use Python multiprocessing to prepare images for pygame

I'm making a slideshow app with that oh-so-naught-ies pan and zoom effect. I'm using pygame.
The main display is therefore realtime 30fps+, and I don't want it stuttering when it has to load a new image - this takes it over 1/30th of a second.
So I wanted to use some parallel process to prepare the images and feed the main process with these objects, which are instances of a class.
I've tried with threading and with multiprocess. Threading 'works' but it's still jumpy (I blame python) - the whole thing slows down when the thread is busy! So the code ran but it didn't meet the goal of allowing a continually smooth display.
But multiprocess segfaults (pygame parachute) as soon as I call a method on the received prepared image from the main process. I've tried pipe and queue communications - both result in the same problem. The method runs up until it does a call to
sized = pygame.transform.scale(self.image, newsize )
Then there's the segfault. This class does not have any dependencies from the main process.
Does pygame just not like multiprocessing? Is there another way that is compatible? Is there a way to 'nice' secondary threads that might stop the threading method performing?
Any help greatly appreciated. Happy to post more code, just ask in comments, but didn't want to dump a big listing here unless needed.
Thanks in advance!
EDIT
This is as short as I could make it. You need to provide three paths to jpeg files in the constructor at the bottom.
#!/usr/bin/env python2
import pygame
import sys
import time
import re
import os
import pickle
from random import randrange, shuffle
from multiprocessing import Process, Pipe
import Queue
class Img:
"""The image objects I need to pass around"""
def __init__(self, filename=None):
image = pygame.image.load(filename).convert()
self.image = pygame.transform.scale(image, (640,480))
def getSurface(self):
"""Get a surface, blit our image onto it in right place."""
surface = pygame.Surface((640,480))
# xxx this next command fails
sized = pygame.transform.scale(self.image, (640,480))
surface.blit(sized, (0,0))
return surface
class Floaty:
"""demo"""
def __init__(self, fileList):
self.fileList = fileList
pygame.init()
self.screen = pygame.display.set_mode((640,480))
# open the first image to get it going
self.img = Img(self.fileList.pop())
# Set up parallel process for opening images
self.parent_conn, child_conn = Pipe()
self.feeder = Process(target=asyncPrep, args=(child_conn,))
self.feeder.start()
def draw(self):
"""draw the image"""
# collect image ready-prepared by other process
if self.parent_conn.poll():
self.img = self.parent_conn.recv()
print ("received ", self.img)
# request new image
self.parent_conn.send(self.fileList.pop())
self.screen.blit(self.img.getSurface(), (0, 0))
pygame.display.flip()
def asyncPrep(conn):
"""load up the files"""
while True:
if conn.poll(1):
filename = conn.recv()
print ("doing ", filename)
img = Img(filename)
conn.send(img)
if __name__ == '__main__':
fileList = ['/path/to/a.jpg', 'path/to/b.jpg', 'path/to/c.jpg']
f = Floaty(fileList)
clock = pygame.time.Clock()
while 1:
f.draw()
clock.tick(4);
When I run this (Python 2.7.6) I get:
('doing ', '/path/to/a.jpg')
('received ', <__main__.Img instance at 0x7f2dbde2ce60>)
('doing ', '/path/to/b.jpg')
Fatal Python error: (pygame parachute) Segmentation Fault
zsh: abort (core dumped)
I solved this using multiprocessing by making the Img class load the image into a string buffer, stored in a property, then adding a postReceive method which loads it into a surface stored in the image property.
The postReceive method is called by the parent process after receiving the Img object from the child.
Therefore the object created by the child is not bound to anything pygame-y.
self.imageBuffer = pygame.image.tostring(
pygame.transform.scale(image, (640,480)),
'RGB')
Then, the new method in Img is simply:
def: postReceive(self):
self.image = pygame.image.frombuffer( self.imagebuffer, 'RGB' )
Add a call to this here:
# collect image ready-prepared by other process
if self.parent_conn.poll():
self.img = self.parent_conn.recv().postReceive()
print ("received ", self.img)

Raspberry Pi Python Open CV Photo Booth

I'm working on making a photo booth running on a Raspberry Pi using Python and OpenCV. I found a great code example of how to capture images from a web cam here. http://joseph-soares.com/programacao/python/python-opencv-salvar-imagem-da-camera-no-disco/
The code that is provided alone works perfect on both the Pi and on my Windows PC. When I start adding code to this I'm having issues. I can no longer see what the web cam is seeing on the Pi and on Windows it is hit or miss. They are both capturing pictures though. In Windows it will actually display the image taken in the frame. If I revert back to the original code, again it works just fine.
I'm basically using a loop to give a count down before the picture is taken and flashing a light on the Arduino to represent the digit output that will be added in. I originally thought it was a memory issue on the Pi but it not working on my desktop is making me think otherwise. Any help would be appreciated.
import time, cv
from datetime import datetime
import pyfirmata
import serial
#board = pyfirmata.Arduino('/dev/ttyACM0')
board = pyfirmata.Arduino('COM7')
#arduino.open()
# start an iterator thread so
# serial buffer doesn't overflow
iter8 = pyfirmata.util.Iterator(board)
iter8.start()
greenLED = board.get_pin('d:13:o')
debug = 1
def captureImage():
snapped = cv.QueryFrame(capture)
cv.SaveImage(datetime.now().strftime('%Y%m%d_%Hh%Mm%Ss%f') + '.jpg', snapped)
if __name__ == '__main__':
capture = cv.CaptureFromCAM(0)
cv.NamedWindow('Webcam')
try:
while True:
for n in range(0, 4):
frame = cv.QueryFrame(capture)
cv.ShowImage('Webcam', frame)
cv.WaitKey(10)
if debug: print "count down"
for i in range (0, 5):
print i
greenLED.write(1)
time.sleep(1)
greenLED.write(0)
time.sleep(0.2)
i+=1
greenLED.write(1)
time.sleep(0.2)
print "Say Cheese"
captureImage()
greenLED.write(0)
if debug: print "Waiting for 5 seconds"
time.sleep(5)
n+=1
break
capture = None
cv.DestroyAllWindows()
board.exit()
except KeyboardInterrupt:
cv.DestroyAllWindows()
board.exit()

Categories