python, cv2.imshow(), raspberryPi and a black screen - python

Currently trying write code with a GUI which will allow for toggling on/off image processing. Ideally the code will allow for turning on/off window view, real time image processing (pretty basic), and controlling an external board.
The problem I'm having revolves around the cv2.imshow() function. A few months back I made a push to increase processing rates by switching from picamera to cv2 where I can perform more complex computations like background subtraction without having to call python all the time. using the bcm2835-v4l2 package, I was able to pull images directly from the picamera using cv2.
fast forward 6 months and while trying to update the code, I find that the function cv2.imshow() does not display correctly anymore. I thought it might be a problem with bcm2835-v4l2 but tests using matplotlib show that the connection is fine. it appears to have everything to do with cv2.imshow() or so I guess.
I am actually creating a separate thread using the threading module for image capture and I am wondering if this could be the culprit. I don't think so though as typing in the commands
import cv2
camera = cv2.VideoCapture(0)
grabbed,frame = camera.read()
cv2.imshow(frame)
produces the same black screen
Down below is my code I am using (on the RPi3) and some images show the error and what is expected.
as for reference here are the details about my system
Raspberry pi3
raspi stretch
python 3.5.1
opencv 3.4.1
Code
import cv2
from threading import Thread
import time
import numpy as np
from tkinter import Button, Label, mainloop, Tk, RIGHT
class GPIOControllersystem:
def __init__(self,OutPinOne=22, OutPinTwo=27,Objsize=30,src=0):
self.Objectsize = Objsize
# Build GUI controller
self.TK = Tk() # Place TK GUI class into self
# Variables
self.STSP = 0
self.ShutdownVar = 0
self.Abut = []
self.Bbut = []
self.Cbut = []
self.Dbut = []
# setup pi camera for aquisition
self.resolution = (640,480)
self.framerate = 60
# Video capture parameters
(w,h) = self.resolution
self.bytesPerFrame = w * h
self.Camera = cv2.VideoCapture(src)
self.fgbg = cv2.createBackgroundSubtractorMOG2()
def Testpins(self):
while True:
grabbed,frame = self.Camera.read()
frame = self.fgbg.apply(frame)
if self.ShutdownVar ==1:
break
if self.STSP == 1:
pic1, pic2 = map(np.copy,(frame,frame))
pic1[pic1 > 126] = 255
pic2[pic2 <250] = 0
frame = pic1
elif self.STSP ==1:
time.sleep(1)
cv2.imshow("Window",frame)
cv2.destroyAllWindows()
def MProcessing(self):
Thread(target=self.Testpins,args=()).start()
return self
def BuildGUI(self):
self.Abut = Button(self.TK,text = "Start/Stop System",command = self.CallbackSTSP)
self.Bbut = Button(self.TK,text = "Change Pump Speed",command = self.CallbackShutdown)
self.Cbut = Button(self.TK,text = "Shutdown System",command = self.callbackPumpSpeed)
self.Dbut = Button(self.TK,text = "Start System",command = self.MProcessing)
self.Abut.pack(padx=5,pady=10,side=RIGHT)
self.Bbut.pack(padx=5,pady=10,side=RIGHT)
self.Cbut.pack(padx=5,pady=10,side=RIGHT)
self.Dbut.pack(padx=5,pady=10,side=RIGHT)
Label(self.TK, text="Controller").pack(padx=5, pady=10, side=RIGHT)
mainloop()
def CallbackSTSP(self):
if self.STSP == 1:
self.STSP = 0
print("stop")
elif self.STSP == 0:
self.STSP = 1
print("start")
def CallbackShutdown(self):
self.ShutdownVar = 1
def callbackPumpSpeed(self):
pass
if __name__ == "__main__":
GPIOControllersystem().BuildGUI()
Using matplotlib.pyplot.imshow(), I can see that the connection between the raspberry pi camera and opencv is working through the bcm2835-v4l2 connection.
However when using opencv.imshow() the window result in a blackbox, nothing is displayed.
Update: so while testing I found out that when I perform the following task
import cv2
import matplotlib
camera = cv2.VideoCapture(0)
grab,frame = camera.read()
matplotlib.pyplot.imshow(frame)
grab,frame = camera.read()
matplotlib.pyplot.imshow(frame)
update was solved and not related to the main problem. This was a buffering issue. Appears to have no correlation to cv2.imshow()

on a raspberry you should work with
from picamera import PiCamera
checkout pyimagesearch for that

Related

Live dehazed video displayed with opencv, freezes, goes not responding

