1+ import sys
2+ from pathlib import Path
3+ import os .path
4+ import pyqtgraph as pg
5+ from pyqtgraph .Qt import QtCore , QtGui , QtWidgets #, QColorDialog
6+ import numpy as np
7+ import matplotlib .pyplot as plt
8+ from PIL import Image
9+
10+ # local modules
11+
12+ pg .mkQApp ()
13+
14+ base_path = Path (__file__ ).parent
15+ file_path = (base_path / "image_analysis_gui.ui" ).resolve ()
16+
17+ uiFile = file_path
18+
19+ WindowTemplate , TemplateBaseClass = pg .Qt .loadUiType (uiFile )
20+
21+ class MainWindow (TemplateBaseClass ):
22+
23+ def __init__ (self ):
24+ super (TemplateBaseClass , self ).__init__ ()
25+
26+ # Create the main window
27+ self .ui = WindowTemplate ()
28+ self .ui .setupUi (self )
29+
30+ #setup imageview
31+ self .imv = pg .ImageView ()
32+ self .imv .getView ().setAspectLocked (lock = False , ratio = 1 )
33+ self .imv .getView ().setMouseEnabled (x = True , y = True )
34+ self .imv .getView ().invertY (False )
35+ self .roi = self .imv .roi
36+ self .roi .translateSnap = True
37+ self .roi .scaleSnap = True
38+ self .calc_scaling_factor () #initialize scaling_factor
39+ self .roi .snapSize = self .scaling_factor #roi snaps to multiples of scaling_factor
40+ self .roi .sigRegionChanged .connect (self .line_profile_update_plot )
41+ self .roi_plot = self .imv .getRoiPlot ().getPlotItem ()
42+
43+ self .ui .image_groupBox .layout ().addWidget (self .imv )
44+
45+ #set up ui signals
46+ self .ui .load_image_pushButton .clicked .connect (self .load_image )
47+ self .ui .custom_pixel_size_checkBox .stateChanged .connect (self .switch_custom_pixel_size )
48+
49+ self .show ()
50+
51+ def load_image (self ):
52+ """
53+ Prompts the user to select a text file containing image data.
54+ """
55+ try :
56+ file = QtWidgets .QFileDialog .getOpenFileName (self , 'Open file' , os .getcwd ())
57+ image = Image .open (file [0 ])
58+ image = image .rotate (- 90 , expand = True )
59+ image_array = np .asarray (image )
60+ try :
61+ width = image_array .shape [0 ]
62+ height = image_array .shape [1 ]
63+ x_vals = np .arange (width )
64+ self .imv .setImage (img = image_array , xvals = x_vals )
65+ self .calc_scaling_factor ()
66+ self .roi .setPos ((0 ,0 ))
67+ self .roi .setSize ([width , height * self .scaling_factor ]) #set line roi
68+ self .line_profile_update_plot ()
69+ except :
70+ pass
71+ except Exception as err :
72+ print (format (err ))
73+
74+ def line_profile_update_plot (self ):
75+ """ Handle line profile for intensity sum viewbox """
76+ #if hasattr(self, "intensity_sums"):
77+ self .roi_plot .clear ()
78+
79+ image = self .imv .getProcessedImage ()
80+
81+ # Extract image data from ROI
82+ axes = (self .imv .axes ['x' ], self .imv .axes ['y' ])
83+ data , coords = self .roi .getArrayRegion (image .view (np .ndarray ), self .imv .imageItem , axes , returnMappedCoords = True )
84+ if data is None :
85+ return
86+
87+ self .calc_scaling_factor ()
88+ x_values = coords [1 ][0 ] * self .scaling_factor #adjust x-axis roi plot
89+
90+ #calculate sums along columns in region
91+ if len (data .shape ) == 2 : #if grayscale, average intensities
92+ sums_to_plot = np .mean (data , axis = 0 )
93+ try :
94+ self .roi_plot .plot (x_values , sums_to_plot )
95+ except :
96+ pass
97+ elif len (data .shape ) > 2 : #if rgb arrays, plot individual components
98+ r_values = data [:,:,0 ]
99+ g_values = data [:,:,1 ]
100+ b_values = data [:,:,2 ]
101+ r_avg = np .mean (r_values , axis = 0 ) #average red values across columns
102+ g_avg = np .mean (g_values , axis = 0 ) #average green values
103+ b_avg = np .mean (b_values , axis = 0 ) #average blue values
104+ try :
105+ self .roi_plot .plot (x_values , r_avg , pen = 'r' )
106+ self .roi_plot .plot (x_values , g_avg , pen = 'g' )
107+ self .roi_plot .plot (x_values , b_avg , pen = 'b' )
108+ except :
109+ pass
110+
111+ def calc_scaling_factor (self ):
112+ """
113+ Calculate scaling factor
114+ """
115+ if self .ui .custom_pixel_size_checkBox .isChecked ():
116+ self .scaling_factor = self .ui .custom_pixel_size_spinBox .value ()
117+ else :
118+ pixel_size = 7.4
119+ self .scaling_factor = pixel_size / int (self .ui .magnification_comboBox .currentText ())
120+
121+ def switch_custom_pixel_size (self ):
122+ checked = self .ui .custom_pixel_size_checkBox .isChecked ()
123+ self .ui .custom_pixel_size_spinBox .setEnabled (checked )
124+ self .ui .magnification_comboBox .setEnabled (not checked )
125+
126+ def close_application (self ):
127+ choice = QtGui .QMessageBox .question (self , 'EXIT!' ,
128+ "Do you want to exit the app?" ,
129+ QtGui .QMessageBox .Yes | QtGui .QMessageBox .No )
130+ if choice == QtGui .QMessageBox .Yes :
131+ sys .exit ()
132+ else :
133+ pass
134+
135+ """Run the Main Window"""
136+ def run ():
137+ win = MainWindow ()
138+ QtGui .QApplication .instance ().exec_ ()
139+ return win
140+
141+ #Uncomment below if you want to run this as standalone
142+ #run()
0 commit comments