How to reduce latency in a PyQT Display? - multithreading

I am working on a program that takes in high-speed CanBus Data and displays it to a speedometer-style display using PYQT (A digital Dash Board Display). I have run into the common problem of the speedometer display having some latency and I have not figured out a way to solve it.
The code below is split into two parts, the init is just setting up the display with the AnalogGaugeWidget being the Speedometer widget. The sorting function is a while loop that sends out a request for the CanBus data and decodes it based on its ID. I am only trying to get the RPM code to work for now, and then work my way to the others.
The code works fast whenever the "self.widget.updateVlue(self.RPM)" code is taken out, but when it is put in, there is roughtly a 1-second latency in the while loop.
If anyone knows how I can help reduce this latency either through better threading or a different code structure I'm all ears. Also if you need the "Speedometer" code let me know and I would be more than happy to provide it.
Thanks.
The important part of the code:
from PyQt5 import QtCore, QtGui, QtWidgets
from threading import Thread
from Speedometer import *
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.resize(1000, 600)
self.widget = AnalogGaugeWidget(self)
self.setCentralWidget(self.widget)
t1 = Thread(target=self.sorting)
t1.start()
def sorting(self):
while 1:
for i in range(1, 1000):
# Example of the data received for RPM
data = "Timestamp: 1647910233.332248 ID: 0140 S Rx DL: 8 f9 93 02 00 00 ff 02 02 Channel: can0"
Timestamp = float(data.split(" ")[1])
ID = data.split(" ")[10]
B0 = data.split(" ")[36]
B1 = data.split(" ")[37]
B2 = data.split(" ")[38]
B3 = data.split(" ")[39]
B4 = data.split(" ")[40]
B5 = data.split(" ")[41]
B6 = data.split(" ")[42]
B7 = data.split(" ")[43]
if ID == '0140':
rpm2 = int((bin(int(B3, base=16))[2:][-5:]), 2)
rpm1 = (int(B2, 16))
self.RPM = (rpm2 * 256 + rpm1)
self.widget.updateValue(self.RPM)
This is the full code that only works when plugged into a CanBus module (To give an idea of the size and complexity of the while loop).
global bitrate
bitrate = 500000
global can_interface
can_interface = "can0"
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.resize(1000, 600)
self.widget = AnalogGaugeWidget(self)
self.setCentralWidget(self.widget)
t1 = Thread(target=self.sorting)
t1.start()
def sorting(self):
SaveData = 0
bus = can.interface.Bus(bustype='socketcan', channel=can_interface, bitrate=bitrate)
while 1:
for i in range(1, 1000):
msg = can.Message(arbitration_id=0x7DF, data=[2, 1, 0, 0, 0, 0, 0, 0], is_extended_id=False)
bus.send(msg)
data = str(bus.recv(timeout=2))
# Example of the data received for RPM
#data = "Timestamp: 1647910233.332248 ID: 0140 S Rx DL: 8 f9 93 02 00 00 ff 02 02 Channel: can0"
Timestamp = float(data.split(" ")[1])
ID = data.split(" ")[10]
B0 = data.split(" ")[36]
B1 = data.split(" ")[37]
B2 = data.split(" ")[38]
B3 = data.split(" ")[39]
B4 = data.split(" ")[40]
B5 = data.split(" ")[41]
B6 = data.split(" ")[42]
B7 = data.split(" ")[43]
# if SaveData == 1:
# with open('Can-Bus Data', 'a') as f:
# f.write('{} {} {} {} {} {} {} {} {} {}\n'.format(Timestamp, ID, B0, B1, B2, B3, B4, B5, B6, B7))
if ID == '0140':
rpm2 = int((bin(int(B3, base=16))[2:][-5:]), 2)
rpm1 = (int(B2, 16))
self.RPM = (rpm2 * 256 + rpm1)
self.widget.updateValue(self.RPM)
CP = int(B1, 16)
if CP >= 128 and CP <= 143:
CP = 1
# ("Clutch is engaged")
else:
CP = 0
# ("Clutch is disengaged")
# TP = round(((int(B0, 16) / 256) * 100), 1)
# TPD = round(((int(B4, 16) / 256) * 100), 1)
if SaveData == 1:
with open('ID 0140', 'a') as f:
f.write(
'{} {} {} {} {} {} {} {} {} {}\n'.format(Timestamp, ID, B0, B1, B2, B3, B4, B5, B6,
B7))
if ID == '0141':
EL = int(B3 + B2, 16)
if SaveData == 1:
with open('ID 0141', 'a') as f:
f.write(
'{} {} {} {} {} {} {} {} {} {}\n'.format(Timestamp, ID, B0, B1, B2, B3, B4, B5, B6,
B7))
if ID == '0360':
TO = int(B2, 16) - 40
TC = int(B3, 16) - 40
CC = int(B5, 16)
if CC == 16:
CC = 1
# ("Cruise Control Engaged")
else:
CC = 0
# ("CC off")
if SaveData == 1:
with open('ID 0360', 'a') as f:
f.write(
'{} {} {} {} {} {} {} {} {} {}\n'.format(Timestamp, ID, B0, B1, B2, B3, B4, B5, B6,
B7))
if ID == '0361':
GI = int(B0, 16)
if SaveData == 1:
with open('ID 0361', 'a') as f:
f.write(
'{} {} {} {} {} {} {} {} {} {}\n'.format(Timestamp, ID, B0, B1, B2, B3, B4, B5, B6,
B7))
if ID == '00d4':
FL = int(B1 + B0, 16) * 0.05747
FR = int(B3 + B2, 16) * 0.05747
BL = int(B5 + B4, 16) * 0.05747
BR = int(B7 + B6, 16) * 0.05747
Speed = round(((FL + FR + BL + BR) / 4), 1)
if SaveData == 1:
with open('ID 00d4', 'a') as f:
f.write(
'{} {} {} {} {} {} {} {} {} {}\n'.format(Timestamp, ID, B0, B1, B2, B3, B4, B5, B6,
B7))
if ID == '00d0':
SA = int(B1 + B0, 16)
if SA > 60000:
SA = SA - 65536
SA = round(SA * 0.1)
LatAcc = int(B6, 16) * 0.2
LonAcc = int(B7, 16) * 0.1
ComAcc = math.sqrt((LatAcc ** 2) + (LonAcc ** 2))
# Idle seems to give a value of 50 for lat and 25 for lon then it changes
if SaveData == 1:
with open('ID 00d0', 'a') as f:
f.write(
'{} {} {} {} {} {} {} {} {} {}\n'.format(Timestamp, ID, B0, B1, B2, B3, B4, B5, B6,
B7))
if ID == '00d1':
Speed1 = round((int(B1 + B0, 16) * 0.015694 * 4), 1)
BP = round(((int(B2, 16) / 77) * 100), 1)
if SaveData == 1:
with open('ID 00d1', 'a') as f:
f.write(
'{} {} {} {} {} {} {} {} {} {}\n'.format(Timestamp, ID, B0, B1, B2, B3, B4, B5, B6,
B7))
if ID == '00d3':
TRC = int(B0 + B1, 16)
if TRC == 2062:
TRC = ("Sport Mode Engaged")
# IDK maybe change the display
elif TRC == 10254:
TRC = ("Sport Mode Engaged and Traction Control Off")
elif TRC == 2006:
TRC = ("Drag Mode Engaged")
elif TRC == 8206:
TRC = ("Drift Mode Engaged")
elif TRC == 6:
TRC = ("Fully engaged")
if SaveData == 1:
with open('ID 00d3', 'a') as f:
f.write(
'{} {} {} {} {} {} {} {} {} {}\n'.format(Timestamp, ID, B0, B1, B2, B3, B4, B5, B6,
B7))
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
main = MainWindow()
main.show()
sys.exit(app.exec_())

