Trying to take pictures with Coral camera with Coral edgeTPU dev board but it is really slow - camera

To start with, I am not a developer, but a mere automation engineer that have worked a bit with coding in Java, python, C#, C++ and C.
I am trying to make a prototype that take pictures and stores them using a digital pin on the board. Atm I can take pictures using a switch, but it is really slow(around 3 seconds pr image).
My complete system is going to be like this:
A product passes by on a conveyor and a photo cell triggers the board to take an image and store it. If an operator removes a product(because of bad quality) the image is stored in a different folder.
I started with the snapshot function shipped with Mendel and have tried to get rid off the overhead, but the Gstream and pipeline-stuff confuses me a lot.
If someone could help me with how to understand the supplied code, or how to write a minimalistic solution to take an image i would be grateful :)
I have tried to understand and use project-teachable and examples-camera from Google coral https://github.com/google-coral, but with no luck. I have had the best luck with the snapshot tool that uses snapshot.py that are referenced here https://coral.withgoogle.com/docs/camera/datasheet/#snapshot-tool
from periphery import GPIO
import time
import argparse
import contextlib
import fcntl
import os
import select
import sys
import termios
import threading
import gi
gi.require_version('Gst', '1.0')
gi.require_version('GstBase', '1.0')
from functools import partial
from gi.repository import GLib, GObject, Gst, GstBase
from PIL import Image
GObject.threads_init()
Gst.init(None)
WIDTH = 2592
HEIGHT = 1944
FILENAME_PREFIX = 'img'
FILENAME_SUFFIX = '.png'
AF_SYSFS_NODE = '/sys/module/ov5645_camera_mipi_v2/parameters/ov5645_af'
CAMERA_INIT_QUERY_SYSFS_NODE = '/sys/module/ov5645_camera_mipi_v2/parameters/ov5645_initialized'
HDMI_SYSFS_NODE = '/sys/class/drm/card0/card0-HDMI-A-1/status'
# No of initial frames to throw away before camera has stabilized
SCRAP_FRAMES = 1
SRC_WIDTH = 2592
SRC_HEIGHT = 1944
SRC_RATE = '15/1'
SRC_ELEMENT = 'v4l2src'
SINK_WIDTH = 2592
SINK_HEIGHT = 1944
SINK_ELEMENT = ('appsink name=appsink sync=false emit-signals=true '
'max-buffers=1 drop=true')
SCREEN_SINK = 'glimagesink sync=false'
FAKE_SINK = 'fakesink sync=false'
SRC_CAPS = 'video/x-raw,format=YUY2,width={width},height={height},framerate={rate}'
SINK_CAPS = 'video/x-raw,format=RGB,width={width},height={height}'
LEAKY_Q = 'queue max-size-buffers=1 leaky=downstream'
PIPELINE = '''
{src_element} ! {src_caps} ! {leaky_q} ! tee name=t
t. ! {leaky_q} ! {screen_sink}
t. ! {leaky_q} ! videoconvert ! {sink_caps} ! {sink_element}
'''
def on_bus_message(bus, message, loop):
t = message.type
if t == Gst.MessageType.EOS:
loop.quit()
elif t == Gst.MessageType.WARNING:
err, debug = message.parse_warning()
sys.stderr.write('Warning: %s: %s\n' % (err, debug))
elif t == Gst.MessageType.ERROR:
err, debug = message.parse_error()
sys.stderr.write('Error: %s: %s\n' % (err, debug))
loop.quit()
return True
def on_new_sample(sink, snapinfo):
if not snapinfo.save_frame():
# Throw away the frame
return Gst.FlowReturn.OK
sample = sink.emit('pull-sample')
buf = sample.get_buffer()
result, mapinfo = buf.map(Gst.MapFlags.READ)
if result:
imgfile = snapinfo.get_filename()
caps = sample.get_caps()
width = WIDTH
height = HEIGHT
img = Image.frombytes('RGB', (width, height), mapinfo.data, 'raw')
img.save(imgfile)
img.close()
buf.unmap(mapinfo)
return Gst.FlowReturn.OK
def run_pipeline(snapinfo):
src_caps = SRC_CAPS.format(width=SRC_WIDTH, height=SRC_HEIGHT, rate=SRC_RATE)
sink_caps = SINK_CAPS.format(width=SINK_WIDTH, height=SINK_HEIGHT)
screen_sink = FAKE_SINK
pipeline = PIPELINE.format(
leaky_q=LEAKY_Q,
src_element=SRC_ELEMENT,
src_caps=src_caps,
sink_caps=sink_caps,
sink_element=SINK_ELEMENT,
screen_sink=screen_sink)
pipeline = Gst.parse_launch(pipeline)
appsink = pipeline.get_by_name('appsink')
appsink.connect('new-sample', partial(on_new_sample, snapinfo=snapinfo))
loop = GObject.MainLoop()
# Set up a pipeline bus watch to catch errors.
bus = pipeline.get_bus()
bus.add_signal_watch()
bus.connect('message', on_bus_message, loop)
# Connect the loop to the snaphelper
snapinfo.connect_loop(loop)
# Run pipeline.
pipeline.set_state(Gst.State.PLAYING)
try:
loop.run()
except:
pass
# Clean up.
pipeline.set_state(Gst.State.NULL)
while GLib.MainContext.default().iteration(False):
pass
class SnapHelper:
def __init__(self, sysfs, prefix='img', oneshot=True, suffix='jpg'):
self.prefix = prefix
self.oneshot = oneshot
self.suffix = suffix
self.snap_it = oneshot
self.num = 0
self.scrapframes = SCRAP_FRAMES
self.sysfs = sysfs
def get_filename(self):
while True:
filename = self.prefix + str(self.num).zfill(4) + '.' + self.suffix
self.num = self.num + 1
if not os.path.exists(filename):
break
return filename
#def check_af(self):
#try:
# self.sysfs.seek(0)
# v = self.sysfs.read()
# if int(v) != 0x10:
# print('NO Focus')
#except:
# pass
# def refocus(self):
# try:#
# self.sysfs.write('1')
# self.sysfs.flush()
# except:
# pass
def save_frame(self):
# We always want to throw away the initial frames to let the
# camera stabilize. This seemed empirically to be the right number
# when running on desktop.
if self.scrapframes > 0:
self.scrapframes = self.scrapframes - 1
return False
if self.snap_it:
self.snap_it = False
retval = True
else:
retval = False
if self.oneshot:
self.loop.quit()
return retval
def connect_loop(self, loop):
self.loop = loop
def take_picture(snap):
start_time = int(round(time.time()))
run_pipeline(snap)
print(time.time()- start_time)
def main():
button = GPIO(138, "in")
last_state = False
with open(AF_SYSFS_NODE, 'w+') as sysfs:
snap = SnapHelper(sysfs, 'test', 'oneshot', 'jpg')
sysfs.write('2')
while 1:
button_state = button.read()
if(button_state==True and last_state == False):
snap = SnapHelper(sysfs, 'test', 'oneshot', 'jpg')
take_picture(snap)
last_state = button_state
if __name__== "__main__":
main()
sys.exit()
Output is what i expect, but it is slow.