I want to implement this library with video dehazing ability.
I have only CPU, but I expect the result will be good without GPU,because video output of DCP,or any other dehaze algorithm works good.
So I developed this code:
import cv2
import torch
import numpy as np
import torch.nn as nn
import math
class dehaze_net(nn.Module):
def __init__(self):
super(dehaze_net, self).__init__()
self.relu = nn.ReLU(inplace=True)
self.e_conv1 = nn.Conv2d(3,3,1,1,0,bias=True)
self.e_conv2 = nn.Conv2d(3,3,3,1,1,bias=True)
self.e_conv3 = nn.Conv2d(6,3,5,1,2,bias=True)
self.e_conv4 = nn.Conv2d(6,3,7,1,3,bias=True)
self.e_conv5 = nn.Conv2d(12,3,3,1,1,bias=True)
def forward(self, x):
source = []
source.append(x)
x1 = self.relu(self.e_conv1(x))
x2 = self.relu(self.e_conv2(x1))
concat1 = torch.cat((x1,x2), 1)
x3 = self.relu(self.e_conv3(concat1))
concat2 = torch.cat((x2, x3), 1)
x4 = self.relu(self.e_conv4(concat2))
concat3 = torch.cat((x1,x2,x3,x4),1)
x5 = self.relu(self.e_conv5(concat3))
clean_image = self.relu((x5 * x) - x5 + 1)
return clean_image
model = dehaze_net()
model.load_state_dict(torch.load('snapshots/dehazer.pth',map_location=torch.device('cpu')))
device = torch.device('cpu')
model.to(device)
cap = cv2.VideoCapture(0)
while cap.isOpened():
ret, frame = cap.read()
if ret:
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
frame = torch.from_numpy(frame.transpose((2, 0, 1))).float().unsqueeze(0) / 255.0
frame = frame.to(device)
with torch.no_grad():
dehazed_frame = model(frame).squeeze().cpu().numpy()
dehazed_frame = (dehazed_frame * 255).clip(0, 255).transpose((1, 2, 0)).astype(np.uint8)
dehazed_frame = cv2.cvtColor(dehazed_frame, cv2.COLOR_RGB2BGR)
cv2.imshow('Dehazed Frame', dehazed_frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
else:
break
cap.release()
cv2.destroyAllWindows()
This is a single file code that needs only snapshots/dehazer.pth to be downloaded from original source(MayankSingal/PyTorch-Image-Dehazing).
I downloaded it and executed the code.
for time being let me show a paper in camera,
The problem:
The problem is
the window that shows the video freezes until it gets a new frame, i.e: Frame1--->FREEZE--->Frame2..., Here is some example:
for 1 second the window looks good
for 5 second the window goes not responding/hangs/freezes...
the window that shows the video, shows the frames with long delay, that is it takes about 5 second for a frame
I was expecting smooth live output(its fine even if Frame-Per-Second is 1 or 2), but I am not ok with that "Not responding" window, I feel the code I/Author have put has some flaw/problem/loop hole. If I use any other code, lik DCP,there is no problem. So whats the part that cause not responding, how to solve?
GUIs need to run their event processing regularly. If that doesn't happen often enough, the GUI becomes noticeably unresponsive. Most operating systems notice that for you and alert you about the program becoming unresponsive.
GUIs are event-based. Any intensive computations must be performed outside of the event loop, i.e. in a thread.
That is not the case in your program because you perform (compute-intensive) inference in the same loop that calls waitKey(), which is the function in OpenCV that performs GUI event processing.
Here is a brief sketch that shows how to use threads:
import cv2 as cv
import threading
import queue
def worker_function(stop_event, result_queue):
cap = cv.VideoCapture()
assert cap.isOpened()
while not stop_event.is_set():
(success, frame) = cap.read()
if not success: break
... # do your inference here
result_queue.put(result_frame)
cap.release()
if __name__ == "__main__":
stop_event = threading.Event()
result_queue = queue.Queue(maxsize=1)
worker_thread = threading.Thread(
target=worker_function, args=(stop_event, result_queue))
worker_thread.start()
cv.namedWindow("window", cv.WINDOW_NORMAL)
while True:
# handle new result, if any
try:
result_frame = result_queue.get_nowait()
cv.imshow("window", result_frame)
result_queue.task_done()
except queue.Empty:
pass
# GUI event processing
key = cv.waitKey(10)
if key in (13, 27): # Enter, Escape
break
stop_event.set()
worker_thread.join()
I didn't test this but the idea is sound.

Python: While loop updating LCD display

I'm fairly new to Python although I do have some understanding of programming.
I am currently using Python 3 on a Raspberry Pi with an LCD display connected to it.
I can output to the display using the PIL library and the examples that came with the display.
What I am trying to do is display a value that updates over a period of time.
To break this down I created a while loop that displays a number, sleeps for 3 seconds, increments the number and then runs back through the loop checking the integer is not greater than 10.
However, the screen never updates the integer. To make sure it’s incrementing and testing correctly I put a print statement to the console and can see it incrementing.
I'm assuming it’s something to do with the while loop not refreshing the display but can't figure it out. Sample code below. Any help appreciated.
#!/usr/bin/python
# -*- coding: UTF-8 -*-
#import chardet
import os
import sys
import time
import logging
import spidev as SPI
sys.path.append("..")
from lib import LCD_2inch4
from PIL import Image,ImageDraw,ImageFont
# Raspberry Pi pin configuration:
RST = 27
DC = 25
BL = 18
bus = 0
device = 0
i = 0
logging.basicConfig(level=logging.DEBUG)
try:
# display with hardware SPI:
disp = LCD_2inch4.LCD_2inch4()
# Initialize library.
disp.Init()
# Clear display.
disp.clear()
# Create blank image for drawing.
image1 = Image.new("RGB", (disp.width, disp.height ), "WHITE")
draw = ImageDraw.Draw(image1)
logging.info("draw point")
while i <10:
test_var = "some text"
draw.rectangle([(0,65),(140,100)],fill = "WHITE")
draw.text((5, 68), test_var, fill = "BLACK")
draw.text((5,150), str(i), fill = "BLACK")
draw = ImageDraw.Draw(image1)
image1=image1.rotate(0)
disp.ShowImage(image1)
time.sleep(3)
i= i+1
print(i)
disp.clear()
disp.module_exit()
logging.info("quit:")
except IOError as e:
logging.info(e)
except KeyboardInterrupt:
disp.module_exit()
logging.info("quit:")
exit()

MediaPipe pose estimator with multiprocessing hangs on its process function

I am currently trying to implement MediaPipe pose estimator as an independent event-based process with Python's multiprocessing library, but it hangs on the MediaPipe's Pose.process() function.
I input the frame with another process (readFrames). Whenever a frame is captured, it is written into a shared object and tells the MediaPipe process (MediaPipeRunner) to start working on the current image:
def readFrames(ns, event):
#initialize the video capture object
cap = cv2.VideoCapture(0)
while cap.isOpened():
ret, frame = cap.read()
if ret:
ns.frame = frame
event.set()
cv2.imshow('Orijinal Frame', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
cap.release()
cv2.destroyAllWindows()
return -1
else:
return
class MediaPipeRunner(mproc.Process):
def __init__(self, name, nsFrame, nsMediaPipe, eventWait, eventPublish):
super(MediaPipeRunner, self).__init__()
# Specify a name for the instance
self.name = name
# Input and output namespaces
self.nsFrame = nsFrame
self.nsMediaPipe = nsMediaPipe
# Waiter and publisher events
self.eventWait = eventWait
self.eventPublish = eventPublish
# Create a pose estimator from MediaPipe
mp_pose = mp.solutions.pose
# Specify pose estimator parameters (static)
static_image_mode = True
model_complexity = 1
enable_segmentation = True # DONT CHANGE
min_detection_confidence = 0.5
# Create a pose estimator here
self.pose = mp_pose.Pose(
static_image_mode=static_image_mode,
model_complexity=model_complexity,
enable_segmentation=enable_segmentation,
min_detection_confidence=min_detection_confidence,
smooth_landmarks=False,
)
def run(self):
while True:
eventFrame.wait()
# This part is where it gets stuck:
results = self.pose.process(cv2.cvtColor(self.nsFrame.frame, cv2.COLOR_BGR2RGB))
if not results.pose_landmarks:
continue
self.nsMediaPipe.segmentation = results.segmentation_mask
eventMP.set()
This is how I bind the processes, namespaces and events:
if __name__=="__main__":
mgr = mproc.Manager()
nsFrame = mgr.Namespace()
nsMP = mgr.Namespace()
eventFrame = mproc.Event()
eventMP = mproc.Event()
camCap = mproc.Process(name='camCap', target=readFrames, args=(nsFrame, eventFrame, ))
camCap.daemon=True
mpCap = MediaPipeRunner('mpCap', nsFrame, nsMP, eventFrame, eventMP, )
mpCap.daemon=True
camCap.start()
mpCap.start()
camCap.join()
mpCap.join()
Am I taking a wrong step on processes or MediaPipe is not getting along with the multiprocessing library of Python?
Any help will be appreciated, thanks in advance :)
P.S.: I installed MediaPipe by pip and version 0.8.9.1 is present.
I have found the problem: The process function behaves correctly when with structure is used in Python (idk why):
with mp_pose.Pose(
static_image_mode=static_image_mode,
model_complexity=model_complexity,
enable_segmentation=enable_segmentation,
min_detection_confidence=min_detection_confidence,
smooth_landmarks=False,
) as pose:
Now this part works!
results = self.pose.process(cv2.cvtColor(self.nsFrame.frame, cv2.COLOR_BGR2RGB))
I hope it might be helpful for you.

File size limit in making timelapse video on the fly with OpenCV, Picamera and an IR camera

I am creating a raspberry pi timelapse camera encoding video with CV2 videowriter
Each image captured with picamera is added to the videowriter and once the intended number of images are taken the videowriter closes.
However - while this works for a few thousand images - it stops at some limit with a filesize of 366Mb which is now frustrating me and I ask you - the internet and hoard of coders to tell me why I am bad a coding and how to fix this - you must be tempted by this..
Here is my offering of garbage for you to laugh pitifully at
import os, cv2
from picamera import PiCamera
from picamera.array import PiRGBArray
from datetime import datetime
from time import sleep
now = datetime.now()
x = now.strftime("%Y")+"-"+now.strftime("%m")+"-"+now.strftime("%d")+"-"+now.strftime("%H")+"-"+now.strftime("%M") #string of dateandtimestart
print(x)
def main():
imagenum = 10000 #how many images
period = 1 #seconds between images
os.chdir ("/home/pi/t_lapse")
os.mkdir(x)
os.chdir(x)
filename = x + ".avi"
camera = PiCamera()
camera.resolution=(1920,1088)
camera.vflip = True
camera.hflip = True
camera.color_effects = (128,128) #makes a black and white image for IR camera
sleep(0.1)
out = cv2.VideoWriter(filename, cv2.cv.CV_FOURCC(*'XVID'), 30, (1920,1088))
for c in range(imagenum):
with PiRGBArray(camera, size=(1920,1088)) as output:
camera.capture(output, 'bgr')
imagec = output.array
out.write(imagec)
output.truncate(0) #trying to get more than 300mb files..
pass
sleep(period-0.5)
camera.close()
out.release()
if __name__ == '__main__':
main()
This example is a part of the whole code I've written (https://github.com/gchennell/RPi-PiLapse) which has an OLED display and buttons and selection of how many images as I have this all in an enclosure - the number of images seems to be limited to about 3000-4000 and then it just gives up and goes home... I tried adding the output.truncate(0)
I have also recreated this in python3 before you cry "BUT CV2.CV2.VIDEOWRITER!!!!" and that hasn't changed a thing - I'm missing something here...

Raspberry Pi - Python & Flask web control with Adafruit DotStar LEDS

apologies if this isn't the right place to ask, but I did some searching and couldn't find much to point me in the right direction. I wasn't quite sure what to search for. I am a novice with python and programming in general, but usually can do enough googling and stealing other code snippets to get my projects running. However I'm at a bit of a roadblock here.
I need to control an Adafruit DotStar lightstrip with a flask web browser app. I've been able to get the flask app working, I've done a simple proof of concept with turning an LED on and off etc., and I can start my lightstrip script but the code I'm trying to run for the lightstrip needs to loop continuously and still be able to change "modes". I have several different images that display on the light strip and I would like to be able to select which one(s) is/are playing, but for now mainly I would just like to be able to start and stop a "shuffle all" mode. If I run the module in a while loop it just loops forever and I can't change the argument to a different "mode". I built a simple script based on Adafruit's DotStar library (specifically the image persistence of vision script, I'm just using PNG images as the map for the different lightstrip "shows").
It all currently works except it only runs each mode once obviously. I had it all in a while loop and it just looped the first selected mode forever and I was unable to turn it off or switch modes. I also thought maybe I should use multiprocessing, and I looked into getting that working, but I couldn't figure out how to stop a process once it started.
Here is the light strip script:
(the 'off' mode is just a black image. I'm sure theres a cleaner way to do this but I'm not sure on how to do that either)
import Image
from dotstar import Adafruit_DotStar
import random
def lightstrip(mode):
loopLength = 120 #loop length in pixels
fade = "/home/pi/lightshow/images/fade.png"
sparkle = "/home/pi/lightshow/images/sparkle.png"
steeplechase = "/home/pi/lightshow/images/steeplechase.png"
bump = "/home/pi/lightshow/images/bump.png"
spaz = "/home/pi/lightshow/images/spaz.png"
sine = "/home/pi/lightshow/images/sine.png"
bounce = "/home/pi/lightshow/images/bounce.png"
off = "/home/pi/lightshow/images/null.png"
numpixels = 30
datapin = 23
clockpin = 24
strip = Adafruit_DotStar(numpixels, 100000)
rOffset = 3
gOffset = 2
bOffset = 1
strip.begin()
if mode == 1:
options = [fade, sparkle, steeplechase, bump, spaz, sine, bounce]
print "Shuffling All..."
if mode == 2:
options = [bump, spaz, sine, bounce]
print "Shuffling Dance..."
if mode == 3:
options = [fade, sparkle, steeplechase]
print "Shuffling Chill..."
if mode == 0:
choice = off
print "Lightstrip off..."
if mode != 0:
choice = random.choice(options)
print "Loading..."
img = Image.open(choice).convert("RGB")
pixels = img.load()
width = img.size[0]
height = img.size[1]
print "%dx%d pixels" % img.size
# Calculate gamma correction table, makes mid-range colors look 'right':
gamma = bytearray(256)
for i in range(256):
gamma[i] = int(pow(float(i) / 255.0, 2.7) * 255.0 + 0.5)
# Allocate list of bytearrays, one for each column of image.
# Each pixel REQUIRES 4 bytes (0xFF, B, G, R).
print "Allocating..."
column = [0 for x in range(width)]
for x in range(width):
column[x] = bytearray(height * 4)
# Convert entire RGB image into column-wise BGR bytearray list.
# The image-paint.py example proceeds in R/G/B order because it's counting
# on the library to do any necessary conversion. Because we're preparing
# data directly for the strip, it's necessary to work in its native order.
print "Converting..."
for x in range(width): # For each column of image...
for y in range(height): # For each pixel in column...
value = pixels[x, y] # Read pixel in image
y4 = y * 4 # Position in raw buffer
column[x][y4] = 0xFF # Pixel start marker
column[x][y4 + rOffset] = gamma[value[0]] # Gamma-corrected R
column[x][y4 + gOffset] = gamma[value[1]] # Gamma-corrected G
column[x][y4 + bOffset] = gamma[value[2]] # Gamma-corrected B
print "Displaying..."
count = loopLength
while (count > 0):
for x in range(width): # For each column of image...
strip.show(column[x]) # Write raw data to strip
count = count - 1
And the main.py script for running the web app:
from flask import *
from lightshow import *
from multiprocessing import Process
import RPi.GPIO as GPIO
import Image
from dotstar import Adafruit_DotStar
import random
import time
app = Flask(__name__)
#app.route("/")
def hello():
return render_template('index.html')
#app.route("/lightstrip/1", methods=['POST'])
def shuffleall():
lightstrip(1)
return ('', 204)
#app.route("/lightstrip/2", methods=['POST'])
def shuffledance():
lightstrip(2)
return ('', 204)
#app.route("/lightstrip/3", methods=['POST'])
def shufflechill():
lightstrip(3)
return ('', 204)
#app.route("/lightstrip/0", methods=['POST'])
def off():
lightstrip(0)
return ('', 204)
if __name__ == "__main__":
app.run(host='0.0.0.0', debug=True)
Again I'm at a bit of a loss here, this may be simple fix or I may be approaching it totally wrong but any and all help would be appreciated. I am a complete beginner to approaching a problem like this. Thank you
Here's an example showing how to start and stop processes using multiprocessing and psutil. In this example the task_runner kills any running processes before starting a new one.
from flask import Flask
import multiprocessing
import psutil
app = Flask(__name__)
def blink(var):
while True:
# do stuff
print(var)
def task_runner(var):
processes = psutil.Process().children()
for p in processes:
p.kill()
process = multiprocessing.Process(target=blink, args=(var,))
process.start()
#app.route("/red")
def red():
task_runner('red')
return 'red started'
#app.route("/blue")
def blue():
task_runner('blue')
return 'blue started'
if __name__ == "__main__":
app.run()
For your question, the task_runner would look something like:
def task_runner(mode):
processes = psutil.Process().children()
for p in processes:
p.kill()
process = multiprocessing.Process(target=lightstrip, args=(mode,))
process.start()

Categories

Resources