Related

Electric Vehicle Routing Path Simulation Giving Wrong Output

My electric vehicle charging algorithm aims at returning the shortest path length by a charging drone. The drone will meet the electric vehicle at a rendezvous point and charge the vehicle. The vehicle selection is done based on the charging urgency of the vehicles. The total path length is calculated when all vehicles are charged based on their urgency. The pseudocode is:
EDF(List_Req)
SunchrgEV = List_Req
Pathlen = 0
Nchgreq = 0
while(SunchrgEV = 0):
U obtains the updated location of all ei element of SunchrgEV via message exchange
S'gcs = set of GCS element of Sgcs
Gr = min {Eucleadian distance between Loc(ei) and Loc(Gj)} //The closest GCS
ex = min [{Eucleadian distance between Loc(ei) and Loc(Gr)}/ResidDist(ei)] // most urgent EV
if SoC(U)<RqB2D(ex) // then U(the drone) itself needs charge and it reports its termination to the server
// the server dispatches another U(drone) to charge the remaining EVs (ei)
Gr = min {Eucleadian distance between Loc(U) and Loc(Gj)} //The closest GCS to U where U goes to full charge
end if
t = tcurrent
// Finding rendezvous point where ex and U meets
RdvLoc = FindRdvLoc(ex, Loc(ex), Loc(U),t)
if RdvLoc is out of service area of U then
Report2server(ex,'Outofservicearea')
continue
end if
Pathlen += Dist2(Loc(U),RdvLoc)
U sends RdvLoc to ex and flies to RdvLoc
if U reaches ex in ChgRng(U) then
{Pathlen += Charge(ex, RdvLoc)
Nchgreq ++
}
else
Report2server(ex, 'Outofservicearea')
endif
SunchrgEV -= ex
do
Update (Loc(U))
Gr = min {Eucleadian distance between Loc(U) and Loc(Gj)} //U returns to Gr
Pathlen += Dist2(Loc(U), Loc(Gr))
return Pathlen and Nchgreq
//Compute the expected location where U meets e on Map(e)
def FindRdvLoc(e,Le,Lu,t):
Compute X = (x,y) on Rte(e,t) so that {Dist(e,X)/Speed(e,t)} = {Dist(U, X-ChgRng(U))/Speed(U)}
return X
def Charge(ei, RdvLoc):
U starts to charge ei and follows Rte(ei,t)
eLoc = FindLoc(Map(ei), Loc(ei), ChgTime(ei), Speed(ei,t))
return DistM(Map(ei), RdvLoc, eLoc)
The code that I have written so far gives the same output regardless of the input. The code is:
import math
import sys
from typing import List, Any
class Location:
x = 0
y = 0
def __init__(self, x, y):
self.x = x
self.y = y
class Result:
path_len: int = 0
n_charge_request: int = 0
def __init__(self, path_len, n_charge_request):
self.path_len = path_len
self.n_charge_request = n_charge_request
def to_string(self):
return "path len : " + str(self.path_len) + ", n_charge_request : " + str(self.n_charge_request)
def print(self):
print(self.to_string())
#SGCs
class ChargingStation:
def __init__(self, location: Location, fuel):
self.location = location
self.fuel = fuel
#EVs(ex)
class Vehicle:
location = Location(0, 0)
fuel = 1
isNeedEmergencyFuel = False
per_fuel_distance_travel = 2
def __init__(self, id, location, fuel):
self.id = id
self.location = location
self.fuel = fuel
# Resid (U)
def residual_distance(self):
return self.fuel * self.per_fuel_distance_travel # assuming each watt or kw fuel will yield to 2 killos or milies
# RqB2D
def requested_amount_of_charge(self, nearest_charge_station_location: Location) -> int:
distance = get_distance(self.location, nearest_charge_station_location)
cover = self.fuel * self.per_fuel_distance_travel
diff = math.fabs(distance - cover)
if diff > 0:
needed_fuel = diff / self.per_fuel_distance_travel + 2
return needed_fuel
return 0
# U(i)
class Drone:
location = Location(0, 0)
fuel = 0
isFlying = False
isSendForEvCharge = False
per_fuel_distance_travel = 20
serving_radius = 15
G = [
ChargingStation(Location(20, 10), 50),
ChargingStation(Location(50, 80), 40),
ChargingStation(Location(30, 30), 60)
]
def __init__(self, location, fuel):
self.location = location
self.fuel = fuel
# Resid (U)
def residual_distance(self):
return self.fuel * self.per_fuel_distance_travel # assuming each unit of fuel will yield to 2 kilos or miles
def is_out_of_service_zone(self, vehicle_location: Location): # ----->
distance = get_distance(self.location, vehicle_location)
return distance > self.serving_radius
#staticmethod
def get_distance(from_location, to_location):
x_dis = to_location.x - from_location.x
y_dis = to_location.y - from_location.y
x_dis_sqr = math.pow(x_dis, 2)
y_dis_sqr = math.pow(y_dis, 2)
final_dis_sum = x_dis_sqr + y_dis_sqr
final = math.sqrt(final_dis_sum)
return final
class EDFGenerator:
min_fuel = 50
charging_stations_for_drones = [ChargingStation(Location(2, 10), 80), ChargingStation(Location(2, 10), 50),
ChargingStation(Location(2, 10), 100)]
list_waiting_drones = [Drone(Location(5, 10), 50), Drone(Location(2, 10), 50), Drone(Location(2, 10), 50)]
list_sent_drones = []
list_charging_drones = []
def __init__(self):
pass
def rdv_loc(self, ei: Vehicle, drone_location: Location, t: int) -> Location | None:
needed_fuel = ei.requested_amount_of_charge(drone_location)
nearest_charge_station = self.get_nearest_charge_station(ei.location, self.charging_stations_for_drones)
needed_fuel_at_nearest_station = needed_fuel / ei.per_fuel_distance_travel
if nearest_charge_station.fuel < needed_fuel_at_nearest_station:
return None
else:
return nearest_charge_station.location
#staticmethod
def get_nearest_charge_station(from_location: Location, list_of_stations: List[ChargingStation]) -> ChargingStation:
nearest = list_of_stations[0]
min_distance = get_distance(from_location, nearest.location)
for station in list_of_stations:
dis = get_distance(from_location, station.location)
if min_distance > dis:
min_distance = dis
nearest = station
return nearest
def NChgReq(self) -> int:
charging_requesters = 0
for drone in self.list_waiting_drones:
if drone.isNeedEmergencyFuel:
charging_requesters += 1
return charging_requesters
def send_drone_to_charge(self, drone: Drone): # ----->
if drone.fuel < self.min_fuel:
nearest_station = self.get_nearest_charge_station(
drone.location,
self.charging_stations_for_drones)
self.list_sent_drones.append(drone)
self.list_waiting_drones.remove(drone)
drone.isSendForEvCharge = True
# send the drone to the charging station here
print(f"Drone {drone} sent to charging station at {nearest_station}")
def check_fuel_and_send_to_charge(self): # ----->
for drone in self.list_waiting_drones:
self.send_drone_to_charge(drone)
def get_drone(self, max_try=4) -> Drone:
if max_try <= 0:
print("max try failed for get_drone")
return None
# take one time from list_waiting_drones ------->
# add to list_sent_drones
# send or return the taken item
if len(self.list_waiting_drones) == 0:
return None
else:
# lastOne = self.list_waiting_drones.pop()
self.last_one = self.list_waiting_drones.pop()
if self.last_one.fuel < self.min_fuel:
print("low fuel failed to get_drone, retry")
self.list_waiting_drones.insert(0, self.last_one)
return max_try - 1
self.list_sent_drones.append(self.last_one)
return self.last_one
def get_closest_location_from_sending_server_to_e_vehicle(self, current_vechicle_location):
min_distance = sys.maxsize
for current_server in self.charging_stations_for_drones:
distance = get_distance(current_vechicle_location, current_server.location)
if min_distance > distance:
min_distance = distance
return min_distance
def get_most_urgent_electric_vehicle(self, closest_distance_between_server_ev: int,
all_uncharged_electric_vehicles: List[Vehicle]) -> Vehicle:
final_ev = None
min_distance = sys.maxsize
for ev in all_uncharged_electric_vehicles:
g_r = self.get_closest_location_from_sending_server_to_e_vehicle(ev.location)
residual_distance = ev.residual_distance()
eq = g_r / residual_distance
if min_distance > eq:
min_distance = eq
final_ev = ev
return final_ev
def reports_termination_to_server(self, drone: Drone):
self.list_charging_drones.append(drone)
self.charge_all_waiting_drones()
def charge_all_waiting_drones(self):
# assuming the environment is not async but synchronous
for drone in self.list_charging_drones:
drone.fuel = 100
self.list_waiting_drones.insert(0, drone)
self.list_charging_drones.clear()
#staticmethod
def report_to_server(ev: Vehicle, message):
print(ev.id + " - " + message)
def get_edf(self, list_req: List[Vehicle]) -> Result:
s_uncharged_electric_vehicles = list_req
path_len = 0
n_charge_req = 0
while len(s_uncharged_electric_vehicles) > 0:
print("uncharged_ev : " + str(len(s_uncharged_electric_vehicles)))
current_uncharged_ev = s_uncharged_electric_vehicles[0]
u = self.get_drone()
if u is None:
print("no drones from any station or with min charge")
return Result(path_len, n_charge_req)
# current_uncharged_ev.location aka e----->
e = current_uncharged_ev.location
# confusion SGCS what would be the SET
g_r: int = self.get_closest_location_from_sending_server_to_e_vehicle(
e) # closest vehicle from sending location
# confusion regarding dis (loc(e), g_r) , g_r already contains the distance
e_x = self.get_most_urgent_electric_vehicle(g_r, s_uncharged_electric_vehicles)
drone_residual_distance = u.residual_distance() # Resid (U)
ev_requested_amount_of_charge = e_x.requested_amount_of_charge(u.location) # RqB2D
if drone_residual_distance < ev_requested_amount_of_charge:
self.reports_termination_to_server(u)
u = self.get_drone()
g_r_2 = self.get_closest_location_from_sending_server_to_e_vehicle(
u.location) # closest vehicle from sending location
self.reports_termination_to_server(u) # sends back the drone for charging
# ?? t is something confusing, how to include t into the equation??
rdv_loc = self.rdv_loc(e_x, u.location, 0) # t should be random
if rdv_loc is None:
self.report_to_server(e_x, "rdv location generate failed")
continue
if u.is_out_of_service_zone(rdv_loc):
self.report_to_server(e_x, "Out of Service")
continue
path_len += get_distance(u.location, rdv_loc)
u.location = rdv_loc
e_x.location = rdv_loc
# list_1 = filter(lambda x: x[3] <= 0.3 and x[2] < 5, list_1)
s_uncharged_electric_vehicles.remove(e_x)
n_charge_req = n_charge_req + 1
return Result(path_len, n_charge_req)
if __name__ == '__main__':
edf_runner = EDFGenerator()
un_charged_vehicles = [
Vehicle(1, Location(1, 1), 2),
Vehicle(2, Location(5, 10), 16),
Vehicle(3, Location(6, 10), 13),
Vehicle(4, Location(8, 11), 22),
Vehicle(5, Location(5, 6), 35),
]
edf_result = edf_runner.get_edf(un_charged_vehicles)
print("first_path_len - edf : ")
edf_result.print()
Where am I wrong? What needs fix?