I switched to a USB-webcam and used the pygame library instead.

Related

multiple processing in dronekit not working

i am trying to make a code about a drone flying to multiple waypoint and the drone can't continue to the next waypoint when i not showing the red color on camera.
because the camera cv2 and the drone runs at the same time, my code runs very laggy, so i tried using multiprocessing method and modify my code. when i trying to run my new code, my multi processing doesn't work and it keeps skipping almost of my code and straight to RTL mode.
from inspect import ArgInfo
from dronekit import connect, VehicleMode, LocationGlobalRelative
from pymavlink import mavutil
from numpy import loadtxt, array
from time import sleep
import sys
import cv2
import numpy as np
import multiprocessing
cap = cv2.VideoCapture(0)
hsv_a = np.array([198, 255, 255])
hsv_b = np.array([158, 68, 137])
treshold = 150
lat = [-35.3629722, -35.3629064, -35.3634361, -35.3638474]
lon = [149.1649709, 149.1655721, 149.1657331, 149.1639733]
#vehicle = connect('udp:127.0.0.1:14551',wait_ready=True)
vehicle = connect('udp:127.0.0.1:14551',wait_ready=True)
def arm_and_takeoff(aTargetAltitude): #fungsi arming dan takeoff
print("Basic pre-arm checks")
# Don't let the user try to arm until autopilot is ready
while not(vehicle.is_armable):
print(" Waiting for vehicle to initialise...")
sleep(1)
print("Arming motors")
# Copter should arm in GUIDED mode
vehicle.mode = VehicleMode("GUIDED")
vehicle.armed = True
while not(vehicle.armed):
print(" Waiting for arming...")
sleep(1)
print("Taking off!")
vehicle.simple_takeoff(aTargetAltitude)
while True:
print(" Altitude: ", vehicle.location.global_relative_frame.alt)
#Break and return from function just below target altitude.
if (vehicle.location.global_relative_frame.alt>=aTargetAltitude*0.95):
print("Reached target altitude")
break
sleep(1)
def dist(a,z): #a=awal z=akhir
d_lat= (a.lat-z.lat)**2
d_long= (a.lon-z.lon)**2
jarak = (d_lat+d_long)**0.5
return jarak
def gerak_drone():
for i in range(0,len(lat)):
print(i)
wp = LocationGlobalRelative(lat[i],lon[i],2)
vehicle.simple_goto(wp)
sleep(1)
while (dist(vehicle.location.global_relative_frame,wp)>=0.0001):
print (str(round(dist(vehicle.location.global_relative_frame,wp)*100000,2)))
while True:
_,frame = cap.read()
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
mask = cv2.inRange(hsv, hsv_b, hsv_a)
cv2.imshow("warna", mask)
cv2.imshow("hitamPutih", gray)
cv2.imshow("apa", frame)
print(cv2.countNonZero(mask))
if cv2.waitKey(500) == 27 or cv2.countNonZero(mask) > treshold :
break
if __name__ == "_main_":
altitude = 2
lat_distance = 1
lon_distance = 1
p1 = multiprocessing.Process(target=arm_and_takeoff, args=(altitude))
p2 = multiprocessing.Process(target=dist, args=(lat_distance, lon_distance))
p3 = multiprocessing.Process(target=gerak_drone)
p1.start()
p2.start()
p3.start()
p1.join()
p2.join()
p3.join()
print("Coming back")
vehicle.mode = VehicleMode("RTL")
sleep(20)
vehicle.mode = VehicleMode("LAND")
Here is my terminal result

can i use OR-tools for TSP with partial distance matrix (for a huge set of nodes)?

