66"""
77
88from PyQt5 .QtWidgets import QCheckBox , QPushButton , QLabel , QMainWindow , QSpinBox
9- from PyQt5 .QtWidgets import QApplication , QWidget , QVBoxLayout , QComboBox
10- from PyQt5 .QtGui import QPixmap , QImage
9+ from PyQt5 .QtWidgets import QApplication , QWidget , QHBoxLayout , QComboBox , QTabWidget
10+ from PyQt5 .QtWidgets import QVBoxLayout
11+ from PyQt5 .QtGui import QPixmap , QImage , QColor , QPainter , QBitmap
1112from PyQt5 .QtCore import Qt
1213import sys
1314
1415import inspect
1516import numpy as np
16- from skimage .segmentation import mark_boundaries
17+ from skimage .segmentation import mark_boundaries , flood_fill
1718from skimage .util import invert
19+ import matplotlib .pyplot as plt
20+ from PIL import Image
1821
1922from ParticleSpy .segptcls import process
2023from ParticleSpy .ParticleAnalysis import parameters
@@ -33,47 +36,55 @@ def __init__(self,im_hs):
3336 self .prev_params .generate ()
3437
3538 offset = 50
39+
40+ self .layout = QHBoxLayout (self )
41+
42+ # Initialize tab screen
43+ self .tabs = QTabWidget ()
44+ self .tab1 = QWidget ()
45+ self .tab2 = QWidget ()
46+
47+ # Add tabs
48+ self .tabs .addTab (self .tab1 ,"Auto" )
49+ self .tabs .addTab (self .tab2 ,"Manual" )
3650
3751 #self.central_widget = QWidget()
3852 #self.setCentralWidget(self.central_widget)
39- lay = QVBoxLayout ()
53+ lay = QHBoxLayout ()
54+ leftlay = QVBoxLayout ()
55+ rightlay = QVBoxLayout ()
56+ self .tab1 .setLayout (lay )
4057
4158 self .label = QLabel (self )
4259 qi = QImage (self .image .data , self .image .shape [1 ], self .image .shape [0 ], self .image .shape [1 ], QImage .Format_Grayscale8 )
4360 pixmap = QPixmap (qi )
44- pixmap2 = pixmap .scaled (512 , 512 , Qt .KeepAspectRatio )
45- self .label .setPixmap (pixmap2 )
46- self .label .setGeometry (10 ,10 ,pixmap2 .width (),pixmap2 .height ())
61+ self . pixmap2 = pixmap .scaled (512 , 512 , Qt .KeepAspectRatio )
62+ self .label .setPixmap (self . pixmap2 )
63+ self .label .setGeometry (10 ,10 ,self . pixmap2 .width (),self . pixmap2 .height ())
4764
48- height = max ((pixmap2 .height ()+ 50 ,300 + offset )) #300 +50
65+ height = max ((self . pixmap2 .height ()+ 50 ,300 + offset )) #300 +50
4966
50- self .resize (pixmap2 .width ()+ 130 , height )
67+ self .resize (self . pixmap2 .width ()+ 130 , height )
5168
5269 self .filt_title = QLabel (self )
5370 self .filt_title .setText ('Pre-filtering options' )
54- self .filt_title .move (pixmap2 .width ()+ 20 , 0 )
5571
5672 self .sptxt = QLabel (self )
5773 self .sptxt .setText ('Rolling ball size' )
58- self .sptxt .move (pixmap2 .width ()+ 20 ,20 )
5974
6075 self .sp = QSpinBox (self )
6176 self .sp .setMaximum (self .image .shape [0 ])
6277 self .sp .valueChanged .connect (self .rollingball )
63- self .sp .move (pixmap2 .width ()+ 20 , 45 )
6478
6579 self .gausstxt = QLabel (self )
6680 self .gausstxt .setText ('Gaussian filter kernel size' )
67- self .gausstxt .move (pixmap2 .width ()+ 20 ,70 )
6881
6982 self .gauss = QSpinBox (self )
7083 self .gauss .setMaximum (self .image .shape [0 ])
7184 self .gauss .valueChanged .connect (self .gaussian )
72- self .gauss .move (pixmap2 .width ()+ 20 , 95 )
7385
7486 self .thresh_title = QLabel (self )
7587 self .thresh_title .setText ('Thresholding options' )
76- self .thresh_title .move (pixmap2 .width ()+ 20 , 135 )
7788
7889 self .comboBox = QComboBox (self )
7990 self .comboBox .addItem ("Otsu" )
@@ -85,65 +96,90 @@ def __init__(self,im_hs):
8596 self .comboBox .addItem ("Local" )
8697 self .comboBox .addItem ("Local Otsu" )
8798 self .comboBox .addItem ("Local+Global Otsu" )
88- self .comboBox .move (pixmap2 .width ()+ 20 , 160 )
8999 self .comboBox .activated [str ].connect (self .threshold_choice )
90100
91101 self .localtxt = QLabel (self )
92102 self .localtxt .setText ('Local filter kernel' )
93- self .localtxt .move (pixmap2 .width ()+ 20 ,195 )
94103
95104 self .local_size = QSpinBox (self )
96105 self .local_size .setMaximum (self .image .shape [0 ])
97106 self .local_size .valueChanged .connect (self .local )
98- self .local_size .move (pixmap2 .width ()+ 20 , 220 )
99107
100108 cb = QCheckBox ('Watershed' , self )
101- cb .move (pixmap2 .width ()+ 20 , 260 )
102109 cb .stateChanged .connect (self .changeWatershed )
103110
104111 cb2 = QCheckBox ('Invert' , self )
105- cb2 .move (pixmap2 .width ()+ 20 , 260 + offset / 2 )
106112 cb2 .stateChanged .connect (self .changeInvert )
107113
108114 self .minsizetxt = QLabel (self )
109115 self .minsizetxt .setText ('Min particle size (px)' )
110- self .minsizetxt .move (pixmap2 .width ()+ 20 , 280 + offset )
111116
112117 self .minsizev = QSpinBox (self )
113118 self .minsizev .setMaximum (self .image .shape [0 ]* self .image .shape [1 ])
114119 self .minsizev .valueChanged .connect (self .minsize )
115- self .minsizev .move (pixmap2 .width ()+ 20 , 305 + offset )
116120
117121 updateb = QPushButton ('Update' ,self )
118- updateb .move (pixmap2 .width ()+ 20 ,355 + offset )
119122 updateb .clicked .connect (self .update )
120123
121124 paramsb = QPushButton ('Get Params' ,self )
122- paramsb .move (pixmap2 .width ()+ 20 ,385 + offset )
123125
124126 paramsb .clicked .connect (self .return_params )
125127
126128 self .imagetxt = QLabel (self )
127129 self .imagetxt .setText ('Display:' )
128- self .imagetxt .move (75 , pixmap2 .height ()+ 15 )
129130
130131 self .imBox = QComboBox (self )
131132 self .imBox .addItem ("Image" )
132133 self .imBox .addItem ("Labels" )
133- self .imBox .move (pixmap2 .width ()/ 2 - 10 , pixmap2 .height ()+ 15 )
134134
135135 self .imBox .activated [str ].connect (self .changeIm )
136+
137+ leftlay .addWidget (self .label )
138+ leftlay .addWidget (self .imagetxt )
139+ leftlay .addWidget (self .imBox )
140+
141+ rightlay .addWidget (self .filt_title )
142+ rightlay .addWidget (self .sptxt )
143+ rightlay .addWidget (self .sp )
144+ rightlay .addWidget (self .gausstxt )
145+ rightlay .addWidget (self .gauss )
146+ rightlay .addStretch (1 )
147+ rightlay .addWidget (self .thresh_title )
148+ rightlay .addWidget (self .comboBox )
149+ rightlay .addStretch (1 )
150+ rightlay .addWidget (self .localtxt )
151+ rightlay .addWidget (self .local_size )
152+ rightlay .addStretch (1 )
153+ rightlay .addWidget (cb )
154+ rightlay .addWidget (cb2 )
155+ rightlay .addStretch (1 )
156+ rightlay .addWidget (self .minsizetxt )
157+ rightlay .addWidget (self .minsizev )
158+ rightlay .addStretch (2 )
159+ rightlay .addWidget (updateb )
160+ rightlay .addWidget (paramsb )
161+
162+ lay .addLayout (leftlay )
163+ lay .addLayout (rightlay )
164+
165+ self .layout .addWidget (self .tabs )
166+ self .setLayout (self .layout )
167+
168+ self .setCentralWidget (self .tabs )
169+
170+ #Tab 2
171+ self .canvas = Canvas (self .pixmap2 )
172+ #self.canvas = Drawer(self.pixmap2)
173+
174+ self .getarrayb = QPushButton ('Save Segmentation' ,self )
175+ self .getarrayb .clicked .connect (self .save_array )
176+
177+ tab2layout = QVBoxLayout ()
178+ tab2layout .addWidget (self .canvas )
179+ tab2layout .addWidget (self .getarrayb )
180+ tab2layout .addStretch (1 )
181+ self .tab2 .setLayout (tab2layout )
136182
137- lay .addWidget (self .thresh_title )
138- lay .addWidget (self .filt_title )
139- lay .addWidget (self .label )
140- lay .addWidget (self .comboBox )
141- lay .addWidget (self .sp )
142- lay .addWidget (self .sptxt )
143- lay .addWidget (self .gauss )
144- lay .addWidget (self .gausstxt )
145- lay .addWidget (self .imagetxt )
146- lay .addWidget (self .minsizev )
147183 self .show ()
148184
149185 def getim (self ,im_hs ):
@@ -179,8 +215,8 @@ def changeInvert(self, state):
179215 qi = QImage (self .image .data , self .image .shape [1 ], self .image .shape [0 ], self .image .shape [1 ], QImage .Format_Indexed8 )
180216
181217 pixmap = QPixmap (qi )
182- pixmap2 = pixmap .scaled (512 , 512 , Qt .KeepAspectRatio )
183- self .label .setPixmap (pixmap2 )
218+ self . pixmap2 = pixmap .scaled (512 , 512 , Qt .KeepAspectRatio )
219+ self .label .setPixmap (self . pixmap2 )
184220
185221 def rollingball (self ):
186222 if self .sp .value () == 1 :
@@ -254,7 +290,78 @@ def threshold_choice(self):
254290 self .params .segment ['threshold' ] = "local_otsu"
255291 if str (self .comboBox .currentText ()) == "Local+Global Otsu" :
256292 self .params .segment ['threshold' ] = "lg_otsu"
293+
294+ def save_array (self ):
295+ self .canvas .savearray (self .image )
296+
297+
298+ class Canvas (QLabel ):
299+
300+ def __init__ (self ,pixmap ):
301+ super ().__init__ ()
302+ self .setPixmap (pixmap )
303+
304+ self .last_x , self .last_y = None , None
305+ self .pen_color = QColor (255 , 0 , 0 , 20 )
306+
307+ def set_pen_color (self , c ):
308+ self .pen_color = QColor (c )
309+
310+ def mousePressEvent (self , e ):
311+ if e .button () == Qt .RightButton :
312+ image = self .pixmap ().toImage ()
313+ b = image .bits ()
314+ b .setsize (512 * 512 * 4 )
315+ arr = np .frombuffer (b , np .uint8 ).reshape ((512 , 512 , 4 ))
316+
317+ arr_test = arr [:,:,0 ]/ arr [:,:,2 ]
318+
319+ painted_arr = np .zeros_like (arr [:,:,0 :3 ])
320+ painted_arr [:,:,2 ][arr_test != 1 ] = 255
321+
322+ painted_arr [:,:,2 ] = flood_fill (painted_arr [:,:,2 ],(e .y (),e .x ()),255 )
323+
324+ qi = QImage (painted_arr .data , painted_arr .shape [1 ], painted_arr .shape [0 ], 3 * painted_arr .shape [1 ], QImage .Format_RGB888 )
325+ pixmap = QPixmap (qi )
326+
327+ painter = QPainter (self .pixmap ())
328+ painter .setOpacity (0.01 )
329+
330+ painter .drawPixmap (0 , 0 , pixmap )
331+ painter .end ()
332+ self .update ()
333+
334+ self .array = painted_arr [:,:,2 ]
335+
336+ def mouseMoveEvent (self , e ):
337+ if e .buttons () == Qt .LeftButton :
338+ if self .last_x is None : # First event.
339+ self .last_x = e .x ()
340+ self .last_y = e .y ()
341+ return # Ignore the first time.
342+
343+ painter = QPainter (self .pixmap ())
344+ p = painter .pen ()
345+ p .setWidth (4 )
346+ p .setColor (self .pen_color )
347+ painter .setPen (p )
348+ painter .drawLine (self .last_x , self .last_y , e .x (), e .y ())
349+ painter .end ()
350+ self .update ()
257351
352+ # Update the origin for next time.
353+ self .last_x = e .x ()
354+ self .last_y = e .y ()
355+
356+ def mouseReleaseEvent (self , e ):
357+ self .last_x = None
358+ self .last_y = None
359+
360+ def savearray (self ,image ):
361+ resized = np .array (Image .fromarray (self .array ).resize ((image .shape [0 ],image .shape [1 ])))
362+ np .save (inspect .getfile (process ).rpartition ('\\ ' )[0 ]+ '/Parameters/manual_mask' ,resized )
363+
364+
258365def main (haadf ):
259366
260367 ex = Application (haadf )
@@ -280,6 +387,9 @@ def SegUI(image):
280387 import hyperspy .api as hs
281388 filename = "Data/JEOL HAADF Image.dm4"
282389 haadf = hs .load (filename )
390+
391+ image_out = np .zeros_like (haadf )
392+
283393 app = QApplication (sys .argv )
284394 app .aboutToQuit .connect (app .deleteLater )
285395
0 commit comments