Saving real time data in Python

I have a python interface of a software which stores data from the camera in excel. The software working is when I click Ready the camera starts recording and status shows(Running) and then when i click on the same tab it stops. NOw i want to write the current data in excel. Currently it is saving all the previous values.
It would be very helpful if i could get help on this as I am new to Python.
import wx
import wx.lib.activex
import csv
import comtypes.client
class EventSink(object):
def __init__(self, frame):
self.counter = 0
self.frame = frame
def DataReady(self):
self.counter +=1
self.frame.Title= "DataReady fired {0} times".format(self.counter)
class MyApp( wx.App ):
def OnClick(self,e):
rb_selection = self.rb.GetStringSelection()
if rb_selection == "WinCam":
data = self.gd.ctrl.GetWinCamDataAsVariant()
data = [[x] for x in data]
else:
p_selection = self.cb.GetStringSelection()
if p_selection == "Profile_X":
data = self.px.ctrl.GetProfileDataAsVariant()
data = [[x] for x in data]#csv.writerows accepts a list of rows where each row is a list, a list of lists
elif p_selection == "Profile_Y":
data = self.py.ctrl.GetProfileDataAsVariant()
data = [[x] for x in data]
**elif p_selection =="data_info":
while self.data18 ==1:
data= [self.data1,self.data2,self.data3,self.data4,self.data5,self.data6,self.data7,self.data8,self.data9,self.data10,self.data11,self.data12,self.data13,self.data14,self.data15,self.data16,self.data17,self.data18]
b=data
file = open('C:\\Users\\Namrata\\data.csv', 'w')
with file:
a = ['Clip Level a', 'Clip level b', 'Major','Minor','Mean','Eff_2W','Ellip','Orient','Crosshair','Xc','Yc','Centroid','Rc','ADC Peak','Exposure','image zoom','plateau uniformity']
zip(a,b)
out = csv.writer(file)
out.writerows(zip(a,b))
file.close()**
else:
datax = self.px.ctrl.GetProfileDataAsVariant()
datay = self.py.ctrl.GetProfileDataAsVariant()
data = [list(row) for row in zip(datax,datay)]#Makes a list of lists; X1 with Y1 in a list, X2 with Y2 in a list etc...
filename = self.ti.Value
with open(filename, 'w') as fp:
w = csv.writer(fp, delimiter=',')
w.writerows(data)
def __init__( self, redirect=False, filename=None ):
wx.App.__init__( self, redirect, filename )
self.frame = wx.Frame( parent=None, id=wx.ID_ANY,size=(1000,760), title='Python Interface to DataRay')
#Panel
p = wx.Panel(self.frame, wx.ID_ANY)
#Get Data
self.gd = wx.lib.activex.ActiveXCtrl(p, 'DATARAYOCX.GetDataCtrl.1')
#The methods of the object are available through the ctrl property of the item
self.gd.ctrl.StartDriver()
self.counter = 0
sink = EventSink(self.frame)
self.sink = comtypes.client.GetEvents(self.gd.ctrl, sink)
#Button Panel
bp = wx.Panel(parent=self.frame, id=wx.ID_ANY, size=(300, 400))
b1 = wx.lib.activex.ActiveXCtrl(parent=bp,size=(280,25), pos=(20, 0),axID='DATARAYOCX.ButtonCtrl.1')
b1.ctrl.ButtonID =297
self.data18= b1.ctrl.GetParameter()
b1.ctrl.GetParameter()#Id's for some ActiveX controls must be set
b2 = wx.lib.activex.ActiveXCtrl(parent=bp,size=(140,25), pos=(5, 30),axID='DATARAYOCX.ButtonCtrl.1')
b2.ctrl.ButtonID =294
self.data1= b2.ctrl.GetParameter()
b3 = wx.lib.activex.ActiveXCtrl(parent=bp,size=(140,25), pos=(150,30),axID='DATARAYOCX.ButtonCtrl.1')
b3.ctrl.ButtonID =295
data2= b3.ctrl.GetParameter()
b4 = wx.lib.activex.ActiveXCtrl(parent=bp,size=(140,25), pos=(5,60),axID='DATARAYOCX.ButtonCtrl.1')
b4.ctrl.ButtonID =180
data3= b4.ctrl.GetParameter()
b5 = wx.lib.activex.ActiveXCtrl(parent=bp,size=(140,25), pos=(150, 60),axID='DATARAYOCX.ButtonCtrl.1')
b5.ctrl.ButtonID =181
self.data4= b5.ctrl.GetParameter()
b6 = wx.lib.activex.ActiveXCtrl(parent=bp,size=(140,25), pos=(5, 90),axID='DATARAYOCX.ButtonCtrl.1')
b6.ctrl.ButtonID =182
data5= b6.ctrl.GetParameter()
b7 = wx.lib.activex.ActiveXCtrl(parent=bp,size=(140,25), pos=(150, 90),axID='DATARAYOCX.ButtonCtrl.1')
b7.ctrl.ButtonID =95
data6= b7.ctrl.GetParameter()
b8 = wx.lib.activex.ActiveXCtrl(parent=bp,size=(140,25), pos=(5, 120),axID='DATARAYOCX.ButtonCtrl.1')
b8.ctrl.ButtonID =177
data7= b8.ctrl.GetParameter()
b9 = wx.lib.activex.ActiveXCtrl(parent=bp,size=(140,25), pos=(150, 120),axID='DATARAYOCX.ButtonCtrl.1')
b9.ctrl.ButtonID =179
data8= b9.ctrl.GetParameter()
b10 = wx.lib.activex.ActiveXCtrl(parent=bp,size=(140,25), pos=(5,150),axID='DATARAYOCX.ButtonCtrl.1')
b10.ctrl.ButtonID =302
data9= b10.ctrl.GetParameter()
b11= wx.lib.activex.ActiveXCtrl(parent=bp,size=(140,25), pos=(150, 150),axID='DATARAYOCX.ButtonCtrl.1')
b11.ctrl.ButtonID =171
data10= b11.ctrl.GetParameter()
b12 = wx.lib.activex.ActiveXCtrl(parent=bp,size=(140,25), pos=(5, 180),axID='DATARAYOCX.ButtonCtrl.1')
b12.ctrl.ButtonID =172
data11= b12.ctrl.GetParameter()
b13 = wx.lib.activex.ActiveXCtrl(parent=bp,size=(140,25), pos=(150, 180),axID='DATARAYOCX.ButtonCtrl.1')
b13.ctrl.ButtonID =298
data12= b13.ctrl.GetParameter()
b14 = wx.lib.activex.ActiveXCtrl(parent=bp,size=(140,25), pos=(5, 210),axID='DATARAYOCX.ButtonCtrl.1')
b14.ctrl.ButtonID =425
data13= b14.ctrl.GetParameter()
b15 = wx.lib.activex.ActiveXCtrl(parent=bp,size=(140,25), pos=(150, 210),axID='DATARAYOCX.ButtonCtrl.1')
b15.ctrl.ButtonID =183
data14= b15.ctrl.GetParameter()
b16 = wx.lib.activex.ActiveXCtrl(parent=bp,size=(140,25), pos=(5, 240),axID='DATARAYOCX.ButtonCtrl.1')
b16.ctrl.ButtonID =409
data15= b16.ctrl.GetParameter()
b17 = wx.lib.activex.ActiveXCtrl(parent=bp,size=(140,25), pos=(150, 240),axID='DATARAYOCX.ButtonCtrl.1')
b17.ctrl.ButtonID =301
data16= b17.ctrl.GetParameter()
b18 = wx.lib.activex.ActiveXCtrl(parent=bp,size=(280,25), pos=(5, 270),axID='DATARAYOCX.ButtonCtrl.1')
b18.ctrl.ButtonID =291
data17= b18.ctrl.GetParameter()
#Custom controls
t = wx.StaticText(bp, label="File:", pos=(5, 300))
self.ti = wx.TextCtrl(bp, value="C:\\Users\\Public\\Documents\\output.csv", pos=(30, 300), size=(170, -1))
self.rb = wx.RadioBox(bp, label="Data:", pos=(5, 330), choices=["Profile", "WinCam","Data Info"])
self.cb = wx.ComboBox(bp, pos=(5,380), choices=[ "Profile_X", "Profile_Y", "data_info","Both"])
self.cb.SetSelection(0)
myb = wx.Button(bp, label="Write", pos=(150,380))
myb.Bind(wx.EVT_BUTTON, self.OnClick)
myd = wx.Button(bp, label="Dialog", pos=(150,330))
myd.Bind(wx.EVT_BUTTON, self.OnClick)
#Pictures
pic = wx.lib.activex.ActiveXCtrl(parent=self.frame,size=(300,400),axID='DATARAYOCX.CCDimageCtrl.1')
tpic = wx.lib.activex.ActiveXCtrl(parent=self.frame,size=(300,400), axID='DATARAYOCX.ThreeDviewCtrl.1')
palette = wx.lib.activex.ActiveXCtrl(parent=self.frame,size=(10,250), axID='DATARAYOCX.PaletteBarCtrl.1')
#Profiles
self.px = wx.lib.activex.ActiveXCtrl(parent=self.frame,size=(300,300),axID='DATARAYOCX.ProfilesCtrl.1')
self.px.ctrl.ProfileID=22
self.py = wx.lib.activex.ActiveXCtrl(parent=self.frame,size=(300,300),axID='DATARAYOCX.ProfilesCtrl.1')
self.py.ctrl.ProfileID = 23
self.ax = wx.lib.activex.ActiveXCtrl(parent=self.frame,size=(150,360),axID='DATARAYOCX.getdataCtrl.1')
#Formatting
row1 = wx.BoxSizer(wx.HORIZONTAL)
row1.Add(window=bp,flag=wx.RIGHT, border=10)
row1.Add(pic)
row1.Add(window=tpic, flag=wx.LEFT, border=10)
row2 = wx.BoxSizer(wx.HORIZONTAL)
row2.Add(self.px, 0, wx.RIGHT, 100)# Arguments: item, proportion, flags, border
row2.Add(self.py)
col1 = wx.BoxSizer(wx.VERTICAL)
col1.Add(sizer=row1, flag=wx.BOTTOM, border=10)
col1.Add(sizer=row2, flag=wx.ALIGN_CENTER_HORIZONTAL)
self.frame.SetSizer(col1)
self.frame.Show()
if __name__ == "__main__":
app = MyApp()
app.MainLoop()
to save data in real time you can do this:
first create a wx.timer that fires constantly:
self.timer = wx.Timer(self)
self.timer.start(#here you have to specify the amount of milliseconds the timer sleep before fire again)
self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer)
then you create the OnTimer() function to store data in the excel file:
from openpyxl import load_workbook
def OnTimer(self, event):
data = #here you get your data
wb = load_workbook('path/to/yout/excel/file.xlsx')
sheet = wb.active()
#here you have to play with cells rows and cols by inserting data and saving,
#for more info go to the below link
openpyxl documentation

