@@ -73,6 +73,21 @@ class BpmDeviceServer(BasePostProcess):
7373#--------- Add you global variables here --------------------------
7474 BPM_TASK_NAME = "BpmTask"
7575 BVDATA_TASK_NAME = "BVDataTask"
76+
77+ ImageType2Bpp = {
78+ Core .Bpp8 : 8 ,
79+ Core .Bpp10 : 10 ,
80+ Core .Bpp12 : 12 ,
81+ Core .Bpp14 : 14 ,
82+ Core .Bpp16 : 16 ,
83+ Core .Bpp32 : 32 ,
84+ Core .Bpp8S : 7 ,
85+ Core .Bpp10S : 9 ,
86+ Core .Bpp12S : 11 ,
87+ Core .Bpp14S : 13 ,
88+ Core .Bpp16S : 15 ,
89+ Core .Bpp32S : 31 ,
90+ }
7691#------------------------------------------------------------------
7792# Device constructor
7893#------------------------------------------------------------------
@@ -86,6 +101,9 @@ def __init__(self,cl, name):
86101
87102 self .palette = self .init_palette ()
88103
104+ # initialize min max for image scaling
105+ #self.min_max = [0, 2**(self.ImageType2Bpp[_control_ref().image().getImageType()])]
106+
89107 BasePostProcess .__init__ (self ,cl ,name )
90108 self .init_device ()
91109
@@ -189,10 +207,10 @@ def getResults(self, from_index=0) :
189207 for i ,r in enumerate (results ):
190208 result_array [i ][0 ] = r .timestamp
191209 result_array [i ][1 ] = self .validate_number (r .beam_intensity )
192- result_array [i ][2 ] = self .validate_number (r .beam_center_x , max_value = max_width )
193- result_array [i ][3 ] = self .validate_number (r .beam_center_y , max_value = max_height )
194- result_array [i ][4 ] = self .validate_number (r .beam_fwhm_x , fallback_value = 0 )
195- result_array [i ][5 ] = self .validate_number (r .beam_fwhm_y , fallback_value = 0 )
210+ result_array [i ][2 ] = self .validate_number (r .beam_center_x , max_value = max_width ) * self . calibration [ 0 ]
211+ result_array [i ][3 ] = self .validate_number (r .beam_center_y , max_value = max_height ) * self . calibration [ 1 ]
212+ result_array [i ][4 ] = self .validate_number (r .beam_fwhm_x , fallback_value = 0 ) * self . calibration [ 0 ]
213+ result_array [i ][5 ] = self .validate_number (r .beam_fwhm_y , fallback_value = 0 ) * self . calibration [ 1 ]
196214 result_array [i ][6 ] = r .frameNumber
197215 return result_array .ravel ()
198216
@@ -205,7 +223,6 @@ def GetPixelIntensity(self, coordinate):
205223 except :
206224 return - 1
207225
208- ##############BACKGROUND : work through bpm device commande.
209226 def TakeBackground (self ):
210227 ctControl = _control_ref ()
211228 extOpt = ctControl .externalOperation ()
@@ -344,8 +361,11 @@ def write_lut_method(self,attr):
344361 prop = {'lut_method' : data }
345362 PyTango .Database ().put_device_property (self .get_name (), prop )
346363
347- else :
348- print ("wrong lut method, 'LINEAR' or 'LOG'" )
364+ else :
365+ PyTango .Except .throw_exception ('WrongData' ,\
366+ f'Wrong value lut_method: { data } , use log or linear instead' ,
367+ 'LimaCCD Class' )
368+
349369
350370 def is_lut_method_allowed (self ,mode ) :
351371 return True
@@ -413,6 +433,48 @@ def read_bvdata(self,attr):
413433
414434 attr .set_value (self .bvdata_format ,self .bvdata )
415435
436+ def read_min_max (self ,attr ):
437+ attr .set_value (self .min_max )
438+
439+ def write_min_max (self , attr ):
440+ data = attr .get_write_value ()
441+ max = 2 ** (self .ImageType2Bpp [_control_ref ().image ().getImageType ()])
442+ range = [0 , max ]
443+ #reset asked to default
444+ if data [0 ] == 0 and data [1 ] == 0 :
445+ data [1 ] = max
446+
447+ if data [0 ] > data [1 ]:
448+ PyTango .Except .throw_exception ('WrongData' ,\
449+ f'Wrong values min_max: { data } , max < min' ,
450+ 'LimaCCD Class' )
451+
452+ if data [0 ] > max or data [1 ] > max :
453+ PyTango .Except .throw_exception ('WrongData' ,\
454+ f'Wrong value min_max: { data } , out of range { range } ' ,
455+ 'LimaCCD Class'
456+ )
457+ self .min_max [0 ] = data [0 ]
458+ self .min_max [1 ] = data [1 ]
459+ #update the property
460+ prop = {'min_max' : data }
461+ PyTango .Database ().put_device_property (self .get_name (), prop )
462+
463+ def is_min_max_allowed (self ,mode ) :
464+ return True
465+
466+ def read_return_bpm_profiles (self ,attr ):
467+ attr .set_value (self .return_bpm_profiles )
468+
469+ def write_return_bpm_profiles (self ,attr ):
470+ data = attr .get_write_value ()
471+ self .return_bpm_profiles = data
472+ #update the property
473+ prop = {'return_bpmpylon/PylonBase.h_profiles' : data }
474+ PyTango .Database ().put_device_property (self .get_name (), prop )
475+
476+ def is_return_bpm_profiles_allowed (self ,mode ) :
477+ return True
416478
417479#==================================================================
418480#
@@ -455,7 +517,15 @@ class BpmDeviceServerClass(PyTango.DeviceClass):
455517 'jpeg_quality' :
456518 [PyTango .DevLong ,
457519 "Set jpeg encoding quality from 1-100" ,
458- 80 ]
520+ 80 ],
521+ 'return_bpm_profiles' :
522+ [PyTango .DevBoolean ,
523+ "return bpm profiles if True, otherwise the beammark profiles" ,
524+ True ],
525+ "min_max" :
526+ [PyTango .DevVarLongArray ,
527+ "min/max value for manual scaling" ,
528+ [0 ,65535 ] ],
459529 }
460530
461531
@@ -505,7 +575,9 @@ class BpmDeviceServerClass(PyTango.DeviceClass):
505575 'bvdata' :[[PyTango .DevEncoded , PyTango .SCALAR , PyTango .READ ]],
506576 'calibration' : [[PyTango .DevDouble , PyTango .SPECTRUM , PyTango .READ_WRITE , 2 ]],
507577 'beammark' : [[PyTango .DevLong , PyTango .SPECTRUM , PyTango .READ_WRITE , 2 ]],
508- 'jpeg_quality' : [[PyTango .DevLong , PyTango .SCALAR , PyTango .READ_WRITE ]]
578+ 'jpeg_quality' : [[PyTango .DevLong , PyTango .SCALAR , PyTango .READ_WRITE ]],
579+ 'min_max' : [[PyTango .DevULong64 , PyTango .SPECTRUM , PyTango .READ_WRITE , 2 ]],
580+ 'return_bpm_profiles' : [[PyTango .DevBoolean , PyTango .SCALAR , PyTango .READ_WRITE ]],
509581 }
510582
511583
@@ -581,26 +653,23 @@ def construct_bvdata(bpm):
581653 jpegFile = StringIO ()
582654 image_type = _control_ref ().image ().getImageType ()
583655
584- if image_type == 0 : #Bpp8
585- bpp = 8
586- elif image_type == 2 : #Bpp10
587- bpp = 10
588- elif image_type == 4 : #Bpp12
589- bpp = 12
590- elif image_type == 6 : #Bpp14
591- bpp = 14
592- elif image_type == 8 : #Bpp16
593- bpp = 16
594- elif image_type == 16 : #Bpp24
595- bpp = 24
596- elif image_type == 10 : #Bpp32
597- bpp = 32
598-
599- min_val = image .buffer .min ()
600- max_val = image .buffer .max ()
601-
602- scale_image = image .buffer
656+ bpp = bpm .ImageType2Bpp [image_type ]
657+
658+ # manual scaling: use the user image min/max intensity to filter
659+ if not bpm .autoscale :
660+ min_val = bpm .min_max [0 ]
661+ max_val = bpm .min_max [1 ]
662+ if max_val == 0 : max_val = 1
663+ scale_image = image .buffer .clip (min_val , max_val )
603664
665+ # auto scaling: use natural image intensity
666+ else :
667+ min_val = image .buffer .min ()
668+ max_val = image .buffer .max ()
669+ if max_val == 0 : max_val = 1
670+ scale_image = image .buffer
671+
672+ # logarithmic scaling
604673 if bpm .lut_method == "LOG" :
605674 if min_val > 0 :
606675 scale_image = numpy .log10 (scale_image )
@@ -610,19 +679,12 @@ def construct_bvdata(bpm):
610679 min_val = numpy .log10 (min_val )
611680 max_val = numpy .log10 (max_val if max_val > 0 else 1 )
612681
613- if bpm .autoscale or bpm .lut_method == "LOG" :
614- scaling = (2 ** 16 - 1. ) / (max_val - min_val )
615- scale_image = ((scale_image - min_val ) * scaling ).astype (numpy .uint16 )
616- else :
617- shift = bpp - 16
618- if shift > 0 :
619- scale_image = numpy .right_shift (scale_image , shift ).astype (numpy .uint16 )
620- elif shift < 0 :
621- scale_image = numpy .left_shift (scale_image , - shift ).astype (numpy .uint16 )
622- else :
623- scale_image = scale_image .astype (numpy .uint16 )
682+ # scale the image to the whole range 16bit before palette transformation for 0 to 65535
683+ scaling = (2 ** 16 - 1. ) / (max_val - min_val )
684+ scale_image = ((scale_image - min_val ) * scaling ).astype (numpy .uint16 )
624685
625- if bpm .color_map == True :
686+ # last transformation ot color or greys palette
687+ if bpm .color_map :
626688 img_buffer = bpm .palette ["color" ].take (scale_image , axis = 0 )
627689 else :
628690 img_buffer = bpm .palette ["grey" ].take (scale_image , axis = 0 )
@@ -635,9 +697,17 @@ def construct_bvdata(bpm):
635697
636698 raw_jpeg_data = jpegFile .getvalue ()
637699 image_jpeg = base64 .b64encode (raw_jpeg_data )
638- profil_x = last_proj_x .tobytes ()
639- profil_y = last_proj_y .tobytes ()
640- bvdata_format = 'dldddliiiidd%ds%ds%ds' % (len (profil_x ),len (profil_y ),len (image_jpeg ))
700+ if bpm .return_bpm_profiles :
701+ profile_x = last_proj_x .tobytes ()
702+ profile_y = last_proj_y .tobytes ()
703+ else :
704+ profile_x = image .buffer [:,bpm .beammark [0 ]].astype (numpy .uint64 )
705+ profile_x = profile_x .tobytes ()
706+ profile_y = image .buffer [bpm .beammark [1 ],:].astype (numpy .uint64 )
707+ profile_y = profile_y .tobytes ()
708+
709+
710+ bvdata_format = 'dldddliiiidd%ds%ds%ds' % (len (profile_x ),len (profile_y ),len (image_jpeg ))
641711 bvdata = struct .pack (
642712 bvdata_format ,
643713 last_acq_time ,
@@ -652,8 +722,8 @@ def construct_bvdata(bpm):
652722 roi_size .getHeight (),
653723 last_fwhm_x ,
654724 last_fwhm_y ,
655- profil_x ,
656- profil_y ,
725+ profile_x ,
726+ profile_y ,
657727 image_jpeg )
658728 return bvdata , bvdata_format
659729
0 commit comments