Update to support i18n & logging

- Add --log-file option
- Add internationalization support with gettext
- Add logging featur
- Remove verbosity flag
- Update string formatting
- Fix Plate::set_border method
This commit is contained in:
linarphy 2023-08-25 17:24:12 +02:00
parent d51bd3ec9c
commit 8b604d8ae2
No known key found for this signature in database
GPG key ID: 3D4AAAC3AD16E79C

View file

@ -1,7 +1,13 @@
from numpy import ndarray, argmax, max, quantile, arange, where, convolve, ones from numpy import ndarray, gradient, ones, argmax, arange, arctan, tan
from scipy.optimize import curve_fit from scipy.optimize import curve_fit
from scipy.signal import convolve
from cv2 import getRotationMatrix2D, warpAffine, INTER_NEAREST
from classes.science.border import Border from classes.science.border import Border
from function.utils import find_point, fill from function.utils import find_point, fill
from function.fit import linear
from logging import getLogger
from gettext import gettext as _
class Plate: class Plate:
""" """
@ -10,15 +16,17 @@ class Plate:
def __init__( self , data ): def __init__( self , data ):
if not isinstance( data , ndarray ): if not isinstance( data , ndarray ):
raise TypeError( 'data must be a ndarray' ) raise TypeError( _( 'data must be a ndarray' ) )
if len( data.shape ) != 2:
raise ValueError( _( 'data must be a 2d matrix' ) )
self.data = data self.data = data
self.set_border() self.set_border()
def set_border( self , factor = 10 ): def set_border( self ):
""" """
Set current border (without area outside the plate) Set current border (without area outside the plate)
""" """
compressed = self.compress( factor ) compressed , factor = self.compress()
points = self.get_points( compressed ) points = self.get_points( compressed )
self.border = Border() self.border = Border()
@ -39,24 +47,45 @@ class Plate:
taken_points = fill( taken_points = fill(
compressed, compressed,
point , point ,
1000 , # intensity threshold 2000 , # intensity threshold
) )
x = [ taken_point[1] for taken_point in taken_points ] x = [ taken_point[1] for taken_point in taken_points ]
y = [ taken_point[0] for taken_point in taken_points ] y = [ taken_point[0] for taken_point in taken_points ]
if max( x ) < x_half: """
if self.border.x.min < max( x ): matrix = ones( compressed.shape )
self.border.x.min = max( x ) # biggest min for taken_point in taken_points:
elif min( x ) > x_half: # elif to only accept one side matrix[ taken_point[0] , taken_point[1] ] = 0
if self.border.x.max > min( x ): import matplotlib.pyplot as plt
self.border.x.max = min( x ) # smallest max plt.plot(
elif max( y ) < y_half: [ point[1] ] ,
if self.border.y.min < max( y ): [ point[0] ] ,
self.border.y.min = max( y ) # same linestyle = '' ,
elif min( y ) > y_half: marker = 'x' ,
if self.border.y.max > min( y ): markersize = 15 ,
self.border.y.max = min( y ) # same markeredgecolor = 'red',
markeredgewidth = 5 ,
)
plt.imshow( compressed , aspect = 'auto' )
plt.imshow( matrix , aspect = 'auto' , alpha = 0.5 )
plt.show()
"""
if len( x ) > 5 and len( y ) > 5:
if max( x ) < x_half:
if self.border.x.min < max( x ):
self.border.x.min = max( x ) # biggest min
elif min( x ) > x_half:
# elif to only accept one side
if self.border.x.max > min( x ):
self.border.x.max = min( x ) # smallest max
elif max( y ) < y_half:
if self.border.y.min < max( y ):
self.border.y.min = max( y ) # same
elif min( y ) > y_half:
if self.border.y.max > min( y ):
self.border.y.max = min( y ) # same
offset = 3 offset = 3
@ -116,36 +145,93 @@ class Plate:
return first_column + last_column + first_line + last_line return first_column + last_column + first_line + last_line
def compress( self , factor ): def compress( self ):
"""
Compress the plate data to fit the biggest dimension in a 1000
pixels axis and the smallest in a 100 pixels axis at minimum.
Return the compressed data and the compression factor used.
"""
min_factor = max( self.data.shape ) // 1000 # min factor to have a side
# with a maximum of 1000 pixels
max_factor = min( self.data.shape ) // 100 # max factor to have
# a side with a minimum of 100 pixel
if min_factor < max_factor:
factor = int( mean( ( max_factor , min_factor ) ) )
else: # the smallest side will be less than 100 pixels with the
# minimum compression factor
logger = getLogger( 'naroo reader' )
logger.warning(
_( (
'slow compression: ratio between height and width'
' is greater than 10 ({ratio:.2f})'
) ).format(
ratio = max( self.size() ) / min( self.size() )
)
)
factor = max_factor
return self.data[ return self.data[
: : factor, : : factor,
: : factor, : : factor,
] ] , factor
def middle( self ):
"""
Get coordinate of center
"""
return (
self.size()[0] // 2,
self.size()[1] // 2,
)
def rotate( self ): def rotate( self ):
""" """
Auto-rotate to be vertically and horizontally aligned Auto-rotate to be vertically and horizontally aligned
""" """
maxes = max( indexes_max = argmax(
self.data[ self.border.slice() ], convolve(
axis = 0 , self.data[
) 1 * self.border.y.size() // 4:
indexes = where( 3 * self.border.y.size() // 4,
maxes > quantile( maxes , 0.5 ) 1 * self.border.x.size() // 4:
3 * self.border.x.size() // 4
] ,
ones( ( 500 , 1 ) ),
'valid' ,
) ,
axis = 0,
) )
abciss = arange( abciss = arange(
self.border.x.min, 1 * self.border.x.size() // 4,
self.border.x.max 3 * self.border.x.size() // 4
)[ indexes ] )
indexes_max = argmax( fit_result = curve_fit(
self.data[ self.border.slice() ], linear ,
axis = 0 , abciss ,
)[ indexes ] indexes_max,
indexes_max = convolve( )[0]
indexes_max ,
ones( 100 ) , angle = arctan( fit_result[0] ) # rad
'same' , diff = int( # adjust height border
) / 100 tan( angle ) * ( self.border.x.size() )
import matplotlib.pyplot as plt )
plt.plot( abciss , indexes_max )
plt.show() rotation_matrix = getRotationMatrix2D(
self.middle(),
angle ,
1 ,
)
self.data = warpAffine(
self.data ,
rotation_matrix,
self.size() ,
flags = INTER_NEAREST,
)
self.border.y.min -= diff
self.border.y.max -= diff
def size( self ):
"""
get plate size
"""
return self.data.shape