Speed Up Python Programs (Adaptive Median Filter)

Hi can someone improve this code ? The code is about Adaptive Median Filter. When working on large image the code is so slow.
import numpy as np
def padding(img,pad):
padded_img = np.zeros((img.shape[0]+2*pad,img.shape[1]+2*pad))
padded_img[pad:-pad,pad:-pad] = img
return padded_img
def AdaptiveMedianFilter(img,s=3,sMax=7):
if len(img.shape) == 3:
raise Exception ("Single channel image only")
H,W = img.shape
a = sMax//2
padded_img = padding(img,a)
f_img = np.zeros(padded_img.shape)
for i in range(a,H+a+1):
for j in range(a,W+a+1):
value = Lvl_A(padded_img,i,j,s,sMax)
f_img[i,j] = value
return f_img[a:-a,a:-a]
def Lvl_A(mat,x,y,s,sMax):
window = mat[x-(s//2):x+(s//2)+1,y-(s//2):y+(s//2)+1]
Zmin = np.min(window)
Zmed = np.median(window)
Zmax = np.max(window)
A1 = Zmed - Zmin
A2 = Zmed - Zmax
if A1 > 0 and A2 < 0:
return Lvl_B(window)
else:
s += 2
if s <= sMax:
return Lvl_A(mat,x,y,s,sMax)
else:
return Zmed
def Lvl_B(window):
h,w = window.shape
Zmin = np.min(window)
Zmed = np.median(window)
Zmax = np.max(window)
Zxy = window[h//2,w//2]
B1 = Zxy - Zmin
B2 = Zxy - Zmax
if B1 > 0 and B2 < 0 :
return Zxy
else:
return Zmed
Is there any way to improve this code ? For example using vectorized sliding window ? I dont know how to use what numpy function. Ps: For boundary checking its using padding so it dont have to check for out of bounds.
The numba's njit is perfect for such kind of computation. Mixed with the parallel=True+prange it can be much faster. Moreover, you can pass the minimum, maximum and median values to Lvl_B rather than recomputing them as #CrisLuengo pointed out.
Here is the modified code:
import numpy as np
from numba import njit,prange
#njit
def padding(img,pad):
padded_img = np.zeros((img.shape[0]+2*pad,img.shape[1]+2*pad))
padded_img[pad:-pad,pad:-pad] = img
return padded_img
#njit(parallel=True)
def AdaptiveMedianFilter(img,s=3,sMax=7):
if len(img.shape) == 3:
raise Exception ("Single channel image only")
H,W = img.shape
a = sMax//2
padded_img = padding(img,a)
f_img = np.zeros(padded_img.shape)
for i in prange(a,H+a+1):
for j in range(a,W+a+1):
value = Lvl_A(padded_img,i,j,s,sMax)
f_img[i,j] = value
return f_img[a:-a,a:-a]
#njit
def Lvl_A(mat,x,y,s,sMax):
window = mat[x-(s//2):x+(s//2)+1,y-(s//2):y+(s//2)+1]
Zmin = np.min(window)
Zmed = np.median(window)
Zmax = np.max(window)
A1 = Zmed - Zmin
A2 = Zmed - Zmax
if A1 > 0 and A2 < 0:
return Lvl_B(window, Zmin, Zmed, Zmax)
else:
s += 2
if s <= sMax:
return Lvl_A(mat,x,y,s,sMax)
else:
return Zmed
#njit
def Lvl_B(window, Zmin, Zmed, Zmax):
h,w = window.shape
Zxy = window[h//2,w//2]
B1 = Zxy - Zmin
B2 = Zxy - Zmax
if B1 > 0 and B2 < 0 :
return Zxy
else:
return Zmed
This code is 500 times faster on my machine with a 256x256 random image.
Note that the first call will not be much faster due to the (included) compilation time.
Note also that the computation can be even faster by not recomputing the min/max/median for each value as the sliding windows share many values (see the paper constant time median filtering (Perreault et al, 2007)).
I tried to improve the previous code you can use the code below but note that the input image in this code is grayscale.
import numpy as np
def adaptive_median_filter(img_gray, s=3, sMax=7):
H, W = img_gray.shape
a = sMax//2
padded_img = np.pad(img_gray, a)
f_img = np.zeros(padded_img.shape)
for i in range(a, H + a + 1):
for j in range(a, W + a + 1):
f_img[i, j] = Lvl_A(padded_img, i, j, s, sMax)
return np.array(f_img[a: -a, a: -a], dtype=np.uint8)
def Lvl_A(mat, x, y, s, sMax):
window = mat[x - (s//2): x + (s//2) + 1, y - (s//2): y + (s//2) + 1]
Zmin = np.min(window)
win_vect = window.reshape(-1)
Zmed = np.sort(win_vect)[len(win_vect)//2] # O(nlog(n))
Zmax = np.max(window)
if Zmin < Zmed < Zmax:
return Lvl_B(window, Zmin, Zmax, Zmed)
else:
s += 2
if s <= sMax:
return Lvl_A(mat, x, y, s, sMax)
else:
return Zmed
def Lvl_B(window, Zmin, Zmax, Zmed):
h, w = window.shape
Zxy = window[h//2, w//2]
if Zmin < Zxy < Zmax:
return Zxy
else:
return Zmed

Dynamically pass leaf values from dataframe to n-ary tree in Python

Given a dataframe as follows:
root subroot leaf value
0 A B1 C1 58
1 A B1 C2 7
2 A B2 C1 0
3 A B2 C2 20
and code as follows:
from collections import deque
class Node:
def __init__(self, name, weight, children):
self.name = name
self.children = children
self.weight = weight
self.weight_plus_children = weight
def get_all_weight(self):
if self.children is None:
return self.weight_plus_children
for child in self.children:
self.weight_plus_children += child.get_all_weight()
return self.weight_plus_children
def print_tree(root: Node):
queue = deque()
queue.append(root)
while queue:
front = queue.popleft()
print('{} = {}'.format(front.name, front.weight_plus_children))
if front.children:
for child in front.children:
if child is not None:
queue.append(child)
leaf1 = Node('C1', 58, None)
leaf2 = Node('C2', 7, None)
leaf3 = Node('C1', 0, None)
leaf4 = Node('C2', 20, None)
subroot = Node('B1', 0, [leaf1, leaf2])
subroot1 = Node('B2', 0, [leaf3, leaf4])
root = Node('A', 0, [subroot, subroot1])
root.get_all_weight()
print_tree(root)
How could I pass leaf values from df to the following leaf dynamically?
The main ideas I'm doing this is I want to read excel files and pass leaf values to the code:
leaf1 = Node('C1', 58, None)
leaf2 = Node('C2', 7, None)
leaf3 = Node('C1', 0, None)
leaf4 = Node('C2', 20, None)
We can filter input=1's rows with: df.loc[df['input'] == 1].
Output expected:
A = 85
B1 = 65
B2 = 20
C1 = 58
C2 = 7
C1 = 0
C2 = 20
Thanks for your kind help.

How to improve execution time of generating image with multithreading

I am wondering why my code does not speed up when I increase number of threads. My app is generating output image from two input images. if I run only one thread, operation takes 28 seconds and if I run 2 to 8 threads operation takes time between 52 and 48 seconds.
This is fragment of my code:
def StartDuboisThreading():
global imageLeft
global imageRight
global anaglyphPixelArray
anaglyphPixelArray = None
numberOfThreads = threadSlider.get()
width, height = imageLeft.size
rgb_imgLeft = imageLeft.convert('RGB')
rgb_imgRight = imageRight.convert('RGB')
rowsPerThread = int(height / numberOfThreads)
remainder = height % numberOfThreads
threads = list()
start = time.time()
for i in range(0, numberOfThreads):
copyImgLeft = copy.deepcopy(rgb_imgLeft)
copyImgRight = copy.deepcopy(rgb_imgRight)
if (i != numberOfThreads - 1):
threads.append(ThreadWithReturnValue(target=ThreadFunctionWithArrays, args=(
i * rowsPerThread, (i + 1) * rowsPerThread, width, copyImgLeft, copyImgRight)))
threads[i].start()
else:
threads.append(ThreadWithReturnValue(target=ThreadFunctionWithArrays, args=(
i * rowsPerThread, height, width, copyImgLeft, copyImgRight)))
threads[i].start()
for i in range(0, numberOfThreads):
pixelsArray = threads[i].join()
if anaglyphPixelArray is None:
anaglyphPixelArray = pixelsArray
else:
anaglyphPixelArray = np.append(anaglyphPixelArray, pixelsArray, axis=0)
end = time.time()
timeElapsed = end - start
operationTimeText.configure(text='Time of operation: ' + timeElapsed.__str__())
CreateImage(anaglyphPixelArray)
I made a deepcopy of my input images objects because I thought that maybe my threads are reffering to the same memory at the same time and this can make a slight delay but this didn't work. Now I am in lack of ideas why this is only slowing down with more threads.
This is my thread function:
def ThreadFunctionWithArrays(startPointY, endPointY, pixelsWidth, pixelsArray1, pixelsArray2):
numberOfRows = endPointY - startPointY
pixelArray = GenerateEmptyPartMatrix(pixelsWidth, numberOfRows)
y = 0
print(str(startPointY) + " " + str(endPointY))
for j in range(startPointY, endPointY):
for i in range(0, pixelsWidth):
r1, g1, b1 = pixelsArray1.getpixel((i, j))
r2, g2, b2 = pixelsArray2.getpixel((i, j))
pixelArray[y][i] = (
r1 * 0.4561 + g1 * 0.500484 + b1 * 0.176381 - r2 * 0.0434706 - g2 * 0.0879388 - b2 * 0.00155529,
- r1 * 0.0400822 - g1 * 0.0378246 - b1 * 0.0157589 + r2 * 0.378476 + g2 * 0.73364 - b2 * 0.0184503,
- r1 * 0.0152161 - g1 * 0.0205971 - b1 * 0.00546856 - r2 * 0.0721527 - g2 * 0.112961 + b2 * 1.2264)
y +=1
return pixelArray
And here is definition of my extended Thread object:
class ThreadWithReturnValue(Thread):
def __init__(self, *args, **kwargs):
super(ThreadWithReturnValue, self).__init__(*args, **kwargs)
self._return = None
def run(self):
if self._target is not None:
self._return = self._target(*self._args, **self._kwargs)
def join(self, *args, **kwargs):
super(ThreadWithReturnValue, self).join(*args, **kwargs)
return self._return

Resources