i'm trying to solve tsp with OR-tools for a problem of something like 80,000 nodes, the problem is, I need a huge distance matrix that takes to much memory ,so its infeasible and i don't get a solution.
so:
is there an option to work with partial distance matrix in or-tools?
if not is there a way to improve my code?
is there another external solver that can work for this task in python?
import math
from collections import namedtuple
import random
import time
from collections import namedtuple
from sklearn.metrics.pairwise import euclidean_distances
import numpy as np
import numba
from scipy.spatial import distance_matrix
from sklearn.metrics.pairwise import euclidean_distances
from math import sqrt
Point = namedtuple("Point", ['x', 'y'])
def solve_it(input_data):
# Modify this code to run your optimization algorithm
global POINTS
# parse the input
lines = input_data.split('\n')
nodeCount = int(lines[0])
points = []
for i in range(1, nodeCount+1):
line = lines[i]
parts = line.split()
points.append(Point(float(parts[0]), float(parts[1])))
#2.routing with or tools
def dist_matrix(nodeCount,points):
data=[]
for k in range(len(points)):
data.append([int(points[k].x),int(points[k].y)])
D=euclidean_distances(data, data)
return D
def create_data_model(D):
"""Stores the data for the problem."""
data = {}
data['distance_matrix'] = D # yapf: disable
data['num_vehicles'] = 1
data['depot'] = 0
return data
def print_solution(manager, routing, solution):
index = routing.Start(0)
plan_output = []#Route for vehicle 0:\n'
route_distance = 0
while not routing.IsEnd(index):
plan_output.append(manager.IndexToNode(index))
index = solution.Value(routing.NextVar(index))
return plan_output
def or_main(nodeCount,points):
from ortools.constraint_solver import routing_enums_pb2
from ortools.constraint_solver import pywrapcp
"""Entry point of the program."""
# Instantiate the data problem.
global sol
D=dist_matrix(nodeCount,points)
data = create_data_model(D)
# Create the routing index manager.
manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']),
data['num_vehicles'], data['depot'])
# Create Routing Model.
routing = pywrapcp.RoutingModel(manager)
def distance_callback(from_index, to_index):
"""Returns the distance between the two nodes."""
# Convert from routing variable Index to distance matrix NodeIndex.
from_node = manager.IndexToNode(from_index)
to_node = manager.IndexToNode(to_index)
return data['distance_matrix'][from_node][to_node]
transit_callback_index = routing.RegisterTransitCallback(distance_callback)
# Define cost of each arc.
routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)
# Setting first solution heuristic.
search_parameters = pywrapcp.DefaultRoutingSearchParameters()
search_parameters.local_search_metaheuristic = (
routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)
k = 100
if nodeCount <= 100:
k = 30
elif 100 <= nodeCount <= 1000:
k = 300
elif nodeCount > 1000:
k = 17000
search_parameters.time_limit.seconds =k
search_parameters.log_search = True
# Solve the problem.
solution = routing.SolveWithParameters(search_parameters)
# #print solution on console.
if solution:
sol=print_solution(manager, routing, solution)
return sol
######################################################################
solution=or_main(nodeCount,points)
# calculate the length of the tour
obj = length(points[solution[-1]], points[solution[0]])
for index in range(0, nodeCount-1):
obj += length(points[solution[index]], points[solution[index+1]])
# prepare the solution in the specified output format
output_data = '%.2f' % obj + ' ' + str(0) + '\n'
output_data += ' '.join(map(str, solution))
return output_data
if __name__ == '__main__':
import sys
if len(sys.argv) > 1:
file_location = sys.argv[1].strip()
with open(file_location, 'r') as input_data_file:
input_data = input_data_file.read()
#print(solve_it(input_data))
else:
print('This test requires an input file. Please select one from the data directory. (i.e. python solver.py ./data/tsp_51_1)')

how to make cross hair mouse tracker on a PlotWidget() promoted in designer-qt5

