def __init__(self, *args, **kwargs): clickpoints.Addon.__init__(self, *args, **kwargs) # set the title and layout self.setWindowTitle("TrackManager - ClickPoints") self.layout = QtWidgets.QVBoxLayout(self) # add some options # the minimum track length self.addOption(key="minLength", display_name="Min Track Length", default=-1, value_type="int", tooltip="How many points a track has to have to be displayed.", min=-1) self.spinBox_minLength = AddQSpinBox(self.layout, "Min Track Length:", value=self.getOption("minLength"), float=False) self.linkOption("minLength", self.spinBox_minLength) # the maximum track length self.addOption(key="maxLength", display_name="Max Track Length", default=-1, value_type="int", tooltip="How many points a track has to have to be displayed.", min=-1) self.spinBox_maxLength = AddQSpinBox(self.layout, "Max Track Length:", value=self.getOption("maxLength"), float=False) self.linkOption("maxLength", self.spinBox_maxLength) # the minimum track displacement self.addOption(key="minDisplacement", display_name="Min Track Displacement", default=-1, value_type="float", tooltip="How much displacement a track has to have to be displayed.", min=-1) self.spinBox_minDisplacement = AddQSpinBox(self.layout, "Min Track Displacement:", value=self.getOption("minDisplacement"), float=True) self.linkOption("minDisplacement", self.spinBox_minDisplacement) # the maximum track displacement self.addOption(key="maxDisplacement", display_name="Max Track Displacement", default=-1, value_type="float", tooltip="How much displacement a track has to have to be displayed.", min=-1) self.spinBox_maxDisplacement = AddQSpinBox(self.layout, "Max Track Displacement:", value=self.getOption("maxDisplacement"), float=True) self.linkOption("maxDisplacement", self.spinBox_maxDisplacement) # add export buttons self.button_update = QtWidgets.QPushButton("Update") self.button_update.clicked.connect(self.update) self.layout.addWidget(self.button_update)
def __init__(self, *args, **kwargs): clickpoints.Addon.__init__(self, *args, **kwargs) # set the title and layout self.setWindowTitle("Kymograph - ClickPoints") self.layout = QtWidgets.QVBoxLayout(self) # add some options # the frame number for the kymograph self.addOption(key="frames", display_name="Frames", default=50, value_type="int", tooltip="How many images to use for the kymograph.") self.input_count = AddQSpinBox(self.layout, "Frames:", value=self.getOption("frames"), float=False) self.linkOption("frames", self.input_count) # the with in pixel of each line self.addOption(key="width", display_name="Width", default=1, value_type="int", tooltip="The width of the slice to cut from the image.") self.input_width = AddQSpinBox(self.layout, "Width:", value=self.getOption("width"), float=False) self.linkOption("width", self.input_width) # the length scaling self.addOption(key="scaleLength", display_name="Scale Length", default=1, value_type="float", tooltip="What is distance a pixel represents.") self.input_scale1 = AddQSpinBox(self.layout, "Scale Length:", value=self.getOption("scaleLength"), float=True) self.linkOption("scaleLength", self.input_scale1) # the time scaling self.addOption( key="scaleTime", display_name="Scale Time", default=1, value_type="float", tooltip="What is the time difference between two images.") self.input_scale2 = AddQSpinBox(self.layout, "Scale Time:", value=self.getOption("scaleTime"), float=True) self.linkOption("scaleTime", self.input_scale2) # the colormap self.addOption(key="colormap", display_name="Colormap", default="None", value_type="string", tooltip="The colormap to use for the kymograph.") maps = ["None"] maps.extend(plt.colormaps()) self.input_colormap = AddQComboBox( self.layout, "Colormap:", selectedValue=self.getOption("colormap"), values=maps) self.input_colormap.setEditable(True) self.linkOption("colormap", self.input_colormap) # the table listing the line objects self.tableWidget = QtWidgets.QTableWidget(0, 1, self) self.layout.addWidget(self.tableWidget) self.row_headers = ["Line Length"] self.tableWidget.setHorizontalHeaderLabels(self.row_headers) self.tableWidget.setMinimumHeight(180) self.setMinimumWidth(500) self.tableWidget.setCurrentCell(0, 0) self.tableWidget.cellClicked.connect(self.cellSelected) # add kymograph types self.my_type = self.db.setMarkerType("kymograph", "#ef7fff", self.db.TYPE_Line, text="#$marker_id") self.my_type2 = self.db.setMarkerType("kymograph_end", "#df00ff", self.db.TYPE_Normal) self.cp.reloadTypes() # add a plot widget self.plot = MatplotlibWidget(self) self.layout.addWidget(self.plot) self.layout.addWidget(NavigationToolbar(self.plot, self)) self.plot.figure.canvas.mpl_connect('button_press_event', self.button_press_callback) # add export buttons layout = QtWidgets.QHBoxLayout() self.button_export = QtWidgets.QPushButton("Export") self.button_export.clicked.connect(self.export) layout.addWidget(self.button_export) self.button_export2 = QtWidgets.QPushButton("Export All") self.button_export2.clicked.connect(self.export2) layout.addWidget(self.button_export2) self.layout.addLayout(layout) # add a progress bar self.progressbar = QtWidgets.QProgressBar() self.layout.addWidget(self.progressbar) # connect slots self.signal_update_plot.connect(self.updatePlotImageEvent) self.signal_plot_finished.connect(self.plotFinishedEvent) # initialize the table self.updateTable() self.selected = None
class Addon(clickpoints.Addon): signal_update_plot = QtCore.Signal() signal_plot_finished = QtCore.Signal() image_plot = None last_update = 0 updating = False exporting = False exporting_index = 0 def __init__(self, *args, **kwargs): clickpoints.Addon.__init__(self, *args, **kwargs) # set the title and layout self.setWindowTitle("Kymograph - ClickPoints") self.layout = QtWidgets.QVBoxLayout(self) # add some options # the frame number for the kymograph self.addOption(key="frames", display_name="Frames", default=50, value_type="int", tooltip="How many images to use for the kymograph.") self.input_count = AddQSpinBox(self.layout, "Frames:", value=self.getOption("frames"), float=False) self.linkOption("frames", self.input_count) # the with in pixel of each line self.addOption(key="width", display_name="Width", default=1, value_type="int", tooltip="The width of the slice to cut from the image.") self.input_width = AddQSpinBox(self.layout, "Width:", value=self.getOption("width"), float=False) self.linkOption("width", self.input_width) # the length scaling self.addOption(key="scaleLength", display_name="Scale Length", default=1, value_type="float", tooltip="What is distance a pixel represents.") self.input_scale1 = AddQSpinBox(self.layout, "Scale Length:", value=self.getOption("scaleLength"), float=True) self.linkOption("scaleLength", self.input_scale1) # the time scaling self.addOption( key="scaleTime", display_name="Scale Time", default=1, value_type="float", tooltip="What is the time difference between two images.") self.input_scale2 = AddQSpinBox(self.layout, "Scale Time:", value=self.getOption("scaleTime"), float=True) self.linkOption("scaleTime", self.input_scale2) # the colormap self.addOption(key="colormap", display_name="Colormap", default="None", value_type="string", tooltip="The colormap to use for the kymograph.") maps = ["None"] maps.extend(plt.colormaps()) self.input_colormap = AddQComboBox( self.layout, "Colormap:", selectedValue=self.getOption("colormap"), values=maps) self.input_colormap.setEditable(True) self.linkOption("colormap", self.input_colormap) # the table listing the line objects self.tableWidget = QtWidgets.QTableWidget(0, 1, self) self.layout.addWidget(self.tableWidget) self.row_headers = ["Line Length"] self.tableWidget.setHorizontalHeaderLabels(self.row_headers) self.tableWidget.setMinimumHeight(180) self.setMinimumWidth(500) self.tableWidget.setCurrentCell(0, 0) self.tableWidget.cellClicked.connect(self.cellSelected) # add kymograph types self.my_type = self.db.setMarkerType("kymograph", "#ef7fff", self.db.TYPE_Line, text="#$marker_id") self.my_type2 = self.db.setMarkerType("kymograph_end", "#df00ff", self.db.TYPE_Normal) self.cp.reloadTypes() # add a plot widget self.plot = MatplotlibWidget(self) self.layout.addWidget(self.plot) self.layout.addWidget(NavigationToolbar(self.plot, self)) self.plot.figure.canvas.mpl_connect('button_press_event', self.button_press_callback) # add export buttons layout = QtWidgets.QHBoxLayout() self.button_export = QtWidgets.QPushButton("Export") self.button_export.clicked.connect(self.export) layout.addWidget(self.button_export) self.button_export2 = QtWidgets.QPushButton("Export All") self.button_export2.clicked.connect(self.export2) layout.addWidget(self.button_export2) self.layout.addLayout(layout) # add a progress bar self.progressbar = QtWidgets.QProgressBar() self.layout.addWidget(self.progressbar) # connect slots self.signal_update_plot.connect(self.updatePlotImageEvent) self.signal_plot_finished.connect(self.plotFinishedEvent) # initialize the table self.updateTable() self.selected = None def button_press_callback(self, event): # only drag with left mouse button if event.button != 1: return # if the user doesn't have clicked on an axis do nothing if event.inaxes is None: return # get the pixel of the kymograph x, y = event.xdata / self.input_scale1.value( ), event.ydata / self.h / self.input_scale2.value() # jump to the frame in time self.cp.jumpToFrame(self.bar.image.sort_index + int(y)) # and to the xy position self.cp.centerOn(*self.getLinePoint(self.bar, x)) def cellSelected(self, row, column): # store the row self.selected = row # and update the plot self.updatePlot() def setTableText(self, row, column, text): if column == -1: item = self.tableWidget.verticalHeaderItem(row) if item is None: item = QtWidgets.QTableWidgetItem("") self.tableWidget.setVerticalHeaderItem(row, item) else: item = self.tableWidget.item(row, column) if item is None: item = QtWidgets.QTableWidgetItem("") self.tableWidget.setItem(row, column, item) if column == 2: item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) item.setText(str(text)) def updateTable(self): self.updating = True bars = self.db.getLines(type=self.my_type) self.bars = [bar for bar in bars] self.bar_dict = {} self.tableWidget.setRowCount(bars.count()) self.last_image_id = None for idx, bar in enumerate(bars): self.updateRow(idx) self.bar_dict[bar.id] = idx self.updating = False def updateRow(self, idx): bar = self.bars[idx] self.setTableText(idx, -1, "#%d" % bar.id) self.setTableText(idx, 0, bar.length()) def getLinePoint(self, line, percentage): x1 = line.x1 x2 = line.x2 y1 = line.y1 y2 = line.y2 if self.mirror: y1, y2 = y2, y1 w = x2 - x1 h = y2 - y1 length = np.sqrt(w**2 + h**2) if self.mirror: percentage = length - percentage return x1 + w * percentage / length, y1 + h * percentage / length def getLine(self, image, line, height, image_entry=None): x1 = line.x1 x2 = line.x2 y1 = line.y1 y2 = line.y2 if self.mirror: y1, y2 = y2, y1 w = x2 - x1 h = y2 - y1 length = np.sqrt(w**2 + h**2) w2 = h / length h2 = -w / length if image_entry and image_entry.offset: offx, offy = image_entry.offset.x, image_entry.offset.y else: offx, offy = 0, 0 x1 -= offx - self.start_offx y1 -= offy - self.start_offy datas = [] for j in np.arange(0, self.h) - self.h / 2. + 0.5: data = [] for i in np.linspace(0, 1, np.ceil(length)): x = x1 + w * i + w2 * j y = y1 + h * i + h2 * j xp = x - np.floor(x) yp = y - np.floor(y) v = np.dot( np.array([[1 - yp, yp]]).T, np.array([[1 - xp, xp]])) if len(image.shape) == 3: data.append( np.sum(image[int(y):int(y) + 2, int(x):int(x) + 2, :] * v[:, :, None], axis=(0, 1), dtype=image.dtype)) else: data.append( np.sum(image[int(y):int(y) + 2, int(x):int(x) + 2] * v, dtype=image.dtype)) datas.append(data) if self.mirror: return np.array(datas)[:, ::-1] return np.array(datas)[::-1, :] def updatePlot(self): if self.selected is None: return self.n = -1 self.terminate() self.mirror = False if self.db.getOption("rotation") == 180: self.mirror = True self.bar = self.bars[self.selected] self.plot.axes.clear() image_start = self.bar.image if image_start.offset: self.start_offx, self.start_offy = image_start.offset.x, image_start.offset.y else: self.start_offx, self.start_offy = 0, 0 self.h = self.input_width.value() if int(self.input_count.value()) == 0: image = self.bar.image.sort_index end_marker = self.db.table_marker.select().where( self.db.table_marker.type == self.my_type2).join( self.db.table_image).where( self.db.table_image.sort_index > image).limit(1) self.n = end_marker[0].image.sort_index - image else: self.n = int(self.input_count.value()) self.progressbar.setRange(0, self.n - 1) data = image_start.data line_cut = self.getLine(data, self.bar, self.h, image_start) self.w = line_cut.shape[1] if len(data.shape) == 3: self.current_data = np.zeros( (self.h * self.n, self.w, data.shape[2]), dtype=line_cut.dtype) else: self.current_data = np.zeros((self.h * self.n, self.w), dtype=line_cut.dtype) self.current_data[0:self.h, :] = line_cut extent = (0, self.current_data.shape[1] * self.input_scale1.value(), self.current_data.shape[0] * self.input_scale2.value(), 0) if self.input_colormap.currentText() != "None": if len(self.current_data.shape) == 3: data_gray = np.dot(self.current_data[..., :3], [0.299, 0.587, 0.114]) self.image_plot = self.plot.axes.imshow( data_gray, cmap=self.input_colormap.currentText(), extent=extent) else: self.image_plot = self.plot.axes.imshow( self.current_data, cmap=self.input_colormap.currentText(), extent=extent) else: self.image_plot = self.plot.axes.imshow(self.current_data, cmap="gray", extent=extent) self.plot.axes.set_xlabel(u"distance (µm)") self.plot.axes.set_ylabel("time (s)") self.plot.figure.tight_layout() self.plot.draw() self.last_update = time.time() self.run_threaded(image_start.sort_index + 1, self.run) def updatePlotImageEvent(self): t = time.time() if t - self.last_update < 0.1 and self.index < self.n - 1: return self.last_update = t if self.image_plot: if len(self.current_data.shape ) == 3 and self.input_colormap.currentText() != "None": data_gray = np.dot(self.current_data[..., :3], [0.299, 0.587, 0.114]) self.image_plot.set_data(data_gray) else: self.image_plot.set_data(self.current_data) self.plot.draw() self.progressbar.setValue(self.index) def run(self, start_frame=0): for index, image in enumerate(self.db.getImageIterator(start_frame)): index += 1 self.index = index line_cut = self.getLine(image.data, self.bar, self.h, image) self.current_data[index * self.h:(index + 1) * self.h, :] = line_cut self.signal_update_plot.emit() if index >= self.n - 1 or self.cp.stop: self.signal_plot_finished.emit() break def plotFinishedEvent(self): if self.exporting: self.export() self.exporting_index += 1 if self.exporting_index < len(self.bars): self.cellSelected(self.exporting_index, 0) else: self.exporting_index = 0 self.exporting = False def export(self): filename = "kymograph%d.%s" # convert to grayscale if it is a color image that should be saved with a colormap if len(self.current_data.shape ) == 3 and self.input_colormap.currentText() != "None": data_gray = np.dot(self.current_data[..., :3], [0.299, 0.587, 0.114]) # if not just keep it else: data_gray = self.current_data # save the data as a numpy file np.savez(filename % (self.bar.id, "npz"), data_gray) # get the colormap cmap = self.input_colormap.currentText() if cmap == "None": cmap = "gray" # save the kymograph as an image plt.imsave(filename % (self.bar.id, "png"), data_gray, cmap=cmap) # print a log in the console print("Exported", filename % (self.bar.id, "npz")) def export2(self): self.exporting_index = 0 self.exporting = True self.cellSelected(self.exporting_index, 0) def markerMoveEvent(self, marker): if marker.type == self.my_type: row = self.bar_dict[marker.id] self.bars[row] = marker self.tableWidget.selectRow(row) self.updateRow(row) self.selected = row self.updatePlot() def markerAddEvent(self, entry): self.updateTable() def markerRemoveEvent(self, entry): self.updateTable() def buttonPressedEvent(self): self.show()
def __init__(self, *args, **kwargs): clickpoints.Addon.__init__(self, *args, **kwargs) # Check if the marker type is present if not self.db.getMarkerType("DM_horizon"): self.db.setMarkerType("DM_horizon", [0, 255, 255], self.db.TYPE_Normal) self.cp.reloadTypes() if not self.db.getMarkerType("DM_to_cam"): self.db.setMarkerType("DM_to_cam", [255, 255, 0], self.db.TYPE_Normal) self.cp.reloadTypes() if not self.db.getMarkerType("DM_between"): self.db.setMarkerType("DM_between", [255, 0, 255], self.db.TYPE_Line) self.cp.reloadTypes() if not self.db.getMarkerType("DM_area"): self.db.setMarkerType("DM_area", [0, 255, 0], self.db.TYPE_Normal) self.cp.reloadTypes() if not self.db.getMarkerType("DM_scalebox"): self.db.setMarkerType("DM_scalebox", [0, 255, 255], self.db.TYPE_Normal) self.cp.reloadTypes() if not self.db.getMarkerType("DM_GPS"): self.db.setMarkerType("DM_GPS", [128, 128, 255], self.db.TYPE_Normal) self.cp.reloadTypes() # TODO: move to parameter self.scalebox_dim = 10 # in meter self.scalebox_dict = dict() # Check if mask type is present if not self.db.getMaskType("area"): self.db.setMaskType("area", color='#00FF00') self.cp.reloadMaskTypes() # store options self.addOption(key='DM_last_camera', default=None, hidden=True, value_type='int') self.addOption(key='DM_focallength_mm', default=None, hidden=True, value_type='float') self.addOption(key='DM_fov_h_deg', default=None, hidden=True, value_type='float') self.addOption(key='DM_fov_v_deg', default=None, hidden=True, value_type='float') self.addOption(key='DM_sensor_w_mm', default=None, hidden=True, value_type='float') self.addOption(key='DM_sensor_h_mm', default=None, hidden=True, value_type='float') self.addOption(key='DM_img_w_px', default=None, hidden=True, value_type='int') self.addOption(key='DM_img_h_px', default=None, hidden=True, value_type='int') self.addOption(key='DM_offset_x_px', default=None, hidden=True, value_type='float') self.addOption(key='DM_offset_y_px', default=None, hidden=True, value_type='float') self.addOption(key='DM_cam_elevation', default=20, hidden=True, value_type='float') self.addOption(key='DM_plane_elevation', default=0, hidden=True, value_type='float') # get json files if available else create defaults """ Default entries for Cameras """ #region # atkaSPOT # Mobotic D12 Day as used in atkaSPOT MobotixM12_Day = dotdict() MobotixM12_Day.fov_h_deg = 45 MobotixM12_Day.fov_v_deg = 34 MobotixM12_Day.sensor_w_mm = None MobotixM12_Day.sensor_h_mm = None MobotixM12_Day.focallength_mm = 22 MobotixM12_Day.img_w_px = 2048 MobotixM12_Day.img_h_px = 1536 MobotixM12_Night = dotdict() MobotixM12_Night.fov_h_deg = 45 MobotixM12_Night.fov_v_deg = 34 MobotixM12_Night.sensor_w_mm = None MobotixM12_Night.sensor_h_mm = None MobotixM12_Night.focallength_mm = 22 MobotixM12_Night.img_w_px = 2048 MobotixM12_Night.img_h_px = 1536 CampbellMpx5 = dotdict() CampbellMpx5.fov_h_deg = 80 CampbellMpx5.fov_v_deg = 65 CampbellMpx5.sensor_w_mm = None CampbellMpx5.sensor_h_mm = None CampbellMpx5.focallength_mm = 12 CampbellMpx5.img_w_px = 2470 CampbellMpx5.img_h_px = 1800 GE4000C_400mm = dotdict() GE4000C_400mm.fov_h_deg = None GE4000C_400mm.fov_v_deg = None GE4000C_400mm.sensor_w_mm = 36 GE4000C_400mm.sensor_h_mm = 24 GE4000C_400mm.focallength_mm = 400 GE4000C_400mm.img_w_px = 4008 GE4000C_400mm.img_h_px = 2672 GE4000C_400mm_crop05 = dotdict() GE4000C_400mm_crop05.fov_h_deg = None GE4000C_400mm_crop05.fov_v_deg = None GE4000C_400mm_crop05.sensor_w_mm = 36 GE4000C_400mm_crop05.sensor_h_mm = 24 GE4000C_400mm_crop05.focallength_mm = 400 GE4000C_400mm_crop05.img_w_px = 2004 GE4000C_400mm_crop05.img_h_px = 1336 Panasonic_DMC_G5 = dotdict() Panasonic_DMC_G5.fov_h_deg = None Panasonic_DMC_G5.fov_v_deg = None Panasonic_DMC_G5.sensor_w_mm = 17.3 Panasonic_DMC_G5.sensor_h_mm = 13.0 Panasonic_DMC_G5.focallength_mm = 14 Panasonic_DMC_G5.img_w_px = 4608 Panasonic_DMC_G5.img_h_px = 3456 Canon_D10 = dotdict() Canon_D10.fov_h_deg = None Canon_D10.fov_v_deg = None Canon_D10.sensor_w_mm = 6.17 Canon_D10.sensor_h_mm = 4.55 Canon_D10.focallength_mm = 6.2 Canon_D10.img_w_px = 4000 Canon_D10.img_h_px = 3000 # add all cameras to one dictionary cam_dict = dotdict() cam_dict['MobotixM12_Day'] = MobotixM12_Day cam_dict['MobotixM12_Night'] = MobotixM12_Night cam_dict['CampbellMpx5'] = CampbellMpx5 cam_dict['GE4000C_400mm'] = GE4000C_400mm cam_dict['GE4000C_400mm_crop05'] = GE4000C_400mm_crop05 cam_dict['Panasonic_DMC_G5'] = Panasonic_DMC_G5 cam_dict['Canon_D10'] = Canon_D10 # endregion camera_json = os.path.join(os.path.dirname(__file__), 'camera.json') if not os.path.exists(camera_json): print( "DistanceMeasure Addon: no default camera.json found - creating ..." ) with open(camera_json, 'w') as fd: json.dump(cam_dict, fd, indent=4, sort_keys=True) else: # read from json file print("DistanceMeasure Addon: loading camera.json") with open(camera_json, 'r') as fd: self.cam_dict = json.load(fd) ## Widget # set the title and layout self.setWindowTitle("Distance - Config") self.setWindowIcon(qta.icon("fa.map-signs")) # self.setMinimumWidth(400) # self.setMinimumHeight(200) self.layout = QtWidgets.QGridLayout(self) ## camera region # use a groupbox for camera parameters self.camera_groupbox = QtWidgets.QGroupBox("Camera") self.camera_groupbox.setSizePolicy( QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)) self.layout.addWidget(self.camera_groupbox, 0, 0) # add a grid layout for elements self.camera_layout = QtWidgets.QVBoxLayout() self.camera_groupbox.setLayout(self.camera_layout) # combo box to select camera models stored in camera.json self.cameraComboBox = AddQComboBox(self.camera_layout, 'Model:', values=cam_dict.keys()) self.cameraComboBox.currentIndexChanged.connect( self.getCameraParametersByJson) self.openFile = AddQOpenFileChoose(self.camera_layout, "Input", "", file_type="*.*") self.openFile.textChanged.connect(self.getCameraParametersByCT) # self.cameraButton = QtWidgets.QPushButton('Load Cam') # self.cameraButton.clicked.connect(self.loadCamerFromFile) # self.camera_layout.addWidget(self.cameraButton) # self.cameraComboBox.setCurrentIndex(5) # self.cameraComboBox.addItems(cam_dict.keys()) self.cbProjection = AddQComboBox( self.camera_layout, "Camera Projection:", values=["Rectilinear", "Cylindrical", "Equirectangular"]) self.leFocallength = AddQLineEdit(self.camera_layout, "f (mm):", editwidth=120) self.leImage_width = AddQLineEdit(self.camera_layout, "image width (px):", editwidth=120) self.leImage_height = AddQLineEdit(self.camera_layout, "image height (px):", editwidth=120) self.leSensor_width = AddQLineEdit(self.camera_layout, "sensor width (mm):", editwidth=120) self.leSensor_height = AddQLineEdit(self.camera_layout, "sensor height (mm):", editwidth=120) self.leFOV_horizontal = AddQLineEdit(self.camera_layout, "FOV horizontal (deg):", editwidth=120) self.leFOV_vertical = AddQLineEdit(self.camera_layout, "FOV vertical (deg):", editwidth=120) self.leOffsetX = AddQLineEdit(self.camera_layout, "center offset x (px):", "0.", editwidth=120) self.leOffsetY = AddQLineEdit(self.camera_layout, "center offset y (px):", "0.", editwidth=120) ## position region self.position_groupbox = QtWidgets.QGroupBox("Position") self.position_groupbox.setSizePolicy( QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)) self.layout.addWidget(self.position_groupbox, 1, 0) # add a grid layout for elements self.position_layout = QtWidgets.QVBoxLayout() self.position_groupbox.setLayout(self.position_layout) self.leCamElevation = AddQLineEdit(self.position_layout, "camera elevation (m):", editwidth=120, value='25') self.lePlaneElevation = AddQLineEdit(self.position_layout, "plane elevation (m):", editwidth=120, value='0') self.leCamTilt = AddQLineEdit(self.position_layout, "camera tilt:", editwidth=120, value=None) self.leCamRoll = AddQLineEdit(self.position_layout, "camera roll:", editwidth=120, value=None) self.leCamPan = AddQLineEdit(self.position_layout, "camera pan:", editwidth=120, value=None) self.leCamLat = AddQLineEdit(self.position_layout, "camera latitude:", editwidth=120) self.leCamLon = AddQLineEdit(self.position_layout, "camera longitude:", editwidth=120) self.leCamPosX = AddQLineEdit(self.position_layout, "camera position X:", editwidth=120) self.leCamPosY = AddQLineEdit(self.position_layout, "camera position Y:", editwidth=120) for c in self.position_groupbox.children(): if hasattr(c, "editingFinished"): c.editingFinished.connect(self.update) for c in self.camera_groupbox.children(): if hasattr(c, "editingFinished"): c.editingFinished.connect(self.update) # get current frame cframe = self.cp.getCurrentFrame() # retrieve data qimg = self.db.getImage(frame=cframe) print( os.path.isfile( os.path.join(qimg.path.path, os.path.splitext(qimg.filename)[0], ".ct"))) # fill context menu from stored options if available if self.getOption('DM_last_camera'): # load from DB self.cameraComboBox.setCurrentIndex( self.getOption('DM_last_camera')) self.getCameraParametersByDB() self.getPostionParametersByDB() self.updateCameraParameters() elif os.path.isfile( os.path.join(qimg.path.path, os.path.splitext(qimg.filename)[0], ".ct")): self.getCameraParametersByCT( os.path.isfile( os.path.join(qimg.path.path, os.path.splitext(qimg.filename)[0], ".ct"))) self.updateCameraParameters() else: # load from json self.getCameraParametersByJson() self.updateCameraParameters() ## display region self.display_groupbox = QtWidgets.QGroupBox("Display and Evaluation") self.display_groupbox.setSizePolicy( QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)) self.layout.addWidget(self.display_groupbox, 2, 0) self.display_layout = QtWidgets.QVBoxLayout() self.display_groupbox.setLayout(self.display_layout) self.cbCalcArea = AddQCheckBox(self.display_layout, "calculate marked area", checked=False, strech=False) self.cbCalcArea.setToolTip( 'NOTE: LUT mode area calculation assumes a cylindrical projection with a straight and horizontal horizon' ) self.cbFitParameters = AddQCheckBox(self.display_layout, "fit camera parameters", checked=False, strech=False) self.sbScaleboxDim = AddQSpinBox(self.display_layout, "scale Box size", value=10, strech=False) self.cbShowHorizon = AddQCheckBox(self.display_layout, "display horizon", checked=True, strech=False) self.horizon_line = None ## projection region self.projection_groupbox = QtWidgets.QGroupBox("Projection") self.projection_groupbox.setSizePolicy( QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)) self.layout.addWidget(self.projection_groupbox, 0, 1, 6, 6) self.projection_layout = QtWidgets.QVBoxLayout() self.projection_groupbox.setLayout(self.projection_layout) self.pltWidget = matplotlibwidget.MatplotlibWidget() self.projection_layout.addWidget(self.pltWidget) self.leExtent = AddQLineEdit(self.projection_layout, 'Extent', '') self.leScaling = AddQLineEdit(self.projection_layout, 'Scaling', '') self.pbRefreshProjection = QtWidgets.QPushButton('Refresh') self.pbRefreshProjection.clicked.connect( self.pushbutton_refreshprojction) self.projection_layout.addWidget(self.pbRefreshProjection) ## stretch area self.layout.addItem( QtWidgets.QSpacerItem(1, 1, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding), 4, 0) self.pushbutton_ok = QtWidgets.QPushButton("Ok") self.pushbutton_ok.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) self.layout.addWidget(self.pushbutton_ok, 5, 0) self.pushbutton_ok.clicked.connect(self.run)
class Addon(clickpoints.Addon): camera = None cam_dict = None initialized = False def __init__(self, *args, **kwargs): clickpoints.Addon.__init__(self, *args, **kwargs) # Check if the marker type is present if not self.db.getMarkerType("DM_horizon"): self.db.setMarkerType("DM_horizon", [0, 255, 255], self.db.TYPE_Normal) self.cp.reloadTypes() if not self.db.getMarkerType("DM_to_cam"): self.db.setMarkerType("DM_to_cam", [255, 255, 0], self.db.TYPE_Normal) self.cp.reloadTypes() if not self.db.getMarkerType("DM_between"): self.db.setMarkerType("DM_between", [255, 0, 255], self.db.TYPE_Line) self.cp.reloadTypes() if not self.db.getMarkerType("DM_area"): self.db.setMarkerType("DM_area", [0, 255, 0], self.db.TYPE_Normal) self.cp.reloadTypes() if not self.db.getMarkerType("DM_scalebox"): self.db.setMarkerType("DM_scalebox", [0, 255, 255], self.db.TYPE_Normal) self.cp.reloadTypes() if not self.db.getMarkerType("DM_GPS"): self.db.setMarkerType("DM_GPS", [128, 128, 255], self.db.TYPE_Normal) self.cp.reloadTypes() # TODO: move to parameter self.scalebox_dim = 10 # in meter self.scalebox_dict = dict() # Check if mask type is present if not self.db.getMaskType("area"): self.db.setMaskType("area", color='#00FF00') self.cp.reloadMaskTypes() # store options self.addOption(key='DM_last_camera', default=None, hidden=True, value_type='int') self.addOption(key='DM_focallength_mm', default=None, hidden=True, value_type='float') self.addOption(key='DM_fov_h_deg', default=None, hidden=True, value_type='float') self.addOption(key='DM_fov_v_deg', default=None, hidden=True, value_type='float') self.addOption(key='DM_sensor_w_mm', default=None, hidden=True, value_type='float') self.addOption(key='DM_sensor_h_mm', default=None, hidden=True, value_type='float') self.addOption(key='DM_img_w_px', default=None, hidden=True, value_type='int') self.addOption(key='DM_img_h_px', default=None, hidden=True, value_type='int') self.addOption(key='DM_offset_x_px', default=None, hidden=True, value_type='float') self.addOption(key='DM_offset_y_px', default=None, hidden=True, value_type='float') self.addOption(key='DM_cam_elevation', default=20, hidden=True, value_type='float') self.addOption(key='DM_plane_elevation', default=0, hidden=True, value_type='float') # get json files if available else create defaults """ Default entries for Cameras """ #region # atkaSPOT # Mobotic D12 Day as used in atkaSPOT MobotixM12_Day = dotdict() MobotixM12_Day.fov_h_deg = 45 MobotixM12_Day.fov_v_deg = 34 MobotixM12_Day.sensor_w_mm = None MobotixM12_Day.sensor_h_mm = None MobotixM12_Day.focallength_mm = 22 MobotixM12_Day.img_w_px = 2048 MobotixM12_Day.img_h_px = 1536 MobotixM12_Night = dotdict() MobotixM12_Night.fov_h_deg = 45 MobotixM12_Night.fov_v_deg = 34 MobotixM12_Night.sensor_w_mm = None MobotixM12_Night.sensor_h_mm = None MobotixM12_Night.focallength_mm = 22 MobotixM12_Night.img_w_px = 2048 MobotixM12_Night.img_h_px = 1536 CampbellMpx5 = dotdict() CampbellMpx5.fov_h_deg = 80 CampbellMpx5.fov_v_deg = 65 CampbellMpx5.sensor_w_mm = None CampbellMpx5.sensor_h_mm = None CampbellMpx5.focallength_mm = 12 CampbellMpx5.img_w_px = 2470 CampbellMpx5.img_h_px = 1800 GE4000C_400mm = dotdict() GE4000C_400mm.fov_h_deg = None GE4000C_400mm.fov_v_deg = None GE4000C_400mm.sensor_w_mm = 36 GE4000C_400mm.sensor_h_mm = 24 GE4000C_400mm.focallength_mm = 400 GE4000C_400mm.img_w_px = 4008 GE4000C_400mm.img_h_px = 2672 GE4000C_400mm_crop05 = dotdict() GE4000C_400mm_crop05.fov_h_deg = None GE4000C_400mm_crop05.fov_v_deg = None GE4000C_400mm_crop05.sensor_w_mm = 36 GE4000C_400mm_crop05.sensor_h_mm = 24 GE4000C_400mm_crop05.focallength_mm = 400 GE4000C_400mm_crop05.img_w_px = 2004 GE4000C_400mm_crop05.img_h_px = 1336 Panasonic_DMC_G5 = dotdict() Panasonic_DMC_G5.fov_h_deg = None Panasonic_DMC_G5.fov_v_deg = None Panasonic_DMC_G5.sensor_w_mm = 17.3 Panasonic_DMC_G5.sensor_h_mm = 13.0 Panasonic_DMC_G5.focallength_mm = 14 Panasonic_DMC_G5.img_w_px = 4608 Panasonic_DMC_G5.img_h_px = 3456 Canon_D10 = dotdict() Canon_D10.fov_h_deg = None Canon_D10.fov_v_deg = None Canon_D10.sensor_w_mm = 6.17 Canon_D10.sensor_h_mm = 4.55 Canon_D10.focallength_mm = 6.2 Canon_D10.img_w_px = 4000 Canon_D10.img_h_px = 3000 # add all cameras to one dictionary cam_dict = dotdict() cam_dict['MobotixM12_Day'] = MobotixM12_Day cam_dict['MobotixM12_Night'] = MobotixM12_Night cam_dict['CampbellMpx5'] = CampbellMpx5 cam_dict['GE4000C_400mm'] = GE4000C_400mm cam_dict['GE4000C_400mm_crop05'] = GE4000C_400mm_crop05 cam_dict['Panasonic_DMC_G5'] = Panasonic_DMC_G5 cam_dict['Canon_D10'] = Canon_D10 # endregion camera_json = os.path.join(os.path.dirname(__file__), 'camera.json') if not os.path.exists(camera_json): print( "DistanceMeasure Addon: no default camera.json found - creating ..." ) with open(camera_json, 'w') as fd: json.dump(cam_dict, fd, indent=4, sort_keys=True) else: # read from json file print("DistanceMeasure Addon: loading camera.json") with open(camera_json, 'r') as fd: self.cam_dict = json.load(fd) ## Widget # set the title and layout self.setWindowTitle("Distance - Config") self.setWindowIcon(qta.icon("fa.map-signs")) # self.setMinimumWidth(400) # self.setMinimumHeight(200) self.layout = QtWidgets.QGridLayout(self) ## camera region # use a groupbox for camera parameters self.camera_groupbox = QtWidgets.QGroupBox("Camera") self.camera_groupbox.setSizePolicy( QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)) self.layout.addWidget(self.camera_groupbox, 0, 0) # add a grid layout for elements self.camera_layout = QtWidgets.QVBoxLayout() self.camera_groupbox.setLayout(self.camera_layout) # combo box to select camera models stored in camera.json self.cameraComboBox = AddQComboBox(self.camera_layout, 'Model:', values=cam_dict.keys()) self.cameraComboBox.currentIndexChanged.connect( self.getCameraParametersByJson) self.openFile = AddQOpenFileChoose(self.camera_layout, "Input", "", file_type="*.*") self.openFile.textChanged.connect(self.getCameraParametersByCT) # self.cameraButton = QtWidgets.QPushButton('Load Cam') # self.cameraButton.clicked.connect(self.loadCamerFromFile) # self.camera_layout.addWidget(self.cameraButton) # self.cameraComboBox.setCurrentIndex(5) # self.cameraComboBox.addItems(cam_dict.keys()) self.cbProjection = AddQComboBox( self.camera_layout, "Camera Projection:", values=["Rectilinear", "Cylindrical", "Equirectangular"]) self.leFocallength = AddQLineEdit(self.camera_layout, "f (mm):", editwidth=120) self.leImage_width = AddQLineEdit(self.camera_layout, "image width (px):", editwidth=120) self.leImage_height = AddQLineEdit(self.camera_layout, "image height (px):", editwidth=120) self.leSensor_width = AddQLineEdit(self.camera_layout, "sensor width (mm):", editwidth=120) self.leSensor_height = AddQLineEdit(self.camera_layout, "sensor height (mm):", editwidth=120) self.leFOV_horizontal = AddQLineEdit(self.camera_layout, "FOV horizontal (deg):", editwidth=120) self.leFOV_vertical = AddQLineEdit(self.camera_layout, "FOV vertical (deg):", editwidth=120) self.leOffsetX = AddQLineEdit(self.camera_layout, "center offset x (px):", "0.", editwidth=120) self.leOffsetY = AddQLineEdit(self.camera_layout, "center offset y (px):", "0.", editwidth=120) ## position region self.position_groupbox = QtWidgets.QGroupBox("Position") self.position_groupbox.setSizePolicy( QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)) self.layout.addWidget(self.position_groupbox, 1, 0) # add a grid layout for elements self.position_layout = QtWidgets.QVBoxLayout() self.position_groupbox.setLayout(self.position_layout) self.leCamElevation = AddQLineEdit(self.position_layout, "camera elevation (m):", editwidth=120, value='25') self.lePlaneElevation = AddQLineEdit(self.position_layout, "plane elevation (m):", editwidth=120, value='0') self.leCamTilt = AddQLineEdit(self.position_layout, "camera tilt:", editwidth=120, value=None) self.leCamRoll = AddQLineEdit(self.position_layout, "camera roll:", editwidth=120, value=None) self.leCamPan = AddQLineEdit(self.position_layout, "camera pan:", editwidth=120, value=None) self.leCamLat = AddQLineEdit(self.position_layout, "camera latitude:", editwidth=120) self.leCamLon = AddQLineEdit(self.position_layout, "camera longitude:", editwidth=120) self.leCamPosX = AddQLineEdit(self.position_layout, "camera position X:", editwidth=120) self.leCamPosY = AddQLineEdit(self.position_layout, "camera position Y:", editwidth=120) for c in self.position_groupbox.children(): if hasattr(c, "editingFinished"): c.editingFinished.connect(self.update) for c in self.camera_groupbox.children(): if hasattr(c, "editingFinished"): c.editingFinished.connect(self.update) # get current frame cframe = self.cp.getCurrentFrame() # retrieve data qimg = self.db.getImage(frame=cframe) print( os.path.isfile( os.path.join(qimg.path.path, os.path.splitext(qimg.filename)[0], ".ct"))) # fill context menu from stored options if available if self.getOption('DM_last_camera'): # load from DB self.cameraComboBox.setCurrentIndex( self.getOption('DM_last_camera')) self.getCameraParametersByDB() self.getPostionParametersByDB() self.updateCameraParameters() elif os.path.isfile( os.path.join(qimg.path.path, os.path.splitext(qimg.filename)[0], ".ct")): self.getCameraParametersByCT( os.path.isfile( os.path.join(qimg.path.path, os.path.splitext(qimg.filename)[0], ".ct"))) self.updateCameraParameters() else: # load from json self.getCameraParametersByJson() self.updateCameraParameters() ## display region self.display_groupbox = QtWidgets.QGroupBox("Display and Evaluation") self.display_groupbox.setSizePolicy( QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)) self.layout.addWidget(self.display_groupbox, 2, 0) self.display_layout = QtWidgets.QVBoxLayout() self.display_groupbox.setLayout(self.display_layout) self.cbCalcArea = AddQCheckBox(self.display_layout, "calculate marked area", checked=False, strech=False) self.cbCalcArea.setToolTip( 'NOTE: LUT mode area calculation assumes a cylindrical projection with a straight and horizontal horizon' ) self.cbFitParameters = AddQCheckBox(self.display_layout, "fit camera parameters", checked=False, strech=False) self.sbScaleboxDim = AddQSpinBox(self.display_layout, "scale Box size", value=10, strech=False) self.cbShowHorizon = AddQCheckBox(self.display_layout, "display horizon", checked=True, strech=False) self.horizon_line = None ## projection region self.projection_groupbox = QtWidgets.QGroupBox("Projection") self.projection_groupbox.setSizePolicy( QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)) self.layout.addWidget(self.projection_groupbox, 0, 1, 6, 6) self.projection_layout = QtWidgets.QVBoxLayout() self.projection_groupbox.setLayout(self.projection_layout) self.pltWidget = matplotlibwidget.MatplotlibWidget() self.projection_layout.addWidget(self.pltWidget) self.leExtent = AddQLineEdit(self.projection_layout, 'Extent', '') self.leScaling = AddQLineEdit(self.projection_layout, 'Scaling', '') self.pbRefreshProjection = QtWidgets.QPushButton('Refresh') self.pbRefreshProjection.clicked.connect( self.pushbutton_refreshprojction) self.projection_layout.addWidget(self.pbRefreshProjection) ## stretch area self.layout.addItem( QtWidgets.QSpacerItem(1, 1, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding), 4, 0) self.pushbutton_ok = QtWidgets.QPushButton("Ok") self.pushbutton_ok.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) self.layout.addWidget(self.pushbutton_ok, 5, 0) self.pushbutton_ok.clicked.connect(self.run) #self.db.addOption('DM_current_cam',self.cameraComboBox.getCurrentIndex()) def getPostionParametersByDB(self): """ load position parameters """ self.leCamElevation.setText( getNumber(self.getOption('DM_cam_elevation'), '%.2f')) self.lePlaneElevation.setText( getNumber(self.getOption('DM_plane_elevation'), '%.2f')) def getCameraParametersByDB(self): """ load camera parameters from last run stored in DB """ # set cam parameters self.leFocallength.setText("%.2f" % self.getOption('DM_focallength_mm')) self.leImage_width.setText("%d" % self.getOption('DM_img_w_px')) self.leImage_height.setText("%d" % self.getOption('DM_img_h_px')) self.leSensor_width.setText( getNumber(self.getOption('DM_sensor_w_mm'), "%.2f")) self.leSensor_height.setText( getNumber(self.getOption('DM_sensor_h_mm'), "%.2f")) self.leFOV_horizontal.setText( getNumber(self.getOption('DM_fov_h_deg'), "%.2f")) self.leFOV_vertical.setText( getNumber(self.getOption('DM_fov_v_deg'), "%.2f")) self.leOffsetX.setText( getNumber(self.getOption('DM_offset_x_px'), "%.2f")) self.leOffsetY.setText( getNumber(self.getOption('DM_offset_y_px'), "%.2f")) def getCameraParametersByJson(self): """ insert camera parameters from camera.json into gui """ self.selected_cam_name = self.cameraComboBox.itemText( self.cameraComboBox.currentIndex()) print("Selected Cam:", self.selected_cam_name) # store to options self.setOption('DM_last_camera', self.cameraComboBox.currentIndex()) cam_by_dict = dotdict(self.cam_dict[self.selected_cam_name]) def getNumber(input, format): try: return (format % input) except TypeError: return "None" # set cam parameters in GUI self.leFocallength.setText("%.2f" % cam_by_dict['focallength_mm']) self.leImage_width.setText("%d" % cam_by_dict['img_w_px']) self.leImage_height.setText("%d" % cam_by_dict['img_h_px']) self.leSensor_width.setText( getNumber(cam_by_dict['sensor_w_mm'], "%.2f")) self.leSensor_height.setText( getNumber(cam_by_dict['sensor_h_mm'], "%.2f")) self.leFOV_horizontal.setText( getNumber(cam_by_dict['fov_h_deg'], "%.2f")) self.leFOV_vertical.setText(getNumber(cam_by_dict['fov_v_deg'], "%.2f")) def getCameraParametersByCT(self, ct_file): cam = ct.load_camera(ct_file) cam_by_dict = {} cam_by_dict['img_w_px'] = cam.image_width_px cam_by_dict['img_h_px'] = cam.image_height_px cam_by_dict['offset_x_px'] = cam.center_x_px - cam.image_width_px / 2 cam_by_dict['offset_y_px'] = cam.center_y_px - cam.image_height_px / 2 cam_by_dict['sensor_w_mm'] = cam.sensor_width_mm cam_by_dict['sensor_h_mm'] = cam.sensor_height_mm cam_by_dict['fov_h_deg'] = np.rad2deg( np.arctan2(cam.image_width_px / 2, cam.focallength_x_px) * 2) cam_by_dict['fov_v_deg'] = np.rad2deg( np.arctan2(cam.image_height_px / 2, cam.focallength_y_px) * 2) cam_by_dict[ 'focallength_mm'] = cam.focallength_x_px * cam.sensor_width_mm / cam.image_width_px # set cam parameters in GUI self.leFocallength.setText("%.2f" % cam_by_dict['focallength_mm']) self.leImage_width.setText("%d" % cam_by_dict['img_w_px']) self.leImage_height.setText("%d" % cam_by_dict['img_h_px']) self.leSensor_width.setText( getNumber(cam_by_dict['sensor_w_mm'], "%.2f")) self.leSensor_height.setText( getNumber(cam_by_dict['sensor_h_mm'], "%.2f")) self.leFOV_horizontal.setText( getNumber(cam_by_dict['fov_h_deg'], "%.2f")) self.leFOV_vertical.setText(getNumber(cam_by_dict['fov_v_deg'], "%.2f")) self.leOffsetX.setText(getNumber(cam_by_dict['offset_x_px'], "%.2f")) self.leOffsetY.setText(getNumber(cam_by_dict['offset_y_px'], "%.2f")) self.leCamElevation.setText(getNumber(cam.elevation_m, "%.2f")) self.leCamPan.setText(getNumber(cam.heading_deg, "%.2f")) self.leCamTilt.setText(getNumber(cam.tilt_deg, "%.2f")) self.leCamRoll.setText(getNumber(cam.roll_deg, "%.2f")) self.leCamLat.setText(getNumber(cam.gps_lat, "%.2f")) self.leCamLon.setText(getNumber(cam.gps_lon, "%.2f")) self.leCamPosX.setText(getNumber(cam.pos_x_m, "%.2f")) self.leCamPosY.setText(getNumber(cam.pos_y_m, "%.2f")) self.updateCameraParameters() def calcSensorDimensionsFromFOV(self): self.cam.sensor_w_mm = utilFOVToSensor(self.cam.fov_h_deg, self.cam.focallength_mm) self.cam.sensor_h_mm = utilFOVToSensor(self.cam.fov_v_deg, self.cam.focallength_mm) def updateCameraParameters(self): """ update camera dictionary for calculation - uses potentially user modified data from gui """ # update current cam parameters self.cam = dotdict() self.cam.fov_h_deg = getFloat(self.leFOV_horizontal.text()) self.cam.fov_v_deg = getFloat(self.leFOV_vertical.text()) self.cam.sensor_w_mm = getFloat(self.leSensor_width.text()) self.cam.sensor_h_mm = getFloat(self.leSensor_height.text()) self.cam.focallength_mm = getFloat(self.leFocallength.text()) self.cam.img_w_px = getInteger(self.leImage_width.text()) self.cam.img_h_px = getInteger(self.leImage_height.text()) self.cam.center_x_px = self.cam.img_w_px / 2. + getFloat( self.leOffsetX.text()) self.cam.center_y_px = self.cam.img_h_px / 2. + getFloat( self.leOffsetY.text()) self.cam.heading_deg = getFloat(self.leCamPan.text()) self.cam.tilt_deg = getFloat(self.leCamTilt.text()) self.cam.roll_deg = getFloat(self.leCamRoll.text()) self.cam.elevation_m = getFloat(self.leCamElevation.text()) self.cam.pos_x_m = getFloat(self.leCamPosX.text()) self.cam.pos_y_m = getFloat(self.leCamPosY.text()) self.cam.projection = self.cbProjection.itemText( self.cbProjection.currentIndex()) self.cam.gps_lat = getFloat(self.leCamLat.text()) self.cam.gps_lon = getFloat(self.leCamLon.text()) if self.cam.sensor_h_mm is None or self.cam.sensor_w_mm is None: self.calcSensorDimensionsFromFOV() # save parameters as options to DB self.setOption('DM_focallength_mm', self.cam.focallength_mm) self.setOption('DM_fov_h_deg', self.cam.fov_h_deg) self.setOption('DM_fov_v_deg', self.cam.fov_v_deg) self.setOption('DM_sensor_w_mm', self.cam.sensor_w_mm) self.setOption('DM_sensor_h_mm', self.cam.sensor_h_mm) self.setOption('DM_img_w_px', self.cam.img_w_px) self.setOption('DM_img_h_px', self.cam.img_h_px) self.setOption('DM_offset_x_px', getFloat(self.leOffsetX.text())) self.setOption('DM_offset_y_px', getFloat(self.leOffsetY.text())) print("Camera:") print(json.dumps(self.cam, indent=4, sort_keys=True)) self.position = dotdict() self.position.cam_elevation = getFloat(self.leCamElevation.text()) self.position.plane_elevation = getFloat(self.lePlaneElevation.text()) # save parameters to options self.setOption('DM_cam_elevation', self.position.cam_elevation) self.setOption('DM_plane_elevation', self.position.plane_elevation) print("Position:") print(json.dumps(self.position, indent=4, sort_keys=True)) print(self.cam) # update camera parameters # self.camera = ct.CameraTransform(self.cam.focallength_mm, [self.cam.sensor_w_mm, self.cam.sensor_h_mm],[self.cam.img_w_px, self.cam.img_h_px]) orientation = ct.SpatialOrientation(heading_deg=self.cam.heading_deg, tilt_deg=self.cam.tilt_deg, roll_deg=self.cam.roll_deg, elevation_m=self.cam.elevation_m, pos_x_m=self.cam.pos_x_m, pos_y_m=self.cam.pos_y_m) if self.cam.projection == "Cylindrical": projection = ct.CylindricalProjection( focallength_mm=self.cam.focallength_mm, image_width_px=self.cam.img_w_px, image_height_px=self.cam.img_h_px, sensor_width_mm=self.cam.sensor_w_mm, sensor_height_mm=self.cam.sensor_h_mm, center_x_px=self.cam.center_x_px, center_y_px=self.cam.center_y_px) elif self.cam.projection == "Equirectangular": projection = ct.EquirectangularProjection( focallength_mm=self.cam.focallength_mm, image_width_px=self.cam.img_w_px, image_height_px=self.cam.img_h_px, sensor_width_mm=self.cam.sensor_w_mm, sensor_height_mm=self.cam.sensor_h_mm, center_x_px=self.cam.center_x_px, center_y_px=self.cam.center_y_px) else: # default to rectilinear projection print("Defaulting to rectiliniear") projection = ct.RectilinearProjection( focallength_mm=self.cam.focallength_mm, image_width_px=self.cam.img_w_px, image_height_px=self.cam.img_h_px, sensor_width_mm=self.cam.sensor_w_mm, sensor_height_mm=self.cam.sensor_h_mm, center_x_px=self.cam.center_x_px, center_y_px=self.cam.center_y_px) self.camera = ct.Camera(orientation=orientation, projection=projection) self.camera.setGPSpos(lat=self.cam.gps_lat, lon=self.cam.gps_lon, elevation=self.cam.elevation_m) def run(self, start_frame=0): self.frame = self.cp.getCurrentFrame() print("processing frame nr %d" % self.frame) self.updateCameraParameters() # # get image parameters # image = self.db.getImage(frame=start_frame) # data = image.data # im_height, im_width, channels = data.shape # self.camera = ct.Camera(self.cam.) if self.cbFitParameters.isChecked(): # try to load marker horizon = self.db.getMarkers(type="DM_horizon", frame=self.frame) if horizon.count() < 2: print( "ERROR: Too few horizon markers placed - please add at least TWO horizon markers" ) return self.camera.fixHorizon(horizon) if self.position.cam_elevation: self.camera.fixHeight(self.position.cam_elevation) # set fit parameter self.fit_params = dotdict() self.fit_params.horizon_points = horizon.count() self.fit_params.cam_elevation = self.camera.height self.fit_params.cam_tilt = np.round(self.camera.tilt, 2) self.fit_params.dist_to_horizon = np.round( self.camera.distanceToHorizon(), 2) # update params self.leCamTilt.setText(getNumber(self.camera.tilt, "%.2f")) self.leCamPan.setText(getNumber(self.camera.heading, "%.2f")) self.leCamRoll.setText(getNumber(self.camera.roll, "%.2f")) # succesfully initialized self.initialized = True # DEBUG # print("Fit Parameter:") # print(json.dumps(self.fit_params, indent=4, sort_keys=True)) # TODO: add region update? self.updateAllMarker() # mask handling if self.cbCalcArea.isChecked(): q_mask = self.db.getMasks(frame=self.frame) print("masks: ", q_mask.count()) rotation = self.db.getOption('rotation') print("rotation ", rotation) print(self.camera) if q_mask.count() > 0: # get mask data mask = q_mask[0].data # binaryse mask[mask > 0] = 1 mask_labeled = label(mask) props = regionprops(mask_labeled) # handle rotated images if rotation == 180: self.LUT = self.camera.generateLUT(invert=True) else: self.LUT = self.camera.generateLUT() # calculate corrected area for idx, n in enumerate( np.unique(mask_labeled)[1:]): # we exclude 0 area = np.zeros(mask_labeled.shape) area[mask_labeled == n] = 1 corrected_area = np.sum(np.sum(area, axis=1) * self.LUT) props[idx].corrected_area = corrected_area self.db.deleteMarkers(type='DM_area', image=q_mask[0].image) # iterate over properties and set marker for display for nr, prop in enumerate(props): self.db.setMarker(image=q_mask[0].image, x=prop.centroid[1], y=prop.centroid[0], text=u'%.2f px²\n%.2f m²' % (prop.area, prop.corrected_area), type='DM_area') self.cp.reloadMarker(frame=self.frame) # show the horizon line self.plotHorizon() def plotHorizon(self): if self.cbShowHorizon.isChecked(): # delete old horizon self.deleteHorizon() # get coordinates p1 = self.camera.getImageHorizon()[0] p2 = self.camera.getImageHorizon()[-1] print(p1, p2) # set pen pen = QtGui.QPen(QtGui.QColor("#00ffff")) pen.setWidth(5) pen.setCosmetic(True) # add object self.horizon_line = QtWidgets.QGraphicsLineItem( QtCore.QLineF(QtCore.QPointF(*p1), QtCore.QPointF(*p2))) self.horizon_line.setPen(pen) self.horizon_line.setParentItem(self.cp.window.view.origin) self.horizon_line.setZValue(100) else: self.deleteHorizon() def deleteHorizon(self): if self.horizon_line: print("delete") self.horizon_line.scene().removeItem(self.horizon_line) self.horizon_line = None def update(self): self.updateCameraParameters() self.updateAllMarker() def updateAllMarker(self): # get distance to cam markers and calculate distance dist2cam = self.db.getMarkers(type="DM_to_cam", frame=self.frame) for marker in dist2cam: self.updateDistMarker(marker) # get line markers and calculate distance in between dist2pt = self.db.getLines(type="DM_between", frame=self.frame) for line in dist2pt: self.updateDistLine(line) # get scalebox markers and update size distscalebox = self.db.getMarkers(type="DM_scalebox", frame=self.frame) for marker in distscalebox: self.updateScalebox(marker) # get scalebox markers and update size gpsMarkers = self.db.getMarkers(type="DM_GPS", frame=self.frame) for marker in gpsMarkers: self.updateGPS(marker) self.cp.reloadMarker(frame=self.frame) self.plotHorizon() self.cp.reloadMarker(frame=self.frame) def updateDistMarker(self, marker): """ Update distance to observer indicated by marker """ pos = self.camera.spaceFromImage(np.array([marker.x, marker.y]), Z=0).T marker.text = "%.2fm" % np.sqrt(pos[0]**2 + pos[1]**2) marker.save() def updateDistLine(self, line): """ Update distance indicated by an line marker """ pts = np.round(np.array([line.getPos1(), line.getPos2()]), 0) #TODO: Why doesnt this work when i supply the same point twice in an array? pos1 = self.camera.spaceFromImage(pts[0], Z=self.position.plane_elevation).T pos2 = self.camera.spaceFromImage(pts[1], Z=self.position.plane_elevation).T dist = np.sqrt(np.sum(((pos1 - pos2)**2))) line.text = "%.2fm" % dist line.save() def updateScalebox(self, marker): scalebox_dim = self.sbScaleboxDim.value() if marker.id in self.scalebox_dict: sb = self.scalebox_dict[marker.id] sb.delete() self.scalebox_dict.pop(marker.id) if marker.text is not None: match = re.match(r"^(?P<dim>\d*\.?\d*)\s*(?P<unit>\S*)?.*", marker.text) if match: match = match.groupdict() if match["unit"] in UNITS.keys(): scalebox_dim = float( match["dim"]) * UNITS[match["unit"]] else: scalebox_dim = float(match["dim"]) sb = ScaleBox(self.cp.window.view.origin, '#ff5f00', np.array([marker.x, marker.y]), self.camera, scalebox_dim) self.scalebox_dict[marker.id] = sb def updateGPS(self, marker): locationData = json.loads(marker.style) if "lon" in locationData and "lat" in locationData: lon = locationData["lon"] lat = locationData["lat"] if "h" in locationData: h = locationData["h"] else: h = 0 imagePos = self.camera.imageFromSpace(self.camera.spaceFromGPS( np.array([lat, lon, h])), hide_backpoints=False) if np.all(~np.isnan(imagePos)): marker.x = imagePos[0] marker.y = imagePos[1] marker.save() else: print("gps position of marker is not in Image!") # pass def markerMoveEvent(self, marker): """ On moving a marker - update the text information """ if self.initialized: if marker.type.name == 'DM_to_cam': self.updateDistMarker(marker) if marker.type.name == 'DM_between': self.updateDistLine(marker) if marker.type.name == 'DM_scalebox': self.updateScalebox(marker) def markerRemoveEvent(self, marker): if self.initialized: if marker.type.name == 'DM_scalebox': self.scalebox_dict[marker.id].delete() del self.scalebox_dict[marker.id] def markerAddEvent(self, marker): """ On adding a marker - calculate values """ if self.initialized: if marker.type.name == 'DM_to_cam': self.updateDistMarker(marker) if marker.type.name == 'DM_between': self.updateDistLine(marker) if marker.type.name == 'DM_scalebox': self.updateScalebox(marker) def pushbutton_refreshprojction(self): print("Refresh projection") # frame = self.cp.getCurrentFrame() img = self.cp.getImage().data if not isinstance(img, np.ndarray): img = img.image rotation = self.db.getOption('rotation') print('rotation', rotation) if rotation == 180: img = img[::-1, ::-1, :] extent = self.leExtent.text() scaling = getFloat(self.leScaling.text()) print(extent) print(scaling) try: ex1, ex2, ex3, ex4 = extent.split(',') print("Setting custom extent to:", ex1, ex2, ex3, ex4) top_view = self.camera.getTopViewOfImage( img, extent=np.array([ex1, ex2, ex3, ex4]).astype(float), scaling=scaling) except: top_view = self.camera.getTopViewOfImage(img, scaling=scaling) self.pltWidget.axes.imshow(top_view) self.pltWidget.show() def buttonPressedEvent(self): # show the addon window when the button in ClickPoints is pressed self.show() try: self.run() except: pass def delete(self): # clean up on reload self.deleteHorizon() # clean scale boxes for i, sb in self.scalebox_dict.items(): sb.delete()
class Addon(clickpoints.Addon): def __init__(self, *args, **kwargs): clickpoints.Addon.__init__(self, *args, **kwargs) # set the title and layout self.setWindowTitle("TrackManager - ClickPoints") self.layout = QtWidgets.QVBoxLayout(self) # add some options # the minimum track length self.addOption( key="minLength", display_name="Min Track Length", default=-1, value_type="int", tooltip="How many points a track has to have to be displayed.", min=-1) self.spinBox_minLength = AddQSpinBox(self.layout, "Min Track Length:", value=self.getOption("minLength"), float=False) self.linkOption("minLength", self.spinBox_minLength) # the maximum track length self.addOption( key="maxLength", display_name="Max Track Length", default=-1, value_type="int", tooltip="How many points a track has to have to be displayed.", min=-1) self.spinBox_maxLength = AddQSpinBox(self.layout, "Max Track Length:", value=self.getOption("maxLength"), float=False) self.linkOption("maxLength", self.spinBox_maxLength) # the minimum track displacement self.addOption( key="minDisplacement", display_name="Min Track Displacement", default=-1, value_type="float", tooltip= "How much displacement a track has to have to be displayed.", min=-1) self.spinBox_minDisplacement = AddQSpinBox( self.layout, "Min Track Displacement:", value=self.getOption("minDisplacement"), float=True) self.linkOption("minDisplacement", self.spinBox_minDisplacement) # the maximum track displacement self.addOption( key="maxDisplacement", display_name="Max Track Displacement", default=-1, value_type="float", tooltip= "How much displacement a track has to have to be displayed.", min=-1) self.spinBox_maxDisplacement = AddQSpinBox( self.layout, "Max Track Displacement:", value=self.getOption("maxDisplacement"), float=True) self.linkOption("maxDisplacement", self.spinBox_maxDisplacement) # add export buttons self.button_update = QtWidgets.QPushButton("Update") self.button_update.clicked.connect(self.update) self.layout.addWidget(self.button_update) def buttonPressedEvent(self): self.show() def update(self): # empty lists query_filters = [] query_parameters = [] # add filter for min count minCount = self.spinBox_minLength.value() if minCount > 0: query_filters.append("count(marker.track_id) > ?") query_parameters.append(minCount) # add filter for max count maxCount = self.spinBox_maxLength.value() if maxCount > -1: query_filters.append("count(marker.track_id) < ?") query_parameters.append(maxCount) # add filter for min displacement minDisplacement = self.spinBox_minDisplacement.value() if minDisplacement > 0: query_filters.append( "((min(marker.x)-max(marker.x))*(min(marker.x)-max(marker.x)))+((min(marker.y)-max(marker.y))*(min(marker.y)-max(marker.y))) > ?" ) query_parameters.append(minDisplacement**2) # add filter for max displacement maxDisplacement = self.spinBox_maxDisplacement.value() if maxDisplacement > -1: query_filters.append( "((min(marker.x)-max(marker.x))*(min(marker.x)-max(marker.x)))+((min(marker.y)-max(marker.y))*(min(marker.y)-max(marker.y))) < ?" ) query_parameters.append(maxDisplacement**2) # apply filters if len(query_filters) > 0: self.db.db.execute_sql( "UPDATE track SET hidden = (SELECT 1-(" + " AND ".join(query_filters) + ") FROM marker WHERE track.id = marker.track_id GROUP BY track_id)", query_parameters) # or show all if no filters are active else: self.db.db.execute_sql("UPDATE track SET hidden = 0") # reload the tracks self.cp.reloadTracks()
def __init__(self, *args, **kwargs): clickpoints.Addon.__init__(self, *args, **kwargs) # set the title and layout self.setWindowTitle("Fluorescence Diffusion - ClickPoints") self.layout = QtWidgets.QVBoxLayout(self) self.addOption(key="delta_t", display_name="Delta t", default=2, value_type="float") self.addOption(key="color_channel", display_name="Color Channel", default=1, value_type="int") self.addOption(key="output_folder", display_name="Output Folder", default="output", value_type="string") # create a line type "connect" if not self.db.getMarkerType("connect"): self.db.setMarkerType("connect", [0, 255, 255], self.db.TYPE_Line) self.cp.reloadTypes() self.layout_intensity = QtWidgets.QHBoxLayout() self.layout.addLayout(self.layout_intensity) self.layout_intensity1 = QtWidgets.QVBoxLayout() self.layout_intensity.addLayout(self.layout_intensity1) self.input_delta_t = AddQSpinBox(self.layout_intensity1, "Delta T:", value=self.getOption("delta_t"), float=True) self.input_delta_t.setSuffix(" s") self.linkOption("delta_t", self.input_delta_t) self.input_color = AddQSpinBox(self.layout_intensity1, "Color Channel:", value=self.getOption("color_channel"), float=False) self.linkOption("color_channel", self.input_color) self.button_update = QtWidgets.QPushButton("Calculate Intensities") self.layout_intensity1.addWidget(self.button_update) self.button_update.clicked.connect(self.updateIntensities) # the table listing the line objects self.tableWidget = QtWidgets.QTableWidget(0, 1, self) self.layout_intensity1.addWidget(self.tableWidget) self.layout_intensity_plot = QtWidgets.QVBoxLayout() self.layout_intensity.addLayout(self.layout_intensity_plot) self.plot_intensity = MatplotlibWidget(self) self.layout_intensity_plot.addWidget(self.plot_intensity) self.layout_intensity_plot.addWidget( NavigationToolbar(self.plot_intensity, self)) self.layout.addWidget(AddHLine()) self.layout_diffusion = QtWidgets.QHBoxLayout() self.layout.addLayout(self.layout_diffusion) self.layout_diffusion1 = QtWidgets.QVBoxLayout() self.layout_diffusion.addLayout(self.layout_diffusion1) self.button_calculate = QtWidgets.QPushButton("Calculate Diffusion") self.layout_diffusion1.addWidget(self.button_calculate) self.button_calculate.clicked.connect(self.calculateDiffusion) # the table listing the line objects self.tableWidget2 = QtWidgets.QTableWidget(0, 1, self) self.layout_diffusion1.addWidget(self.tableWidget2) self.layout_diffusion_plot = QtWidgets.QVBoxLayout() self.layout_diffusion.addLayout(self.layout_diffusion_plot) self.plot_diffusion = MatplotlibWidget(self) self.layout_diffusion_plot.addWidget(self.plot_diffusion) self.layout_diffusion_plot.addWidget( NavigationToolbar(self.plot_diffusion, self)) # add a progress bar self.progressbar = QtWidgets.QProgressBar() self.layout.addWidget(self.progressbar) self.diffusionConstants = []
class Addon(clickpoints.Addon): def __init__(self, *args, **kwargs): clickpoints.Addon.__init__(self, *args, **kwargs) # set the title and layout self.setWindowTitle("Fluorescence Diffusion - ClickPoints") self.layout = QtWidgets.QVBoxLayout(self) self.addOption(key="delta_t", display_name="Delta t", default=2, value_type="float") self.addOption(key="color_channel", display_name="Color Channel", default=1, value_type="int") self.addOption(key="output_folder", display_name="Output Folder", default="output", value_type="string") # create a line type "connect" if not self.db.getMarkerType("connect"): self.db.setMarkerType("connect", [0, 255, 255], self.db.TYPE_Line) self.cp.reloadTypes() self.layout_intensity = QtWidgets.QHBoxLayout() self.layout.addLayout(self.layout_intensity) self.layout_intensity1 = QtWidgets.QVBoxLayout() self.layout_intensity.addLayout(self.layout_intensity1) self.input_delta_t = AddQSpinBox(self.layout_intensity1, "Delta T:", value=self.getOption("delta_t"), float=True) self.input_delta_t.setSuffix(" s") self.linkOption("delta_t", self.input_delta_t) self.input_color = AddQSpinBox(self.layout_intensity1, "Color Channel:", value=self.getOption("color_channel"), float=False) self.linkOption("color_channel", self.input_color) self.button_update = QtWidgets.QPushButton("Calculate Intensities") self.layout_intensity1.addWidget(self.button_update) self.button_update.clicked.connect(self.updateIntensities) # the table listing the line objects self.tableWidget = QtWidgets.QTableWidget(0, 1, self) self.layout_intensity1.addWidget(self.tableWidget) self.layout_intensity_plot = QtWidgets.QVBoxLayout() self.layout_intensity.addLayout(self.layout_intensity_plot) self.plot_intensity = MatplotlibWidget(self) self.layout_intensity_plot.addWidget(self.plot_intensity) self.layout_intensity_plot.addWidget( NavigationToolbar(self.plot_intensity, self)) self.layout.addWidget(AddHLine()) self.layout_diffusion = QtWidgets.QHBoxLayout() self.layout.addLayout(self.layout_diffusion) self.layout_diffusion1 = QtWidgets.QVBoxLayout() self.layout_diffusion.addLayout(self.layout_diffusion1) self.button_calculate = QtWidgets.QPushButton("Calculate Diffusion") self.layout_diffusion1.addWidget(self.button_calculate) self.button_calculate.clicked.connect(self.calculateDiffusion) # the table listing the line objects self.tableWidget2 = QtWidgets.QTableWidget(0, 1, self) self.layout_diffusion1.addWidget(self.tableWidget2) self.layout_diffusion_plot = QtWidgets.QVBoxLayout() self.layout_diffusion.addLayout(self.layout_diffusion_plot) self.plot_diffusion = MatplotlibWidget(self) self.layout_diffusion_plot.addWidget(self.plot_diffusion) self.layout_diffusion_plot.addWidget( NavigationToolbar(self.plot_diffusion, self)) # add a progress bar self.progressbar = QtWidgets.QProgressBar() self.layout.addWidget(self.progressbar) self.diffusionConstants = [] def calculateIntensities(self): self.cp.save() self.times = [] # get times for t, im in enumerate(self.db.getImages()): self.times.append(t * self.input_delta_t.value()) # iterate over cells self.cell_intensities = [] self.cell_names = [] self.cell_colors = [] self.cell_indices = [] self.cell_areas = [] for m, cell in enumerate(self.db.getMaskTypes()): self.cell_names.append(cell.name) self.cell_colors.append(cell.color) self.cell_indices.append(cell.index) inte_list = [] size = 0 for t, im in enumerate(self.db.getImages()): mask = (im.mask.data == cell.index) if not np.any(mask): break im1 = im.data if len(im1.shape) == 3: if im1.shape[2] == 1: im1 = im1[:, :, 0] else: im1 = im1[:, :, self.input_color.value()] inte_list.append(np.mean(im1[mask])) if t == 0: size = np.sum(mask) self.cell_intensities.append(inte_list) self.cell_areas.append(size) self.link_pairs = [] for connection in self.db.getLines(type="connect"): pair1 = connection.image.mask.data[int(connection.y1), int(connection.x1)] pair2 = connection.image.mask.data[int(connection.y2), int(connection.x2)] try: pair1 = self.cell_indices.index(pair1) pair2 = self.cell_indices.index(pair2) except ValueError: print("Invalid connection!") continue if pair1 < pair2: pair = (pair1, pair2) else: pair = (pair2, pair1) if pair not in self.link_pairs: self.link_pairs.append(pair) print(self.link_pairs) if len(self.diffusionConstants) != len(self.link_pairs): self.diffusionConstants = np.zeros(len(self.link_pairs)) def setTableText(self, tableWidget, row, column, text): if column == -1: item = tableWidget.verticalHeaderItem(row) if item is None: item = QtWidgets.QTableWidgetItem("") tableWidget.setVerticalHeaderItem(row, item) elif row == -1: item = tableWidget.horizontalHeaderItem(column) if item is None: item = QtWidgets.QTableWidgetItem("") tableWidget.setHorizontalHeaderItem(column, item) else: item = tableWidget.item(row, column) if item is None: item = QtWidgets.QTableWidgetItem("") tableWidget.setItem(row, column, item) if column == 2: item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) item.setText(str(text)) def updateTable(self): self.tableWidget.setRowCount(len(self.cell_names)) self.tableWidget.setColumnCount(len(self.times)) for index, time in enumerate(self.times): self.setTableText(self.tableWidget, -1, index, "%s s" % str(time)) for index, cell in enumerate(self.cell_names): self.setTableText(self.tableWidget, index, -1, cell) for index2, intensity in enumerate(self.cell_intensities[index]): self.setTableText(self.tableWidget, index, index2, "%.2f" % intensity) self.tableWidget.horizontalHeader().setSectionResizeMode( QtWidgets.QHeaderView.Stretch) self.tableWidget2.setRowCount(len(self.link_pairs)) print(self.tableWidget2.rowCount(), len(self.link_pairs)) self.tableWidget2.setColumnCount(1) self.setTableText(self.tableWidget2, -1, 0, "Diffusion") for index, pair in enumerate(self.link_pairs): self.setTableText( self.tableWidget2, index, -1, "%s - %s" % (self.cell_names[pair[0]], self.cell_names[pair[1]])) self.setTableText(self.tableWidget2, index, 0, self.diffusionConstants[index]) def updateIntensityPlot(self): ax = self.plot_intensity.figure.axes[0] ax.clear() plots = [] for index, cell in enumerate(self.cell_names): p, = ax.plot(self.times, self.cell_intensities[index], "-", color=self.cell_colors[index]) plots.append(p) ax.set_xlabel("time (s)") ax.set_ylabel("mean intensity") ax.legend(plots, self.cell_names) self.plot_intensity.figure.tight_layout() self.plot_intensity.figure.canvas.draw() def updateIntensities(self): self.calculateIntensities() self.updateTable() self.updateIntensityPlot() def calculateDiffusion(self): self.calculateIntensities() self.run_threaded() def updateDiffusionPlot(self): I = np.array(self.Model(self.diffusionConstants)) ax = self.plot_diffusion.figure.axes[0] ax.clear() plots = [] for index, cell in enumerate(self.cell_names): p, = ax.plot(self.times, self.cell_intensities[index], "o", color=self.cell_colors[index]) p, = ax.plot(self.times, I[:, index] / self.cell_areas[index], "-", color=self.cell_colors[index]) plots.append(p) ax.set_xlabel("time (s)") ax.set_ylabel("mean intensity") ax.legend(plots, self.cell_names) self.plot_diffusion.figure.tight_layout() self.plot_diffusion.figure.canvas.draw() def run(self, start_frame=0): self.progressbar.setRange(0, 0) self.cp.window.app.processEvents() print("---- Building Model ----") self.ModelCost, self.Model = GetModel( self.times, np.array(self.cell_intensities).T * np.array(self.cell_areas), self.link_pairs, len(self.cell_names), self.cell_areas) # random starting values p = np.random.rand(len(self.link_pairs) + 1) * 5 + 20 # find best diffusion constants print("---- Minimize Model ----") res = minimize(self.ModelCost, p, method='L-BFGS-B', jac=True, options={ 'disp': True, 'maxiter': int(1e5) }, bounds=((0, None), ) * len(p)) self.diffusionConstants = res['x'] print("---- Plot Model ----") self.updateTable() self.updateDiffusionPlot() self.progressbar.setRange(0, 100) def buttonPressedEvent(self): self.updateIntensities() self.show()