I am trying to make a cross hair on my pyqtgraph interactive plots, which are embedded in a PyQt5 GUI thanks to the designer-qt5. I found a working
code in the pyqtgraph "examples". A simplified WORKING example is posted below. Now I want the same, but the problem seems to be that I promoted a
QGraphicsView() to a pg.PlotWidget in the designer, instead of pg.GraphicsWindow()? The Code does not work for me because my p1 is "pyqtgraph.widgets.PlotWidget.PlotWidget object" while in the example p1 is
"pyqtgraph.graphicsItems.PlotItem.PlotItem.PlotItem object".
So what should I do to make this example work for me?
import numpy as np
import pyqtgraph as pg
from pyqtgraph.Qt import QtGui, QtCore
from pyqtgraph.Point import Point
pg.setConfigOption('background', '#ffffff')
pg.setConfigOption('foreground', 'k')
pg.setConfigOptions(antialias=True)
app = QtGui.QApplication([])
win = pg.GraphicsWindow()
win.setWindowTitle('pyqtgraph example: crosshair')
label = pg.LabelItem(justify='right')
win.addItem(label)
p1 = win.addPlot(row=1, col=0)
p1.setAutoVisible(y=True)
#create numpy arrays
#make the numbers large to show that the xrange shows data from 10000 to all the way 0
data1 = 10000 + 15000 * pg.gaussianFilter(np.random.random(size=10000), 10) + 3000 * np.random.random(size=10000)
p1.plot(data1, pen="r")
#cross hair
vLine = pg.InfiniteLine(angle=90, movable=False)
hLine = pg.InfiniteLine(angle=0, movable=False)
p1.addItem(vLine, ignoreBounds=True)
p1.addItem(hLine, ignoreBounds=True)
vb = p1.vb
print(p1)
print(vb)
def mouseMoved(evt):
pos = evt[0] ## using signal proxy turns original arguments into a tuple
if p1.sceneBoundingRect().contains(pos):
mousePoint = vb.mapSceneToView(pos)
index = int(mousePoint.x())
if index > 0 and index < len(data1):
label.setText("<span style='font-size: 12pt'>x=%0.1f, <span style='color: green'>y2=%0.1f</span>" % (mousePoint.x(), data1[index]))
vLine.setPos(mousePoint.x())
hLine.setPos(mousePoint.y())
proxy = pg.SignalProxy(p1.scene().sigMouseMoved, rateLimit=60, slot=mouseMoved)
#p1.scene().sigMouseMoved.connect(mouseMoved)
## Start Qt event loop unless running in interactive mode or using pyside.
if __name__ == '__main__':
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()
I am very sorry for the noise!!! I fix it myself!
The important part was:
plot_wg.proxy = proxy
Very simple...
Below is the function, which should work for any PlotWidget:
def cross_hair(self, plot_wg, log=False ):
global fit
################### TETS cross hair ############3
vLine = pg.InfiniteLine(angle=90, movable=False)#, pos=0)
hLine = pg.InfiniteLine(angle=0, movable=False)#, pos=2450000)
plot_wg.addItem(vLine, ignoreBounds=True)
plot_wg.addItem(hLine, ignoreBounds=True)
vb = plot_wg.getViewBox()
label = pg.TextItem()
plot_wg.addItem(label)
def mouseMoved(evt):
pos = evt[0] ## using signal proxy turns original arguments into a tuple
if plot_wg.sceneBoundingRect().contains(pos):
mousePoint = vb.mapSceneToView(pos)
if log == True:
label.setText("x=%0.3f, y1=%0.3f"%(10**mousePoint.x(), mousePoint.y()))
else:
label.setText("x=%0.3f, y1=%0.3f"%(mousePoint.x(), mousePoint.y()))
vLine.setPos(mousePoint.x())
hLine.setPos(mousePoint.y())
#print(mousePoint.x(),mousePoint.y())
plot_wg.getViewBox().setAutoVisible(y=True)
proxy = pg.SignalProxy(plot_wg.scene().sigMouseMoved, rateLimit=60, slot=mouseMoved)
plot_wg.proxy = proxy
proxy = pg.SignalProxy(plot_wg.scene().sigMouseMoved, rateLimit=60, slot=mouseMoved)
plot_wg.proxy = proxy
################### TETS cross hair ############3

PyGtk Serialization

I am currently working on a Note taking app in pyGtk and have set up a TextView where a user can type and add text tags for Bold Underline and Italics.
However, when it comes to saving the formatted text I cannot figure out how to do so.
I am trying to save in Gtk's native tagset format however after using
tag_format = TextBuffer.register_serialize_tagset()
content = TextBuffer.serialize(self, tag_format, start,end)
I cannot write this to a file with
open(filename, 'w').write(content)
because I get an error which states that it cannot write in bytes and needs a string instead.
I am currently working on a Note taking app in pyGtk and have set up a TextView where a user can type and add text tags for Bold Underline and Italics.
However, when it comes to saving the formatted text I cannot figure out how to do so.
I am trying to save in Gtk's native tagset format however after using
tag_format = TextBuffer.register_serialize_tagset()
content = TextBuffer.serialize(self, tag_format, start,end)
I cannot write this to a file with
open(filename, 'w').write(content)
because I get an error which states that it cannot write in bytes and needs a string instead.
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Pango
I am currently working on a Note taking app in pyGtk and have set up a TextView where a user can type and add text tags for Bold Underline and Italics.
However, when it comes to saving the formatted text I cannot figure out how to do so.
I am trying to save in Gtk's native tagset format however after using
tag_format = TextBuffer.register_serialize_tagset()
content = TextBuffer.serialize(self, tag_format, start,end)
I cannot write this to a file with
open(filename, 'w').write(content)
because I get an error which states that it cannot write in bytes and needs a string instead.
File "example.py", line 87, in save_file
open(filename, 'w').write(content)
TypeError: write() argument must be str, not bytes
Here is sample code you can run and test by typing and then saving
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Pango
class MainWindow(Gtk.ApplicationWindow):
def __init__(self):
Gtk.Window.__init__(self, title = "TwoNote")
self.grid = Gtk.Grid()
self.toolbar = Gtk.Toolbar()
self.grid.add(self.toolbar)
#buttons for toolbar
self.button_bold = Gtk.ToggleToolButton()
self.button_italic = Gtk.ToggleToolButton()
self.button_underline = Gtk.ToggleToolButton()
self.button_save = Gtk.ToolButton()
self.button_open = Gtk.ToolButton()
self.mytext = TextSet(self.button_bold, self.button_italic, self.button_underline)
self.button_bold.set_icon_name("format-text-bold-symbolic")
self.toolbar.insert(self.button_bold, 0)
self.button_italic.set_icon_name("format-text-italic-symbolic")
self.toolbar.insert(self.button_italic, 1)
self.button_underline.set_icon_name("format-text-underline-symbolic")
self.toolbar.insert(self.button_underline, 2)
self.toolbar.insert(self.button_save, 3)
self.toolbar.insert(self.button_open, 4)
self.button_open.set_icon_name("document-open-data")
self.button_save.set_icon_name("document-save")
self.button_save.connect("clicked", self.save_file)
self.button_open.connect("clicked", self.open_file)
self.button_bold.connect("toggled", self.mytext.on_button_clicked, "Bold", self.button_italic, self.button_underline)
self.button_italic.connect("toggled", self.mytext.on_button_clicked, "Italic", self.button_bold, self.button_underline)
self.button_underline.connect("toggled", self.mytext.on_button_clicked, "Underline", self.button_bold, self.button_italic)
self.grid.attach_next_to(self.mytext, self.toolbar, Gtk.PositionType.BOTTOM, 10,30)
self.add(self.grid)
filename = "Untitled"
def open_file(self, widget):
open_dialog = Gtk.FileChooserDialog("Open an existing file", self, Gtk.FileChooserAction.OPEN,(Gtk.STOCK_CANCEL,Gtk.ResponseType.CANCEL,Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
open_response = open_dialog.run()
if open_response == Gtk.ResponseType.OK:
filename = open_dialog.get_filename()
text = open(filename).read()
self.mytext.get_buffer().set_text(text)
open_dialog.destroy()
elif open_response == Gtk.ResponseType.CANCEL:
print("Cancel clicked")
open_dialog.destroy()
def save_file(self, widget):
savechooser = Gtk.FileChooserDialog('Save File', self, Gtk.FileChooserAction.SAVE, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_SAVE, Gtk.ResponseType.OK))
allfilter = Gtk.FileFilter()
allfilter.set_name('All files')
allfilter.add_pattern('*')
savechooser.add_filter(allfilter)
txtFilter = Gtk.FileFilter()
txtFilter.set_name('Text file')
txtFilter.add_pattern('*.txt')
savechooser.add_filter(txtFilter)
response = savechooser.run()
if response == Gtk.ResponseType.OK:
filename = savechooser.get_filename()
print(filename, 'selected.')
buf = self.mytext.get_buffer()
start, end = buf.get_bounds()
tag_format = buf.register_serialize_tagset()
content = buf.serialize(buf, tag_format, start, end)
try:
open(filename, 'w').write(content)
except SomeError as e:
print('Could not save %s: %s' % (filename, err))
savechooser.destroy()
elif response == Gtk.ResponseType.CANCEL:
print('Closed, file not saved.')
savechooser.destroy()
class TextSet(Gtk.TextView):
def __init__(self, buttonBold, buttonItalic, buttonUnderline, interval = 1 ):
# Textview Setup
Gtk.TextView.__init__(self)
self.set_vexpand(True)
self.set_indent(10)
self.set_top_margin(90)
self.set_left_margin(20)
self.set_right_margin(20)
self.set_wrap_mode(Gtk.WrapMode.CHAR)
self.tb = TextBuffer()
self.set_buffer(self.tb)
# Thread setup
self.button_bold = buttonBold
self.button_italic = buttonItalic
self.button_underline = buttonUnderline
def on_button_clicked(self, widget, tagname, widget1, widget2):
state = widget.get_active()
name = widget.get_icon_name()
bounds = self.tb.get_selection_bounds()
self.tagname = tagname
if(state):
widget1.set_active(False)
widget2.set_active(False)
#highlighting
if(len(bounds) != 0):
start, end = bounds
myIter = self.tb.get_iter_at_mark(self.tb.get_insert())
myTags = myIter.get_tags()
if(myTags == [] and state == True):
self.tb.apply_tag_by_name(tagname, start, end)
elif(myTags != [] and state == True):
self.tb.remove_all_tags(start, end)
self.tb.apply_tag_by_name(tagname, start, end)
else:
for i in range(len(myTags)):
if(myTags[i].props.name == tagname):
self.tb.remove_tag_by_name(tagname,start,end)
myTags = []
self.tb.markup(widget, tagname)
def mouse_clicked(self, window, event):
self.button_bold.set_active(False)
self.button_italic.set_active(False)
self.button_underline.set_active(False)
class TextBuffer(Gtk.TextBuffer):
def __init__(self):
Gtk.TextBuffer.__init__(self)
self.connect_after('insert-text', self.text_inserted)
# A list to hold our active tags
self.taglist_on = []
# Our Bold tag.
self.tag_bold = self.create_tag("Bold", weight=Pango.Weight.BOLD)
self.tag_none = self.create_tag("None", weight=Pango.Weight.NORMAL)
self.tag_italic = self.create_tag("Italic", style=Pango.Style.ITALIC)
self.tag_underline = self.create_tag("Underline", underline=Pango.Underline.SINGLE)
def get_iter_position(self):
return self.get_iter_at_mark(self.get_insert())
def markup(self, widget, tagname):
self.tag_name = tagname
self.check = True
''' add "bold" to our active tags list '''
if(widget.get_active() == True):
if(self.tag_name == 'Bold'):
if 'Bold' in self.taglist_on:
del self.taglist_on[self.taglist_on.index('Bold')]
else:
self.taglist_on.append('Bold')
if(self.tag_name == 'Italic'):
if 'Italic' in self.taglist_on:
del self.taglist_on[self.taglist_on.index('Italic')]
else:
self.taglist_on.append('Italic')
if(self.tag_name == 'Underline'):
if 'Underline' in self.taglist_on:
del self.taglist_on[self.taglist_on.index('Underline')]
else:
self.taglist_on.append('Underline')
else:
self.check = False
def text_inserted(self, buffer, iter, text, length):
# A text was inserted in the buffer. If there are ny tags in self.tags_on, apply them
#if self.taglist_None or self.taglist_Italic or self.taglist_Underline or self.taglist_Bold:
if self.taglist_on:
# This sets the iter back N characters
iter.backward_chars(length)
# And this applies tag from iter to end of buffer
if(self.check == True):
if(self.tag_name == 'Italic'):
self.apply_tag_by_name('Italic', self.get_iter_position(), iter)
if(self.tag_name == 'Bold'):
self.apply_tag_by_name('Bold', self.get_iter_position(), iter)
if(self.tag_name == 'Underline'):
self.apply_tag_by_name('Underline', self.get_iter_position(), iter)
else:
self.remove_all_tags(self.get_iter_position(), iter)
win = MainWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
I figured it out rather than using
open(filename, 'w').write(content)
to save the content I imported GLib and used
GLib.file_set_contents(filename, content)

object oriented architecture and pickling problems and multiprocessing in Tkinter/matplotlib GUI

I know that several questions have been created with people asking about non-responsive GUIs and the ultimate answer is that Tkinter is not thread safe. However, it is my understanding that queues can be utilized to overcome this problem. Therefore, I have been looking into using the multiprocessing module with queues such that my code can be utilized on hyperthreaded and multicore systems.
What I would like to do is to try and do a very complex least squares fitting of multiple imported spectra in different tabs whenever a button is pressed.
The problem is that my code is still hanging up on the long process that I initialize by a button in my GUI. I have knocked the code down to something that still may run and has most of the objects of my original program, yet still suffers from the problem of not being responsive.
I believe my problem is in the multiprocessing portion of my program.
Therefore my question is regarding the multiprocessing portion of the code and if there is a better way to organize the process_spectra() function shown here:
def process_spectra(self):
process_list = []
queue = mp.Queue()
for tab in self.tab_list:
process_list.append(mp.Process(target=Deconvolution(tab).deconvolute(), args=(queue,)))
process_list[-1].start()
process_list[-1].join()
return
At the moment it appears that this is not actually making the deconvolution process into a different thread. I would like the process_spectra function to process all of the spectra with the deconvolution function simultaneously while still being able to interact with and see the changes in the spectra and GUI.
Here is the full code which can be run as a .py file directly to reproduce my problem:
from Tkinter import *
import Tkinter
import tkFileDialog
import matplotlib
from matplotlib import *
matplotlib.use('TKAgg')
from matplotlib import pyplot, figure, backends
import numpy as np
import lmfit
import multiprocessing as mp
# lots of different peaks can appear
class peak:
def __init__(self, n, m):
self.n = n
self.m = m
def location(self, i):
location = i*self.m/self.n
return location
def NM(self):
return str(self.n) + str(self.m)
# The main function that is given by the user has X and Y data and peak data
class Spectra:
def __init__(self, spectra_name, X, Y):
self.spectra_name = spectra_name
self.X = X
self.Y = Y
self.Y_model = Y*0
self.Y_background_model = Y*0
self.Y_without_background_model = Y*0
self.dYdX = np.diff(self.Y)/np.diff(self.X)
self.peak_list = self.initialize_peaks(3, 60)
self.params = lmfit.Parameters()
def peak_amplitude_dictionary(self):
peak_amplitude_dict = {}
for peak in self.peak_list:
peak_amplitude_dict[peak] = self.params['P' + peak.NM() + '_1_amp'].value
return peak_amplitude_dict
def peak_percentage_dictionary(self):
peak_percentage_dict = {}
for peak in self.peak_list:
peak_percentage_dict[peak] = self.peak_amplitude_dictionary()[peak]/np.sum(self.peak_amplitude_dictionary().values())
return peak_percentage_dict
# Function to create all of the peaks and store them in a list
def initialize_peaks(self, lowestNM, highestNM):
peaks=[]
for n in range(0,highestNM+1):
for m in range(0,highestNM+1):
if(n<lowestNM and m<lowestNM): break
elif(n<m): break
else: peaks.append(peak(n,m))
return peaks
# This is just a whole bunch of GUI stuff
class Spectra_Tab(Frame):
def __init__(self, parent, spectra):
self.spectra = spectra
self.parent = parent
Frame.__init__(self, parent)
self.tab_name = spectra.spectra_name
self.canvas_frame = Frame(self, bd=3, bg= 'WHITE', relief=SUNKEN)
self.canvas_frame.pack(side=LEFT, fill=BOTH, padx=0, pady=0, expand=1)
self.results_frame = Frame(self, bd=3, bg= 'WHITE', relief=SUNKEN, width=600)
self.results_frame.pack(side=RIGHT, fill=BOTH, padx=0, pady=0, expand=1)
self.top_canvas_frame = Frame(self.canvas_frame, bd=0, bg= 'WHITE', relief=SUNKEN)
self.top_canvas_frame.pack(side=TOP, fill=BOTH, padx=0, pady=0, expand=1)
self.original_frame = Frame(self.top_canvas_frame, bd=1, relief=SUNKEN)
self.original_frame.pack(side=LEFT, fill=BOTH, padx=0, pady=0, expand=1)
self.scrollbar = Scrollbar(self.results_frame)
self.scrollbar.pack(side=RIGHT, fill=BOTH,expand=1)
self.sidebar = Listbox(self.results_frame)
self.sidebar.pack(fill=BOTH, expand=1)
self.sidebar.config(yscrollcommand=self.scrollbar.set)
self.scrollbar.config(command=self.sidebar.yview)
self.original_fig = figure.Figure()
self.original_plot = self.original_fig.add_subplot(111)
init_values = np.zeros(len(self.spectra.Y))
self.original_line, = self.original_plot.plot(self.spectra.X, self.spectra.Y, 'r-')
self.original_background_line, = self.original_plot.plot(self.spectra.X, init_values, 'k-', animated=True)
self.original_canvas = backends.backend_tkagg.FigureCanvasTkAgg(self.original_fig, master=self.original_frame)
self.original_canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)
self.original_canvas._tkcanvas.pack(side=TOP, fill=BOTH, expand=1)
self.original_canvas.show()
self.original_canvas.draw()
self.original_canvas_BBox = self.original_plot.figure.canvas.copy_from_bbox(self.original_plot.bbox)
ax1 = self.original_plot.figure.axes[0]
ax1.set_xlim(self.spectra.X.min(), self.spectra.X.max())
ax1.set_ylim(0, self.spectra.Y.max() + .05*self.spectra.Y.max())
self.step=0
self.update()
# This just refreshes the GUI stuff everytime that the parameters are fit in the least squares method
def refreshFigure(self):
self.step=self.step+1
if(self.step==1):
self.original_canvas_BBox = self.original_plot.figure.canvas.copy_from_bbox(self.original_plot.bbox)
self.original_plot.figure.canvas.restore_region(self.original_canvas_BBox)
self.original_background_line.set_data(self.spectra.X, self.spectra.Y_background_model)
self.original_plot.draw_artist(self.original_line)
self.original_plot.draw_artist(self.original_background_line)
self.original_plot.figure.canvas.blit(self.original_plot.bbox)
# show percentage of peaks on the side bar
self.sidebar.delete(0, Tkinter.END)
peak_dict = self.spectra.peak_percentage_dictionary()
for peak in sorted(peak_dict.iterkeys()):
self.sidebar.insert(0, peak.NM() + ' ' + str(peak_dict[peak]) + '%' )
return
# just a tab bar
class TabBar(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.tabs = {}
self.buttons = {}
self.current_tab = None
def show(self):
self.pack(side=BOTTOM, expand=0, fill=X)
def add(self, tab):
tab.pack_forget()
self.tabs[tab.tab_name] = tab
b = Button(self, text=tab.tab_name, relief=RAISED, command=(lambda name=tab.tab_name: self.switch_tab(name)))
b.pack(side=LEFT)
self.buttons[tab.tab_name] = b
def switch_tab(self, name):
if self.current_tab:
self.buttons[self.current_tab].config(relief=RAISED)
self.tabs[self.current_tab].pack_forget()
self.tabs[name].pack(side=BOTTOM)
self.current_tab = name
self.buttons[name].config(relief=SUNKEN)
class Deconvolution:
def __init__(self, spectra_tab):
self.spectra_tab = spectra_tab
self.spectra = spectra_tab.spectra
self.model = [0 for x in self.spectra.X]
self.model_without_background = [0 for x in self.spectra.X]
self.residual_array = [0 for x in self.spectra.X]
# Amplitudes for backgrounds
self.pi_plasmon_amp = np.interp(4.3, self.spectra.X, self.spectra.Y)
self.graphite_amp = np.interp(5, self.spectra.X, self.spectra.Y)
self.spectra.params.add('PPAmp', value=self.pi_plasmon_amp, vary=True, min=0.0, max=None)
self.spectra.params.add('PPCenter', value=4.3, vary=True)
self.spectra.params.add('PPFWHM', value=.4, vary=True)
self.spectra.params.add('GLAmp', value=self.graphite_amp, vary=True, min=0.0, max=None)
self.spectra.params.add('GLCenter', value=5, vary=True)
self.spectra.params.add('GLFWHM', value=.4, vary=True)
self.background_model = self.pseudoVoigt(self.spectra.X, self.spectra.params['PPAmp'].value, self.spectra.params['PPCenter'].value, self.spectra.params['PPFWHM'].value, 1)+\
self.pseudoVoigt(self.spectra.X, self.spectra.params['GLAmp'].value, self.spectra.params['GLCenter'].value, self.spectra.params['GLFWHM'].value, 1)
for peak in self.spectra.peak_list:
for i in range(1,4):
param_prefix = 'P' + peak.NM() + '_' + str(i)
center = peak.location(i)
amp = np.interp(center, self.spectra.X, self.spectra.Y - self.background_model)
width = 0.02
self.spectra.params.add(param_prefix + '_amp', value = 0.8*amp, vary=False, min=0.0, max=None)
self.spectra.params.add(param_prefix + '_center', value = center, vary=False, min=0.0, max=None)
self.spectra.params.add(param_prefix + '_width', value = width, vary=False, min=0.0, max=None)
self.model_without_background += self.pseudoVoigt(self.spectra.X, self.spectra.params[param_prefix + '_amp'].value, self.spectra.params[param_prefix + '_center'].value, self.spectra.params[param_prefix + '_width'].value, 1)
def deconvolute(self):
for State in range(0,3):
# Make each voigt profile for each tube
for peak in self.spectra.peak_list:
for i in range(1,4):
param_prefix = 'P' + peak.NM() + '_' + str(i)
if(State==1):
self.spectra.params[param_prefix + '_amp'].vary = True
if(State==2):
self.spectra.params[param_prefix + '_width'].vary = True
result = lmfit.Minimizer(self.residual, self.spectra.params, fcn_args=(State,))
result.prepare_fit()
result.leastsq()#lbfgsb()
def residual(self, params, State):
self.model = self.background_model
if(State>0):
self.model += self.model_without_background
for x in range(0, len(self.spectra.X)):
if(self.background_model[x]>self.spectra.Y[x]):
self.residual_array[x] = -999999.-9999.*(self.spectra.Y[x]-self.background_model[x])
else:
self.residual_array[x] = self.spectra.Y[x]-self.model[x]
self.spectra.Y_model = self.model
self.spectra.Y_background_model = self.background_model
self.spectra.Y_without_background_model = self.model_without_background
self.spectra_tab.refreshFigure()
return self.residual_array
def pseudoVoigt(self, x, amp, center, width, shapeFactor):
LorentzPortion = (width**2/((x-center)**2+width**2))
GaussianPortion = 1/(np.sqrt(2*np.pi*width**2))*np.e**(-(x-center)**2/(2*width**2))
try:
Voigt = amp*(shapeFactor*LorentzPortion+(1-shapeFactor)*GaussianPortion)
except ZeroDivisionError:
width = width+0.01
LorentzPortion = (width**2/((x-center)**2+width**2))
GaussianPortion = 1/(np.sqrt(2*np.pi*width**2))*np.e**(-(x-center)**2/(2*width**2))
Voigt = amp*(shapeFactor*LorentzPortion+(1-shapeFactor)*GaussianPortion)
return Voigt
class MainWindow(Tk):
def __init__(self, parent):
Tk.__init__(self, parent)
self.parent = parent
self.wm_state('zoomed')
self.spectra_list = []
self.tab_list = []
self.button_frame = Frame(self, bd=3, relief=SUNKEN)
self.button_frame.pack(side=TOP, fill=BOTH)
self.tab_frame = Frame(self, bd=3, relief=SUNKEN)
self.tab_frame.pack(side=BOTTOM, fill=BOTH, expand=1)
open_spectra_button = Button(self.button_frame, text='open spectra', command=self.open_spectra)
open_spectra_button.pack(side=LEFT, fill=Y)
process_spectra_button = Button(self.button_frame, text='process spectra', command=self.process_spectra)
process_spectra_button.pack(side=LEFT, fill=Y)
self.tab_bar = TabBar(self.tab_frame)
self.tab_bar.show()
self.resizable(True,False)
self.update()
def open_spectra(self):
# This will prompt user for file input later, but here is an example
file_name_list = ['spectra_1', 'spectra_2']
for file_name in file_name_list:
# Just make up functions that may be imported
X_values = np.arange(1240.0/1350.0, 1240./200., 0.01)
if(file_name=='spectra_1'):
Y_values = np.array(np.e**.2*X_values + np.sin(10*X_values)+np.cos(4*X_values))
if(file_name=='spectra_2'):
Y_values = np.array(np.e**.2*X_values + np.sin(10*X_values)+np.cos(3*X_values)+.3*np.cos(.5*X_values))
self.spectra_list.append(Spectra(file_name, X_values, Y_values))
self.tab_list.append(Spectra_Tab(self.tab_frame, self.spectra_list[-1]))
self.tab_bar.add(self.tab_list[-1])
self.tab_bar.switch_tab(self.spectra_list[0].spectra_name)
self.tab_bar.show()
return
def process_spectra(self):
process_list = []
queue = mp.Queue()
for tab in self.tab_list:
process_list.append(mp.Process(target=Deconvolution(tab).deconvolute(), args=(queue,)))
process_list[-1].start()
process_list[-1].join()
return
if __name__ == "__main__":
root = MainWindow(None)
root.mainloop()
EDIT:
I am editing this question because I realized that my question did not regard the real problem. I think the code I have supplied has problems with having a Tkinter Frame passed as a parameter to something that needs to be pickled, ? and it can't because it's not thread safe?? It gives a pickle error that points to Tkinter in some way.
However, I am not sure how to reorganize this code such that the only part that is pickled is the data part since the threads or processes must access the Tkinter frames in order to update them via refreshFigure().
Does anyone have any ideas regarding how to do this? I have researched it but everyone's examples are usually simple with only one figure or that only refreshes after the process is completed.
The segment target=Deconvolution(tab).deconvolute() will actually be evaluated instead of passed to a subprocess. You could replace this with a wrapper function
def mp_deconvolute(tab):
return Deconvolution(tab).deconvolute()
I'm not sure if your queue is actually be used at all but I believe that would be more appropriate for a worker Pool scenario.
Edit:
Oh, and you would call it like so
process_list.append(mp.Process(target=mp_deconvolute, args=(tab)))
Edit again:
You could just define that as a lambda function too unless you to to add more complexity
mp_deconv = lambda x: Deconvolution(tab).deconvolute()
process_list.append(mp.Process(target=mp_deconv, args=(tab)))