diff options
Diffstat (limited to 'utils/raspberrypi/ctt')
-rwxr-xr-x | utils/raspberrypi/ctt/ctt.py | 136 | ||||
-rw-r--r-- | utils/raspberrypi/ctt/ctt_alsc.py | 144 | ||||
-rw-r--r-- | utils/raspberrypi/ctt/ctt_awb.py | 118 | ||||
-rw-r--r-- | utils/raspberrypi/ctt/ctt_ccm.py | 52 | ||||
-rw-r--r-- | utils/raspberrypi/ctt/ctt_geq.py | 48 | ||||
-rw-r--r-- | utils/raspberrypi/ctt/ctt_image_load.py | 116 | ||||
-rw-r--r-- | utils/raspberrypi/ctt/ctt_lux.py | 16 | ||||
-rw-r--r-- | utils/raspberrypi/ctt/ctt_macbeth_locator.py | 240 | ||||
-rw-r--r-- | utils/raspberrypi/ctt/ctt_noise.py | 26 | ||||
-rw-r--r-- | utils/raspberrypi/ctt/ctt_ransac.py | 52 | ||||
-rw-r--r-- | utils/raspberrypi/ctt/ctt_tools.py | 38 |
11 files changed, 493 insertions, 493 deletions
diff --git a/utils/raspberrypi/ctt/ctt.py b/utils/raspberrypi/ctt/ctt.py index 5fe22e14..3674d310 100755 --- a/utils/raspberrypi/ctt/ctt.py +++ b/utils/raspberrypi/ctt/ctt.py @@ -41,15 +41,15 @@ def get_col_lux(string): """ Extract colour and lux values from filename """ - col = re.search('([0-9]+)[kK](\.(jpg|jpeg|brcm|dng)|_.*\.(jpg|jpeg|brcm|dng))$',string) - lux = re.search('([0-9]+)[lL](\.(jpg|jpeg|brcm|dng)|_.*\.(jpg|jpeg|brcm|dng))$',string) + col = re.search('([0-9]+)[kK](\.(jpg|jpeg|brcm|dng)|_.*\.(jpg|jpeg|brcm|dng))$', string) + lux = re.search('([0-9]+)[lL](\.(jpg|jpeg|brcm|dng)|_.*\.(jpg|jpeg|brcm|dng))$', string) try: col = col.group(1) except AttributeError: """ Catch error if images labelled incorrectly and pass reasonable defaults """ - return None,None + return None, None try: lux = lux.group(1) except AttributeError: @@ -57,15 +57,15 @@ def get_col_lux(string): Catch error if images labelled incorrectly and pass reasonable defaults Still returns colour if that has been found. """ - return col,None - return int( col ),int( lux ) + return col, None + return int( col ), int( lux ) """ Camera object that is the backbone of the tuning tool. Input is the desired path of the output json. """ class Camera: - def __init__(self,jfile): + def __init__(self, jfile): self.path = os.path.dirname(os.path.expanduser(__file__)) + '/' if self.path == '/': self.path = '' @@ -96,9 +96,9 @@ class Camera: }, "rpi.awb": { "priors" : [ - {"lux": 0,"prior":[ 2000, 1.0, 3000, 0.0, 13000, 0.0]}, - {"lux": 800,"prior":[ 2000, 0.0, 6000, 2.0, 13000, 2.0]}, - {"lux": 1500,"prior":[ 2000, 0.0, 4000, 1.0, 6000, 6.0, 6500, 7.0, 7000, 1.0, 13000, 1.0]} + {"lux": 0, "prior": [ 2000, 1.0, 3000, 0.0, 13000, 0.0]}, + {"lux": 800, "prior": [ 2000, 0.0, 6000, 2.0, 13000, 2.0]}, + {"lux": 1500, "prior": [ 2000, 0.0, 4000, 1.0, 6000, 6.0, 6500, 7.0, 7000, 1.0, 13000, 1.0]} ], "modes" : { "auto" : { "lo" : 2500, "hi" : 8000 }, @@ -189,7 +189,7 @@ class Camera: }, "rpi.ccm": { }, - "rpi.sharpen":{ + "rpi.sharpen": { } } @@ -198,7 +198,7 @@ class Camera: Perform colour correction calibrations by comparing macbeth patch colours to standard macbeth chart colours. """ - def ccm_cal(self,do_alsc_colour): + def ccm_cal(self, do_alsc_colour): if 'rpi.ccm' in self.disable: return 1 print('\nStarting CCM calibration') @@ -227,7 +227,7 @@ class Camera: cal_cb_list = self.json['rpi.alsc']['calibrations_Cb'] self.log += '\nALSC tables found successfully' except KeyError: - cal_cr_list,cal_cb_list=None,None + cal_cr_list, cal_cb_list=None, None print('WARNING! No ALSC tables found for CCM!') print('Performing CCM calibrations without ALSC correction...') self.log += '\nWARNING: No ALSC tables found.\nCCM calibration ' @@ -236,7 +236,7 @@ class Camera: """ case where config options result in CCM done without ALSC colour tables """ - cal_cr_list,cal_cb_list=None,None + cal_cr_list, cal_cb_list=None, None self.log += '\nWARNING: No ALSC tables found.\nCCM calibration ' self.log += 'performed without ALSC correction...' @@ -244,7 +244,7 @@ class Camera: Do CCM calibration """ try: - ccms = ccm(self,cal_cr_list,cal_cb_list) + ccms = ccm(self, cal_cr_list, cal_cb_list) except ArithmeticError: print('ERROR: Matrix is singular!\nTake new pictures and try again...') self.log += '\nERROR: Singular matrix encountered during fit!' @@ -262,7 +262,7 @@ class Camera: various colour temperatures, as well as providing a maximum 'wiggle room' distance from this curve (transverse_neg/pos). """ - def awb_cal(self,greyworld,do_alsc_colour): + def awb_cal(self, greyworld, do_alsc_colour): if 'rpi.awb' in self.disable: return 1 print('\nStarting AWB calibration') @@ -292,21 +292,21 @@ class Camera: cal_cb_list = self.json['rpi.alsc']['calibrations_Cb'] self.log += '\nALSC tables found successfully' except KeyError: - cal_cr_list,cal_cb_list=None,None + cal_cr_list, cal_cb_list=None, None print('ERROR, no ALSC calibrations found for AWB') print('Performing AWB without ALSC tables') self.log += '\nWARNING: No ALSC tables found.\nAWB calibration ' self.log += 'performed without ALSC correction...' else: - cal_cr_list,cal_cb_list=None,None + cal_cr_list, cal_cb_list=None, None self.log += '\nWARNING: No ALSC tables found.\nAWB calibration ' self.log += 'performed without ALSC correction...' """ call calibration function """ plot = "rpi.awb" in self.plot - awb_out = awb(self,cal_cr_list,cal_cb_list,plot) - ct_curve,transverse_neg,transverse_pos = awb_out + awb_out = awb(self, cal_cr_list, cal_cb_list, plot) + ct_curve, transverse_neg, transverse_pos = awb_out """ write output to json """ @@ -323,7 +323,7 @@ class Camera: colour channel seperately, and then partially corrects for vignetting. The extent of the correction depends on the 'luminance_strength' parameter. """ - def alsc_cal(self,luminance_strength,do_alsc_colour): + def alsc_cal(self, luminance_strength, do_alsc_colour): if 'rpi.alsc' in self.disable: return 1 print('\nStarting ALSC calibration') @@ -346,8 +346,8 @@ class Camera: call calibration function """ plot = "rpi.alsc" in self.plot - alsc_out = alsc_all(self,do_alsc_colour,plot) - cal_cr_list,cal_cb_list,luminance_lut,av_corn = alsc_out + alsc_out = alsc_all(self, do_alsc_colour, plot) + cal_cr_list, cal_cb_list, luminance_lut, av_corn = alsc_out """ write ouput to json and finish if not do_alsc_colour """ @@ -392,12 +392,12 @@ class Camera: """ obtain worst-case scenario residual sigmas """ - sigma_r,sigma_b = get_sigma(self,cal_cr_list,cal_cb_list) + sigma_r, sigma_b = get_sigma(self, cal_cr_list, cal_cb_list) """ write output to json """ - self.json['rpi.alsc']['sigma'] = np.round(sigma_r,5) - self.json['rpi.alsc']['sigma_Cb'] = np.round(sigma_b,5) + self.json['rpi.alsc']['sigma'] = np.round(sigma_r, 5) + self.json['rpi.alsc']['sigma_Cb'] = np.round(sigma_b, 5) self.log += '\nCalibrated sigmas written to json file' print('Finished ALSC calibrations') @@ -417,7 +417,7 @@ class Camera: perform calibration """ plot = 'rpi.geq' in self.plot - slope,offset = geq_fit(self,plot) + slope, offset = geq_fit(self, plot) """ write output to json """ @@ -441,7 +441,7 @@ class Camera: image with lux level closest to 1000 is chosen. """ luxes = [Img.lux for Img in self.imgs] - argmax = luxes.index(min(luxes, key=lambda l:abs(1000-l))) + argmax = luxes.index(min(luxes, key=lambda l: abs(1000-l))) Img = self.imgs[argmax] self.log += '\nLux found closest to 1000: {} lx'.format(Img.lux) self.log += '\nImage used: ' + Img.name @@ -450,7 +450,7 @@ class Camera: """ do calibration """ - lux_out,shutter_speed,gain = lux(self,Img) + lux_out, shutter_speed, gain = lux(self, Img) """ write output to json """ @@ -474,28 +474,28 @@ class Camera: run calibration on all images and sort by slope. """ plot = "rpi.noise" in self.plot - noise_out = sorted([noise(self,Img,plot) for Img in self.imgs], key = lambda x:x[0]) + noise_out = sorted([noise(self, Img, plot) for Img in self.imgs], key = lambda x: x[0]) self.log += '\nFinished processing images' """ take the average of the interquartile """ l = len(noise_out) - noise_out = np.mean(noise_out[l//4:1+3*l//4],axis=0) + noise_out = np.mean(noise_out[l//4:1+3*l//4], axis=0) self.log += '\nAverage noise profile: constant = {} '.format(int(noise_out[1])) self.log += 'slope = {:.3f}'.format(noise_out[0]) """ write to json """ self.json['rpi.noise']['reference_constant'] = int(noise_out[1]) - self.json['rpi.noise']['reference_slope'] = round(noise_out[0],3) + self.json['rpi.noise']['reference_slope'] = round(noise_out[0], 3) self.log += '\nNOISE calibrations written to json' print('Finished NOISE calibrations') """ Removes json entries that are turned off """ - def json_remove(self,disable): - self.log_new_sec('Disabling Options',cal=False) + def json_remove(self, disable): + self.log_new_sec('Disabling Options', cal=False) if len(self.disable) == 0: self.log += '\nNothing disabled!' return 1 @@ -512,16 +512,16 @@ class Camera: """ Write json dictionary to file """ - jstring = json.dumps(self.json,sort_keys=False) + jstring = json.dumps(self.json, sort_keys=False) """ make it pretty :) """ - pretty_print_json(jstring,self.jf) + pretty_print_json(jstring, self.jf) """ add a new section to the log file """ - def log_new_sec(self,section,cal=True): + def log_new_sec(self, section, cal=True): self.log += '\n'+self.log_separator self.log += section if cal: @@ -531,8 +531,8 @@ class Camera: """ write script arguments to log file """ - def log_user_input(self,json_output,directory,config,log_output): - self.log_new_sec('User Arguments',cal=False) + def log_user_input(self, json_output, directory, config, log_output): + self.log_new_sec('User Arguments', cal=False) self.log += '\nJson file output: ' + json_output self.log += '\nCalibration images directory: ' + directory if config == None: @@ -555,19 +555,19 @@ class Camera: """ write log file """ - def write_log(self,filename): + def write_log(self, filename): if filename == None: filename = 'ctt_log.txt' self.log += '\n' + self.log_separator - with open(filename,'w') as logfile: + with open(filename, 'w') as logfile: logfile.write(self.log) """ Add all images from directory, pass into relevant list of images and extrace lux and temperature values. """ - def add_imgs(self,directory,mac_config,blacklevel=-1): - self.log_new_sec('Image Loading',cal=False) + def add_imgs(self, directory, mac_config, blacklevel=-1): + self.log_new_sec('Image Loading', cal=False) img_suc_msg = 'Image loaded successfully!' print('\n\nLoading images from '+directory) self.log += '\nDirectory: ' + directory @@ -588,12 +588,12 @@ class Camera: """ obtain colour and lux value """ - col,lux = get_col_lux(filename) + col, lux = get_col_lux(filename) """ Check if image is an alsc calibration image """ if 'alsc' in filename: - Img = load_image(self,address,mac=False) + Img = load_image(self, address, mac=False) self.log += '\nIdentified as an ALSC image' """ check if imagae data has been successfully unpacked @@ -633,7 +633,7 @@ class Camera: self.log += '\nWARNING: Error reading lux value' self.log += '\nImage discarded!' continue - Img = load_image(self,address,mac_config) + Img = load_image(self, address, mac_config) """ check that image data has been successfuly unpacked """ @@ -645,7 +645,7 @@ class Camera: """ if successful, append to list and continue to next image """ - Img.col,Img.lux = col,lux + Img.col, Img.lux = col, lux Img.name = filename self.log += '\nColour temperature: {} K'.format(col) self.log += '\nLux value: {} lx'.format(lux) @@ -683,7 +683,7 @@ class Camera: patterns = list(set([Img.pattern for Img in all_imgs])) sigbitss = list(set([Img.sigbits for Img in all_imgs])) blacklevels = list(set([Img.blacklevel_16 for Img in all_imgs])) - sizes = list(set([(Img.w,Img.h) for Img in all_imgs])) + sizes = list(set([(Img.w, Img.h) for Img in all_imgs])) if len(camNames)==1 and len(patterns)==1 and len(sigbitss)==1 and len(blacklevels) ==1 and len(sizes)== 1: self.grey = (patterns[0] == 128) @@ -694,14 +694,14 @@ class Camera: self.log += '\nGreyscale camera identified' self.log += '\nSignificant bits: {}'.format(sigbitss[0]) self.log += '\nBlacklevel: {}'.format(blacklevels[0]) - self.log += '\nImage size: w = {} h = {}'.format(sizes[0][0],sizes[0][1]) + self.log += '\nImage size: w = {} h = {}'.format(sizes[0][0], sizes[0][1]) return 1 else: print('\nERROR: Images from different cameras') self.log += '\nERROR: Images are from different cameras' return 0 -def run_ctt(json_output,directory,config,log_output): +def run_ctt(json_output, directory, config, log_output): """ check input files are jsons """ @@ -717,7 +717,7 @@ def run_ctt(json_output,directory,config,log_output): read configurations """ try: - with open(config,'r') as config_json: + with open(config, 'r') as config_json: configs = json.load(config_json) except FileNotFoundError: configs = {} @@ -731,18 +731,18 @@ def run_ctt(json_output,directory,config,log_output): """ load configurations from config file, if not given then set default """ - disable = get_config(configs,"disable",[],'list') - plot = get_config(configs,"plot",[],'list') - awb_d = get_config(configs,"awb",{},'dict') - greyworld = get_config(awb_d,"greyworld",0,'bool') - alsc_d = get_config(configs,"alsc",{},'dict') - do_alsc_colour = get_config(alsc_d,"do_alsc_colour",1,'bool') - luminance_strength = get_config(alsc_d,"luminance_strength",0.5,'num') - blacklevel = get_config(configs,"blacklevel",-1,'num') - macbeth_d = get_config(configs,"macbeth",{},'dict') - mac_small = get_config(macbeth_d,"small",0,'bool') - mac_show = get_config(macbeth_d,"show",0,'bool') - mac_config = (mac_small,mac_show) + disable = get_config(configs, "disable", [], 'list') + plot = get_config(configs, "plot", [], 'list') + awb_d = get_config(configs, "awb", {}, 'dict') + greyworld = get_config(awb_d, "greyworld", 0, 'bool') + alsc_d = get_config(configs, "alsc", {}, 'dict') + do_alsc_colour = get_config(alsc_d, "do_alsc_colour", 1, 'bool') + luminance_strength = get_config(alsc_d, "luminance_strength", 0.5, 'num') + blacklevel = get_config(configs, "blacklevel", -1, 'num') + macbeth_d = get_config(configs, "macbeth", {}, 'dict') + mac_small = get_config(macbeth_d, "small", 0, 'bool') + mac_show = get_config(macbeth_d, "show", 0, 'bool') + mac_config = (mac_small, mac_show) if blacklevel < -1 or blacklevel >= 2**16: print('\nInvalid blacklevel, defaulted to 64') @@ -762,10 +762,10 @@ def run_ctt(json_output,directory,config,log_output): """ try: Cam = Camera(json_output) - Cam.log_user_input(json_output,directory,config,log_output) + Cam.log_user_input(json_output, directory, config, log_output) Cam.disable = disable Cam.plot = plot - Cam.add_imgs(directory,mac_config,blacklevel) + Cam.add_imgs(directory, mac_config, blacklevel) except FileNotFoundError: raise ArgError('\n\nError: Input image directory not found!') @@ -781,11 +781,11 @@ def run_ctt(json_output,directory,config,log_output): Cam.json['rpi.black_level']['black_level'] = Cam.blacklevel_16 Cam.json_remove(disable) print('\nSTARTING CALIBRATIONS') - Cam.alsc_cal(luminance_strength,do_alsc_colour) + Cam.alsc_cal(luminance_strength, do_alsc_colour) Cam.geq_cal() Cam.lux_cal() Cam.noise_cal() - Cam.awb_cal(greyworld,do_alsc_colour) + Cam.awb_cal(greyworld, do_alsc_colour) Cam.ccm_cal(do_alsc_colour) print('\nFINISHED CALIBRATIONS') Cam.write_json() @@ -819,5 +819,5 @@ if __name__ == '__main__': """ parse input arguments """ - json_output,directory,config,log_output = parse_input() - run_ctt(json_output,directory,config,log_output) + json_output, directory, config, log_output = parse_input() + run_ctt(json_output, directory, config, log_output) diff --git a/utils/raspberrypi/ctt/ctt_alsc.py b/utils/raspberrypi/ctt/ctt_alsc.py index fe1cff65..cd99495f 100644 --- a/utils/raspberrypi/ctt/ctt_alsc.py +++ b/utils/raspberrypi/ctt/ctt_alsc.py @@ -12,7 +12,7 @@ from mpl_toolkits.mplot3d import Axes3D """ preform alsc calibration on a set of images """ -def alsc_all(Cam,do_alsc_colour,plot): +def alsc_all(Cam, do_alsc_colour, plot): imgs_alsc = Cam.imgs_alsc """ create list of colour temperatures and associated calibration tables @@ -22,16 +22,16 @@ def alsc_all(Cam,do_alsc_colour,plot): list_cb = [] list_cg = [] for Img in imgs_alsc: - col,cr,cb,cg,size = alsc(Cam,Img,do_alsc_colour,plot) + col, cr, cb, cg, size = alsc(Cam, Img, do_alsc_colour, plot) list_col.append(col) list_cr.append(cr) list_cb.append(cb) list_cg.append(cg) Cam.log += '\n' Cam.log += '\nFinished processing images' - w,h,dx,dy = size - Cam.log += '\nChannel dimensions: w = {} h = {}'.format(int(w),int(h)) - Cam.log += '\n16x12 grid rectangle size: w = {} h = {}'.format(dx,dy) + w, h, dx, dy = size + Cam.log += '\nChannel dimensions: w = {} h = {}'.format(int(w), int(h)) + Cam.log += '\n16x12 grid rectangle size: w = {} h = {}'.format(dx, dy) """ convert to numpy array for data manipulation @@ -56,66 +56,66 @@ def alsc_all(Cam,do_alsc_colour,plot): """ indices = np.where(list_col == ct) ct = int(ct) - t_r = np.mean(list_cr[indices],axis=0) - t_b = np.mean(list_cb[indices],axis=0) + t_r = np.mean(list_cr[indices], axis=0) + t_b = np.mean(list_cb[indices], axis=0) """ force numbers to be stored to 3dp.... :( """ - t_r = np.where((100*t_r)%1<=0.05, t_r+0.001,t_r) - t_b = np.where((100*t_b)%1<=0.05, t_b+0.001,t_b) - t_r = np.where((100*t_r)%1>=0.95, t_r-0.001,t_r) - t_b = np.where((100*t_b)%1>=0.95, t_b-0.001,t_b) - t_r = np.round(t_r,3) - t_b = np.round(t_b,3) - r_corners = (t_r[0],t_r[15],t_r[-1],t_r[-16]) - b_corners = (t_b[0],t_b[15],t_b[-1],t_b[-16]) + t_r = np.where((100*t_r)%1<=0.05, t_r+0.001, t_r) + t_b = np.where((100*t_b)%1<=0.05, t_b+0.001, t_b) + t_r = np.where((100*t_r)%1>=0.95, t_r-0.001, t_r) + t_b = np.where((100*t_b)%1>=0.95, t_b-0.001, t_b) + t_r = np.round(t_r, 3) + t_b = np.round(t_b, 3) + r_corners = (t_r[0], t_r[15], t_r[-1], t_r[-16]) + b_corners = (t_b[0], t_b[15], t_b[-1], t_b[-16]) r_cen = t_r[5*16+7]+t_r[5*16+8]+t_r[6*16+7]+t_r[6*16+8] - r_cen = round(r_cen/4,3) + r_cen = round(r_cen/4, 3) b_cen = t_b[5*16+7]+t_b[5*16+8]+t_b[6*16+7]+t_b[6*16+8] - b_cen = round(b_cen/4,3) + b_cen = round(b_cen/4, 3) Cam.log += '\nRed table corners: {}'.format(r_corners) Cam.log += '\nRed table centre: {}'.format(r_cen) Cam.log += '\nBlue table corners: {}'.format(b_corners) Cam.log += '\nBlue table centre: {}'.format(b_cen) cr_dict = { - 'ct':ct, - 'table':list(t_r) + 'ct': ct, + 'table': list(t_r) } cb_dict = { - 'ct':ct, - 'table':list(t_b) + 'ct': ct, + 'table': list(t_b) } cal_cr_list.append(cr_dict) cal_cb_list.append(cb_dict) Cam.log += '\n' else: - cal_cr_list,cal_cb_list = None,None + cal_cr_list, cal_cb_list = None, None """ average all values for luminance shading and return one table for all temperatures """ - lum_lut = np.mean(list_cg,axis=0) - lum_lut = np.where((100*lum_lut)%1<=0.05,lum_lut+0.001,lum_lut) - lum_lut = np.where((100*lum_lut)%1>=0.95,lum_lut-0.001,lum_lut) - lum_lut = list(np.round(lum_lut,3)) + lum_lut = np.mean(list_cg, axis=0) + lum_lut = np.where((100*lum_lut)%1<=0.05, lum_lut+0.001, lum_lut) + lum_lut = np.where((100*lum_lut)%1>=0.95, lum_lut-0.001, lum_lut) + lum_lut = list(np.round(lum_lut, 3)) """ calculate average corner for lsc gain calculation further on """ - corners = (lum_lut[0],lum_lut[15],lum_lut[-1],lum_lut[-16]) + corners = (lum_lut[0], lum_lut[15], lum_lut[-1], lum_lut[-16]) Cam.log += '\nLuminance table corners: {}'.format(corners) l_cen = lum_lut[5*16+7]+lum_lut[5*16+8]+lum_lut[6*16+7]+lum_lut[6*16+8] - l_cen = round(l_cen/4,3) + l_cen = round(l_cen/4, 3) Cam.log += '\nLuminance table centre: {}'.format(l_cen) av_corn = np.sum(corners)/4 - return cal_cr_list,cal_cb_list,lum_lut,av_corn + return cal_cr_list, cal_cb_list, lum_lut, av_corn """ calculate g/r and g/b for 32x32 points arranged in a grid for a single image """ -def alsc(Cam,Img,do_alsc_colour,plot=False): +def alsc(Cam, Img, do_alsc_colour, plot=False): Cam.log += '\nProcessing image: ' + Img.name """ get channel in correct order @@ -126,31 +126,31 @@ def alsc(Cam,Img,do_alsc_colour,plot=False): -(-(w-1)//32) is a ceiling division. w-1 is to deal robustly with the case where w is a multiple of 32. """ - w,h = Img.w/2,Img.h/2 - dx,dy = int(-(-(w-1)//16)),int(-(-(h-1)//12)) + w, h = Img.w/2, Img.h/2 + dx, dy = int(-(-(w-1)//16)), int(-(-(h-1)//12)) """ average the green channels into one """ - av_ch_g = np.mean((channels[1:2]),axis = 0) + av_ch_g = np.mean((channels[1:2]), axis = 0) if do_alsc_colour: """ obtain 16x12 grid of intensities for each channel and subtract black level """ - g = get_16x12_grid(av_ch_g,dx,dy) - Img.blacklevel_16 - r = get_16x12_grid(channels[0],dx,dy) - Img.blacklevel_16 - b = get_16x12_grid(channels[3],dx,dy) - Img.blacklevel_16 + g = get_16x12_grid(av_ch_g, dx, dy) - Img.blacklevel_16 + r = get_16x12_grid(channels[0], dx, dy) - Img.blacklevel_16 + b = get_16x12_grid(channels[3], dx, dy) - Img.blacklevel_16 """ calculate ratios as 32 bit in order to be supported by medianBlur function """ - cr = np.reshape(g/r,(12,16)).astype('float32') - cb = np.reshape(g/b,(12,16)).astype('float32') - cg = np.reshape(1/g,(12,16)).astype('float32') + cr = np.reshape(g/r, (12, 16)).astype('float32') + cb = np.reshape(g/b, (12, 16)).astype('float32') + cg = np.reshape(1/g, (12, 16)).astype('float32') """ median blur to remove peaks and save as float 64 """ - cr = cv2.medianBlur(cr,3).astype('float64') - cb = cv2.medianBlur(cb,3).astype('float64') - cg = cv2.medianBlur(cg,3).astype('float64') + cr = cv2.medianBlur(cr, 3).astype('float64') + cb = cv2.medianBlur(cb, 3).astype('float64') + cg = cv2.medianBlur(cg, 3).astype('float64') cg = cg/np.min(cg) """ @@ -158,49 +158,49 @@ def alsc(Cam,Img,do_alsc_colour,plot=False): for sanity check """ if plot: - hf = plt.figure(figsize=(8,8)) + hf = plt.figure(figsize=(8, 8)) ha = hf.add_subplot(311, projection='3d') """ note Y is plotted as -Y so plot has same axes as image """ - X,Y = np.meshgrid(range(16),range(12)) - ha.plot_surface(X,-Y,cr,cmap=cm.coolwarm,linewidth=0) + X, Y = np.meshgrid(range(16), range(12)) + ha.plot_surface(X, -Y, cr, cmap=cm.coolwarm, linewidth=0) ha.set_title('ALSC Plot\nImg: {}\n\ncr'.format(Img.str)) hb = hf.add_subplot(312, projection='3d') - hb.plot_surface(X,-Y,cb,cmap=cm.coolwarm,linewidth=0) + hb.plot_surface(X, -Y, cb, cmap=cm.coolwarm, linewidth=0) hb.set_title('cb') hc = hf.add_subplot(313, projection='3d') - hc.plot_surface(X,-Y,cg,cmap=cm.coolwarm,linewidth=0) + hc.plot_surface(X, -Y, cg, cmap=cm.coolwarm, linewidth=0) hc.set_title('g') # print(Img.str) plt.show() - return Img.col,cr.flatten(),cb.flatten(),cg.flatten(),(w,h,dx,dy) + return Img.col, cr.flatten(), cb.flatten(), cg.flatten(), (w, h, dx, dy) else: """ only perform calculations for luminance shading """ - g = get_16x12_grid(av_ch_g,dx,dy) - Img.blacklevel_16 - cg = np.reshape(1/g,(12,16)).astype('float32') - cg = cv2.medianBlur(cg,3).astype('float64') + g = get_16x12_grid(av_ch_g, dx, dy) - Img.blacklevel_16 + cg = np.reshape(1/g, (12, 16)).astype('float32') + cg = cv2.medianBlur(cg, 3).astype('float64') cg = cg/np.min(cg) if plot: - hf = plt.figure(figssize=(8,8)) - ha = hf.add_subplot(1,1,1,projection='3d') - X,Y = np.meashgrid(range(16),range(12)) - ha.plot_surface(X,-Y,cg,cmap=cm.coolwarm,linewidth=0) + hf = plt.figure(figssize=(8, 8)) + ha = hf.add_subplot(1, 1, 1, projection='3d') + X, Y = np.meashgrid(range(16), range(12)) + ha.plot_surface(X, -Y, cg, cmap=cm.coolwarm, linewidth=0) ha.set_title('ALSC Plot (Luminance only!)\nImg: {}\n\ncg').format(Img.str) plt.show() - return Img.col,None,None,cg.flatten(),(w,h,dx,dy) + return Img.col, None, None, cg.flatten(), (w, h, dx, dy) """ Compresses channel down to a 16x12 grid """ -def get_16x12_grid(chan,dx,dy): +def get_16x12_grid(chan, dx, dy): grid = [] """ since left and bottom border will not necessarily have rectangles of @@ -208,11 +208,11 @@ def get_16x12_grid(chan,dx,dy): """ for i in range(11): for j in range(15): - grid.append(np.mean(chan[dy*i:dy*(1+i),dx*j:dx*(1+j)])) - grid.append(np.mean(chan[dy*i:dy*(1+i),15*dx:])) + grid.append(np.mean(chan[dy*i:dy*(1+i), dx*j:dx*(1+j)])) + grid.append(np.mean(chan[dy*i:dy*(1+i), 15*dx:])) for j in range(15): - grid.append(np.mean(chan[11*dy:,dx*j:dx*(1+j)])) - grid.append(np.mean(chan[11*dy:,15*dx:])) + grid.append(np.mean(chan[11*dy:, dx*j:dx*(1+j)])) + grid.append(np.mean(chan[11*dy:, 15*dx:])) """ return as np.array, ready for further manipulation """ @@ -221,7 +221,7 @@ def get_16x12_grid(chan,dx,dy): """ obtains sigmas for red and blue, effectively a measure of the 'error' """ -def get_sigma(Cam,cal_cr_list,cal_cb_list): +def get_sigma(Cam, cal_cr_list, cal_cb_list): Cam.log += '\nCalculating sigmas' """ provided colour alsc tables were generated for two different colour @@ -239,9 +239,9 @@ def get_sigma(Cam,cal_cr_list,cal_cb_list): sigma_rs = [] sigma_bs = [] for i in range(len(cts)-1): - sigma_rs.append(calc_sigma(cal_cr_list[i]['table'],cal_cr_list[i+1]['table'])) - sigma_bs.append(calc_sigma(cal_cb_list[i]['table'],cal_cb_list[i+1]['table'])) - Cam.log += '\nColour temperature interval {} - {} K'.format(cts[i],cts[i+1]) + sigma_rs.append(calc_sigma(cal_cr_list[i]['table'], cal_cr_list[i+1]['table'])) + sigma_bs.append(calc_sigma(cal_cb_list[i]['table'], cal_cb_list[i+1]['table'])) + Cam.log += '\nColour temperature interval {} - {} K'.format(cts[i], cts[i+1]) Cam.log += '\nSigma red: {}'.format(sigma_rs[-1]) Cam.log += '\nSigma blue: {}'.format(sigma_bs[-1]) @@ -254,19 +254,19 @@ def get_sigma(Cam,cal_cr_list,cal_cb_list): Cam.log += '\nMaximum sigmas: Red = {} Blue = {}'.format(sigma_r, sigma_b) - # print(sigma_rs,sigma_bs) - # print(sigma_r,sigma_b) - return sigma_r,sigma_b + # print(sigma_rs, sigma_bs) + # print(sigma_r, sigma_b) + return sigma_r, sigma_b """ calculate sigma from two adjacent gain tables """ -def calc_sigma(g1,g2): +def calc_sigma(g1, g2): """ reshape into 16x12 matrix """ - g1 = np.reshape(g1,(12,16)) - g2 = np.reshape(g2,(12,16)) + g1 = np.reshape(g1, (12, 16)) + g2 = np.reshape(g2, (12, 16)) """ apply gains to gain table """ @@ -294,4 +294,4 @@ def calc_sigma(g1,g2): return mean difference """ mean_diff = np.mean(diffs) - return(np.round(mean_diff,5)) + return(np.round(mean_diff, 5)) diff --git a/utils/raspberrypi/ctt/ctt_awb.py b/utils/raspberrypi/ctt/ctt_awb.py index d3130612..9a92033b 100644 --- a/utils/raspberrypi/ctt/ctt_awb.py +++ b/utils/raspberrypi/ctt/ctt_awb.py @@ -12,7 +12,7 @@ from scipy.optimize import fmin """ obtain piecewise linear approximation for colour curve """ -def awb(Cam,cal_cr_list,cal_cb_list,plot): +def awb(Cam, cal_cr_list, cal_cb_list, plot): imgs = Cam.imgs """ condense alsc calibration tables into one dictionary @@ -21,7 +21,7 @@ def awb(Cam,cal_cr_list,cal_cb_list,plot): colour_cals = None else: colour_cals = {} - for cr,cb in zip(cal_cr_list,cal_cb_list): + for cr, cb in zip(cal_cr_list, cal_cb_list): cr_tab = cr['table'] cb_tab = cb['table'] """ @@ -29,7 +29,7 @@ def awb(Cam,cal_cr_list,cal_cb_list,plot): """ cr_tab= cr_tab/np.min(cr_tab) cb_tab= cb_tab/np.min(cb_tab) - colour_cals[cr['ct']] = [cr_tab,cb_tab] + colour_cals[cr['ct']] = [cr_tab, cb_tab] """ obtain data from greyscale macbeth patches """ @@ -42,17 +42,17 @@ def awb(Cam,cal_cr_list,cal_cb_list,plot): Note: if alsc is disabled then colour_cals will be set to None and the function will just return the greyscale patches """ - r_patchs,b_patchs,g_patchs = get_alsc_patches(Img,colour_cals) + r_patchs, b_patchs, g_patchs = get_alsc_patches(Img, colour_cals) """ - calculate ratio of r,b to g + calculate ratio of r, b to g """ r_g = np.mean(r_patchs/g_patchs) b_g = np.mean(b_patchs/g_patchs) - Cam.log += '\n r : {:.4f} b : {:.4f}'.format(r_g,b_g) + Cam.log += '\n r : {:.4f} b : {:.4f}'.format(r_g, b_g) """ The curve tends to be better behaved in so-called hatspace. - R,B,G represent the individual channels. The colour curve is plotted in - r,b space, where: + R, B, G represent the individual channels. The colour curve is plotted in + r, b space, where: r = R/G b = B/G This will be referred to as dehatspace... (sorry) @@ -71,18 +71,18 @@ def awb(Cam,cal_cr_list,cal_cb_list,plot): """ r_g_hat = r_g/(1+r_g+b_g) b_g_hat = b_g/(1+r_g+b_g) - Cam.log += '\n r_hat : {:.4f} b_hat : {:.4f}'.format(r_g_hat,b_g_hat) - rbs_hat.append((r_g_hat,b_g_hat,Img.col)) - rb_raw.append((r_g,b_g)) + Cam.log += '\n r_hat : {:.4f} b_hat : {:.4f}'.format(r_g_hat, b_g_hat) + rbs_hat.append((r_g_hat, b_g_hat, Img.col)) + rb_raw.append((r_g, b_g)) Cam.log += '\n' Cam.log += '\nFinished processing images' """ sort all lits simultaneously by r_hat """ - rbs_zip = list(zip(rbs_hat,rb_raw)) - rbs_zip.sort(key=lambda x:x[0][0]) - rbs_hat,rb_raw = list(zip(*rbs_zip)) + rbs_zip = list(zip(rbs_hat, rb_raw)) + rbs_zip.sort(key=lambda x: x[0][0]) + rbs_hat, rb_raw = list(zip(*rbs_zip)) """ unzip tuples ready for processing """ @@ -91,7 +91,7 @@ def awb(Cam,cal_cr_list,cal_cb_list,plot): """ fit quadratic fit to r_g hat and b_g_hat """ - a,b,c = np.polyfit(rbs_hat[0],rbs_hat[1],2) + a, b, c = np.polyfit(rbs_hat[0], rbs_hat[1], 2) Cam.log += '\nFit quadratic curve in hatspace' """ the algorithm now approximates the shortest distance from each point to the @@ -113,11 +113,11 @@ def awb(Cam,cal_cr_list,cal_cb_list,plot): def f(x): return a*x**2 + b*x + c """ - iterate over points (R,B are x and y coordinates of points) and calculate + iterate over points (R, B are x and y coordinates of points) and calculate distance to line in dehatspace """ dists = [] - for i, (R,B) in enumerate(zip(rbs_hat[0],rbs_hat[1])): + for i, (R, B) in enumerate(zip(rbs_hat[0], rbs_hat[1])): """ define function to minimise as square distance between datapoint and point on curve. Squaring is monotonic so minimising radius squared is @@ -129,7 +129,7 @@ def awb(Cam,cal_cr_list,cal_cb_list,plot): """ perform optimisation with scipy.optmisie.fmin """ - x_hat = fmin(f_min,R,disp=0)[0] + x_hat = fmin(f_min, R, disp=0)[0] y_hat = f(x_hat) """ dehat @@ -179,16 +179,16 @@ def awb(Cam,cal_cr_list,cal_cb_list,plot): """ r_fit = r_hat_fit/(1-r_hat_fit-b_hat_fit) b_fit = b_hat_fit/(1-r_hat_fit-b_hat_fit) - c_fit = np.round(rbs_hat[2],0) + c_fit = np.round(rbs_hat[2], 0) """ round to 4dp """ - r_fit = np.where((1000*r_fit)%1<=0.05,r_fit+0.0001,r_fit) - r_fit = np.where((1000*r_fit)%1>=0.95,r_fit-0.0001,r_fit) - b_fit = np.where((1000*b_fit)%1<=0.05,b_fit+0.0001,b_fit) - b_fit = np.where((1000*b_fit)%1>=0.95,b_fit-0.0001,b_fit) - r_fit = np.round(r_fit,4) - b_fit = np.round(b_fit,4) + r_fit = np.where((1000*r_fit)%1<=0.05, r_fit+0.0001, r_fit) + r_fit = np.where((1000*r_fit)%1>=0.95, r_fit-0.0001, r_fit) + b_fit = np.where((1000*b_fit)%1<=0.05, b_fit+0.0001, b_fit) + b_fit = np.where((1000*b_fit)%1>=0.95, b_fit-0.0001, b_fit) + r_fit = np.round(r_fit, 4) + b_fit = np.round(b_fit, 4) """ The following code ensures that colour temperature decreases with increasing r/g @@ -200,8 +200,8 @@ def awb(Cam,cal_cr_list,cal_cb_list,plot): while i > 0 : if c_fit[i] > c_fit[i-1]: Cam.log += '\nColour temperature increase found\n' - Cam.log += '{} K at r = {} to '.format(c_fit[i-1],r_fit[i-1]) - Cam.log += '{} K at r = {}'.format(c_fit[i],r_fit[i]) + Cam.log += '{} K at r = {} to '.format(c_fit[i-1], r_fit[i-1]) + Cam.log += '{} K at r = {}'.format(c_fit[i], r_fit[i]) """ if colour temperature increases then discard point furthest from the transformed fit (dehatspace) @@ -209,8 +209,8 @@ def awb(Cam,cal_cr_list,cal_cb_list,plot): error_1 = abs(dists[i-1]) error_2 = abs(dists[i]) Cam.log += '\nDistances from fit:\n' - Cam.log += '{} K : {:.5f} , '.format(c_fit[i],error_1) - Cam.log += '{} K : {:.5f}'.format(c_fit[i-1],error_2) + Cam.log += '{} K : {:.5f} , '.format(c_fit[i], error_1) + Cam.log += '{} K : {:.5f}'.format(c_fit[i-1], error_2) """ find bad index note that in python false = 0 and true = 1 @@ -221,9 +221,9 @@ def awb(Cam,cal_cr_list,cal_cb_list,plot): """ delete bad point """ - r_fit = np.delete(r_fit,bad) - b_fit = np.delete(b_fit,bad) - c_fit = np.delete(c_fit,bad).astype(np.uint16) + r_fit = np.delete(r_fit, bad) + b_fit = np.delete(b_fit, bad) + c_fit = np.delete(c_fit, bad).astype(np.uint16) """ note that if a point has been discarded then the length has decreased by one, meaning that decreasing the index by one will reassess the kept @@ -235,7 +235,7 @@ def awb(Cam,cal_cr_list,cal_cb_list,plot): """ return formatted ct curve, ordered by increasing colour temperature """ - ct_curve = list(np.array(list(zip(b_fit,r_fit,c_fit))).flatten())[::-1] + ct_curve = list(np.array(list(zip(b_fit, r_fit, c_fit))).flatten())[::-1] Cam.log += '\nFinal CT curve:' for i in range(len(ct_curve)//3): j = 3*i @@ -247,15 +247,15 @@ def awb(Cam,cal_cr_list,cal_cb_list,plot): plotting code for debug """ if plot: - x = np.linspace(np.min(rbs_hat[0]),np.max(rbs_hat[0]),100) + x = np.linspace(np.min(rbs_hat[0]), np.max(rbs_hat[0]), 100) y = a*x**2 + b*x + c - plt.subplot(2,1,1) + plt.subplot(2, 1, 1) plt.title('hatspace') - plt.plot(rbs_hat[0],rbs_hat[1],ls='--',color='blue') - plt.plot(x,y,color='green',ls='-') - plt.scatter(rbs_hat[0],rbs_hat[1],color='red') + plt.plot(rbs_hat[0], rbs_hat[1], ls='--', color='blue') + plt.plot(x, y, color='green', ls='-') + plt.scatter(rbs_hat[0], rbs_hat[1], color='red') for i, ct in enumerate(rbs_hat[2]): - plt.annotate(str(ct),(rbs_hat[0][i],rbs_hat[1][i])) + plt.annotate(str(ct), (rbs_hat[0][i], rbs_hat[1][i])) plt.xlabel('$\hat{r}$') plt.ylabel('$\hat{b}$') """ @@ -265,13 +265,13 @@ def awb(Cam,cal_cr_list,cal_cb_list,plot): # ax = plt.gca() # ax.set_aspect('equal') plt.grid() - plt.subplot(2,1,2) + plt.subplot(2, 1, 2) plt.title('dehatspace - indoors?') - plt.plot(r_fit,b_fit,color='blue') - plt.scatter(rb_raw[0],rb_raw[1],color='green') - plt.scatter(r_fit,b_fit,color='red') - for i,ct in enumerate(c_fit): - plt.annotate(str(ct),(r_fit[i],b_fit[i])) + plt.plot(r_fit, b_fit, color='blue') + plt.scatter(rb_raw[0], rb_raw[1], color='green') + plt.scatter(r_fit, b_fit, color='red') + for i, ct in enumerate(c_fit): + plt.annotate(str(ct), (r_fit[i], b_fit[i])) plt.xlabel('$r$') plt.ylabel('$b$') """ @@ -286,15 +286,15 @@ def awb(Cam,cal_cr_list,cal_cb_list,plot): """ end of plotting code """ - return(ct_curve,np.round(transverse_pos,5),np.round(transverse_neg,5)) + return(ct_curve, np.round(transverse_pos, 5), np.round(transverse_neg, 5)) """ obtain greyscale patches and perform alsc colour correction """ -def get_alsc_patches(Img,colour_cals,grey=True): +def get_alsc_patches(Img, colour_cals, grey=True): """ get patch centre coordinates, image colour and the actual - patches for each channel,remembering to subtract blacklevel + patches for each channel, remembering to subtract blacklevel If grey then only greyscale patches considered """ if grey: @@ -316,12 +316,12 @@ def get_alsc_patches(Img,colour_cals,grey=True): g_patchs = (patches[1]+patches[2])/2 - Img.blacklevel_16 if colour_cals == None: - return r_patchs,b_patchs,g_patchs + return r_patchs, b_patchs, g_patchs """ find where image colour fits in alsc colour calibration tables """ cts = list(colour_cals.keys()) - pos = bisect_left(cts,col) + pos = bisect_left(cts, col) """ if img colour is below minimum or above maximum alsc calibration colour, simply pick extreme closest to img colour @@ -343,32 +343,32 @@ def get_alsc_patches(Img,colour_cals,grey=True): bef_tabs = np.array(colour_cals[bef]) aft_tabs = np.array(colour_cals[aft]) col_tabs = (bef_tabs*db + aft_tabs*da)/(da+db) - col_tabs = np.reshape(col_tabs,(2,12,16)) + col_tabs = np.reshape(col_tabs, (2, 12, 16)) """ - calculate dx,dy used to calculate alsc table + calculate dx, dy used to calculate alsc table """ - w,h = Img.w/2,Img.h/2 - dx,dy = int(-(-(w-1)//16)),int(-(-(h-1)//12)) + w, h = Img.w/2, Img.h/2 + dx, dy = int(-(-(w-1)//16)), int(-(-(h-1)//12)) """ make list of pairs of gains for each patch by selecting the correct value in alsc colour calibration table """ patch_gains = [] for cen in cen_coords: - x,y = cen[0]//dx, cen[1]//dy + x, y = cen[0]//dx, cen[1]//dy # We could probably do with some better spatial interpolation here? - col_gains = (col_tabs[0][y][x],col_tabs[1][y][x]) + col_gains = (col_tabs[0][y][x], col_tabs[1][y][x]) patch_gains.append(col_gains) """ multiply the r and b channels in each patch by the respective gain, finally performing the alsc colour correction """ - for i,gains in enumerate(patch_gains): + for i, gains in enumerate(patch_gains): r_patchs[i] = r_patchs[i] * gains[0] b_patchs[i] = b_patchs[i] * gains[1] """ - return greyscale patches, g channel and correct r,b channels + return greyscale patches, g channel and correct r, b channels """ - return r_patchs,b_patchs,g_patchs + return r_patchs, b_patchs, g_patchs diff --git a/utils/raspberrypi/ctt/ctt_ccm.py b/utils/raspberrypi/ctt/ctt_ccm.py index 8200a27f..1771fc43 100644 --- a/utils/raspberrypi/ctt/ctt_ccm.py +++ b/utils/raspberrypi/ctt/ctt_ccm.py @@ -19,7 +19,7 @@ def degamma(x): """ FInds colour correction matrices for list of images """ -def ccm(Cam,cal_cr_list,cal_cb_list): +def ccm(Cam, cal_cr_list, cal_cb_list): imgs = Cam.imgs """ standard macbeth chart colour values @@ -32,7 +32,7 @@ def ccm(Cam,cal_cr_list,cal_cb_list): [130, 128, 176], # blue flower [92, 190, 172], # bluish green [224, 124, 47], # orange - [68, 91,170], # purplish blue + [68, 91, 170], # purplish blue [198, 82, 97], # moderate red [94, 58, 106], # purple [159, 189, 63], # yellow green @@ -58,7 +58,7 @@ def ccm(Cam,cal_cr_list,cal_cb_list): """ reorder reference values to match how patches are ordered """ - m_srgb = np.array([m_srgb[i::6] for i in range(6)]).reshape((24,3)) + m_srgb = np.array([m_srgb[i::6] for i in range(6)]).reshape((24, 3)) """ reformat alsc correction tables or set colour_cals to None if alsc is @@ -68,7 +68,7 @@ def ccm(Cam,cal_cr_list,cal_cb_list): colour_cals = None else: colour_cals = {} - for cr,cb in zip(cal_cr_list,cal_cb_list): + for cr, cb in zip(cal_cr_list, cal_cb_list): cr_tab = cr['table'] cb_tab = cb['table'] """ @@ -76,7 +76,7 @@ def ccm(Cam,cal_cr_list,cal_cb_list): """ cr_tab= cr_tab/np.min(cr_tab) cb_tab= cb_tab/np.min(cb_tab) - colour_cals[cr['ct']] = [cr_tab,cb_tab] + colour_cals[cr['ct']] = [cr_tab, cb_tab] """ for each image, perform awb and alsc corrections. @@ -91,14 +91,14 @@ def ccm(Cam,cal_cr_list,cal_cb_list): Note: if alsc is disabled then colour_cals will be set to None and no the function will simply return the macbeth patches """ - r,b,g = get_alsc_patches(Img,colour_cals,grey=False) + r, b, g = get_alsc_patches(Img, colour_cals, grey=False) """ do awb Note: awb is done by measuring the macbeth chart in the image, rather than from the awb calibration. This is done so the awb will be perfect and the ccm matrices will be more accurate. """ - r_greys,b_greys,g_greys = r[3::4],b[3::4],g[3::4] + r_greys, b_greys, g_greys = r[3::4], b[3::4], g[3::4] r_g = np.mean(r_greys/g_greys) b_g = np.mean(b_greys/g_greys) r = r / r_g @@ -108,16 +108,16 @@ def ccm(Cam,cal_cr_list,cal_cb_list): normalise brightness wrt reference macbeth colours and then average each channel for each patch """ - gain = np.mean(m_srgb)/np.mean((r,g,b)) + gain = np.mean(m_srgb)/np.mean((r, g, b)) Cam.log += '\nGain with respect to standard colours: {:.3f}'.format(gain) - r = np.mean(gain*r,axis=1) - b = np.mean(gain*b,axis=1) - g = np.mean(gain*g,axis=1) + r = np.mean(gain*r, axis=1) + b = np.mean(gain*b, axis=1) + g = np.mean(gain*g, axis=1) """ calculate ccm matrix """ - ccm = do_ccm(r,g,b,m_srgb) + ccm = do_ccm(r, g, b, m_srgb) """ if a ccm has already been calculated for that temperature then don't @@ -133,18 +133,18 @@ def ccm(Cam,cal_cr_list,cal_cb_list): """ average any ccms that share a colour temperature """ - for k,v in ccm_tab.items(): - tab = np.mean(v,axis=0) - tab = np.where((10000*tab)%1<=0.05,tab+0.00001,tab) - tab = np.where((10000*tab)%1>=0.95,tab-0.00001,tab) - ccm_tab[k] = list(np.round(tab,5)) + for k, v in ccm_tab.items(): + tab = np.mean(v, axis=0) + tab = np.where((10000*tab)%1<=0.05, tab+0.00001, tab) + tab = np.where((10000*tab)%1>=0.95, tab-0.00001, tab) + ccm_tab[k] = list(np.round(tab, 5)) Cam.log += '\nMatrix calculated for colour temperature of {} K'.format(k) """ return all ccms with respective colour temperature in the correct format, sorted by their colour temperature """ - sorted_ccms = sorted(ccm_tab.items(),key=lambda kv: kv[0]) + sorted_ccms = sorted(ccm_tab.items(), key=lambda kv: kv[0]) ccms = [] for i in sorted_ccms: ccms.append({ @@ -161,19 +161,19 @@ calculation. Should you want to fit them in another space (e.g. LAB) we wish you the best of luck and send us the code when you are done! :-) """ -def do_ccm(r,g,b,m_srgb): +def do_ccm(r, g, b, m_srgb): rb = r-b gb = g-b rb_2s = (rb*rb) rb_gbs = (rb*gb) gb_2s = (gb*gb) - r_rbs = ( rb * (m_srgb[...,0] - b) ) - r_gbs = ( gb * (m_srgb[...,0] - b) ) - g_rbs = ( rb * (m_srgb[...,1] - b) ) - g_gbs = ( gb * (m_srgb[...,1] - b) ) - b_rbs = ( rb * (m_srgb[...,2] - b) ) - b_gbs = ( gb * (m_srgb[...,2] - b) ) + r_rbs = ( rb * (m_srgb[..., 0] - b) ) + r_gbs = ( gb * (m_srgb[..., 0] - b) ) + g_rbs = ( rb * (m_srgb[..., 1] - b) ) + g_gbs = ( gb * (m_srgb[..., 1] - b) ) + b_rbs = ( rb * (m_srgb[..., 2] - b) ) + b_gbs = ( gb * (m_srgb[..., 2] - b) ) """ Obtain least squares fit @@ -216,6 +216,6 @@ def do_ccm(r,g,b,m_srgb): """ format ccm """ - ccm = [r_a,r_b,r_c,g_a,g_b,g_c,b_a,b_b,b_c] + ccm = [r_a, r_b, r_c, g_a, g_b, g_c, b_a, b_b, b_c] return ccm diff --git a/utils/raspberrypi/ctt/ctt_geq.py b/utils/raspberrypi/ctt/ctt_geq.py index dd798f4a..f8395e43 100644 --- a/utils/raspberrypi/ctt/ctt_geq.py +++ b/utils/raspberrypi/ctt/ctt_geq.py @@ -13,25 +13,25 @@ Uses green differences in macbeth patches to fit green equalisation threshold model. Ideally, all macbeth chart centres would fall below the threshold as these should be corrected by geq. """ -def geq_fit(Cam,plot): +def geq_fit(Cam, plot): imgs = Cam.imgs """ green equalisation to mitigate mazing. Fits geq model by looking at difference between greens in macbeth patches """ - geqs = np.array([ geq(Cam,Img)*Img.againQ8_norm for Img in imgs ]) + geqs = np.array([ geq(Cam, Img)*Img.againQ8_norm for Img in imgs ]) Cam.log += '\nProcessed all images' - geqs = geqs.reshape((-1,2)) + geqs = geqs.reshape((-1, 2)) """ data is sorted by green difference and top half is selected since higher green difference data define the decision boundary. """ - geqs = np.array(sorted(geqs,key = lambda r:np.abs((r[1]-r[0])/r[0]))) + geqs = np.array(sorted(geqs, key = lambda r: np.abs((r[1]-r[0])/r[0]))) length = len(geqs) - g0 = geqs[length//2:,0] - g1 = geqs[length//2:,1] + g0 = geqs[length//2:, 0] + g1 = geqs[length//2:, 1] gdiff = np.abs(g0-g1) """ find linear fit by minimising asymmetric least square errors @@ -40,7 +40,7 @@ def geq_fit(Cam,plot): threshold, hence the upper bound approach """ def f(params): - m,c = params + m, c = params a = gdiff - (m*g0+c) """ asymmetric square error returns: @@ -49,29 +49,29 @@ def geq_fit(Cam,plot): """ return(np.sum(a**2+0.95*np.abs(a)*a)) - initial_guess = [0.01,500] + initial_guess = [0.01, 500] """ Nelder-Mead is usually not the most desirable optimisation method but has been chosen here due to its robustness to undifferentiability (is that a word?) """ - result = optimize.minimize(f,initial_guess,method='Nelder-Mead') + result = optimize.minimize(f, initial_guess, method='Nelder-Mead') """ need to check if the fit worked correectly """ if result.success: - slope,offset = result.x + slope, offset = result.x Cam.log += '\nFit result: slope = {:.5f} '.format(slope) Cam.log += 'offset = {}'.format(int(offset)) """ optional plotting code """ if plot: - x = np.linspace(max(g0)*1.1,100) + x = np.linspace(max(g0)*1.1, 100) y = slope*x + offset plt.title('GEQ Asymmetric \'Upper Bound\' Fit') - plt.plot(x,y,color='red',ls='--',label='fit') - plt.scatter(g0,gdiff,color='b',label='data') + plt.plot(x, y, color='red', ls='--', label='fit') + plt.scatter(g0, gdiff, color='b', label='data') plt.ylabel('Difference in green channels') plt.xlabel('Green value') @@ -103,7 +103,7 @@ def geq_fit(Cam,plot): """ if plot: y2 = slope*x + offset - plt.plot(x,y2,color='green',ls='--',label='scaled fit') + plt.plot(x, y2, color='green', ls='--', label='scaled fit') plt.grid() plt.legend() plt.show() @@ -122,19 +122,19 @@ def geq_fit(Cam,plot): print(result.message) Cam.log += '\nWARNING: Asymmetric least squares fit failed! ' Cam.log += 'Standard fit used could possibly lead to worse results' - fit = np.polyfit(gdiff,g0,1) - offset,slope = -fit[1]/fit[0],1/fit[0] + fit = np.polyfit(gdiff, g0, 1) + offset, slope = -fit[1]/fit[0], 1/fit[0] Cam.log += '\nFit result: slope = {:.5f} '.format(slope) Cam.log += 'offset = {}'.format(int(offset)) """ optional plotting code """ if plot: - x = np.linspace(max(g0)*1.1,100) + x = np.linspace(max(g0)*1.1, 100) y = slope*x + offset plt.title('GEQ Linear Fit') - plt.plot(x,y,color='red',ls='--',label='fit') - plt.scatter(g0,gdiff,color='b',label='data') + plt.plot(x, y, color='red', ls='--', label='fit') + plt.scatter(g0, gdiff, color='b', label='data') plt.ylabel('Difference in green channels') plt.xlabel('Green value') """ @@ -158,22 +158,22 @@ def geq_fit(Cam,plot): """ if plot: y2 = slope*x + offset - plt.plot(x,y2,color='green',ls='--',label='scaled fit') + plt.plot(x, y2, color='green', ls='--', label='scaled fit') plt.legend() plt.grid() plt.show() - return round(slope,5),int(offset) + return round(slope, 5), int(offset) """" Return green channels of macbeth patches -returns g0,g1 where +returns g0, g1 where > g0 is green next to red > g1 is green next to blue """ -def geq(Cam,Img): +def geq(Cam, Img): Cam.log += '\nProcessing image {}'.format(Img.name) patches = [Img.patches[i] for i in Img.order][1:3] - g_patches = np.array([(np.mean(patches[0][i]),np.mean(patches[1][i])) for i in range(24)]) + g_patches = np.array([(np.mean(patches[0][i]), np.mean(patches[1][i])) for i in range(24)]) Cam.log += '\n' return(g_patches) diff --git a/utils/raspberrypi/ctt/ctt_image_load.py b/utils/raspberrypi/ctt/ctt_image_load.py index dd7adb16..7d097118 100644 --- a/utils/raspberrypi/ctt/ctt_image_load.py +++ b/utils/raspberrypi/ctt/ctt_image_load.py @@ -18,7 +18,7 @@ Once image is extracted from data, it finds 24 16x16 patches for each channel, centred at the macbeth chart squares """ class Image: - def __init__(self,buf): + def __init__(self, buf): self.buf = buf self.patches = None self.saturated = False @@ -45,11 +45,11 @@ class Image: Channel order depending on bayer pattern """ bayer_case = { - 0 : (0,1,2,3), #red - 1 : (2,0,3,1), #green next to red - 2 : (3,2,1,0), #green next to blue - 3 : (1,0,3,2), #blue - 128 : (0,1,2,3) #arbitrary order for greyscale casw + 0 : (0, 1, 2, 3), #red + 1 : (2, 0, 3, 1), #green next to red + 2 : (3, 2, 1, 0), #green next to blue + 3 : (1, 0, 3, 2), #blue + 128 : (0, 1, 2, 3) #arbitrary order for greyscale casw } self.order = bayer_case[self.pattern] @@ -87,7 +87,7 @@ class Image: """ get image from raw scanline data """ - def get_image(self,raw): + def get_image(self, raw): self.dptr = [] """ check if data is 10 or 12 bits @@ -100,31 +100,31 @@ class Image: """ stack scan lines into matrix """ - raw = np.array(raw).reshape(-1,lin_len).astype(np.int64)[:self.h,...] + raw = np.array(raw).reshape(-1, lin_len).astype(np.int64)[:self.h, ...] """ separate 5 bits in each package, stopping when w is satisfied """ - ba0 = raw[...,0:5*((self.w+3)>>2):5] - ba1 = raw[...,1:5*((self.w+3)>>2):5] - ba2 = raw[...,2:5*((self.w+3)>>2):5] - ba3 = raw[...,3:5*((self.w+3)>>2):5] - ba4 = raw[...,4:5*((self.w+3)>>2):5] + ba0 = raw[..., 0:5*((self.w+3)>>2):5] + ba1 = raw[..., 1:5*((self.w+3)>>2):5] + ba2 = raw[..., 2:5*((self.w+3)>>2):5] + ba3 = raw[..., 3:5*((self.w+3)>>2):5] + ba4 = raw[..., 4:5*((self.w+3)>>2):5] """ assemble 10 bit numbers """ - ch0 = np.left_shift((np.left_shift(ba0,2) + (ba4%4)),6) - ch1 = np.left_shift((np.left_shift(ba1,2) + (np.right_shift(ba4,2)%4)),6) - ch2 = np.left_shift((np.left_shift(ba2,2) + (np.right_shift(ba4,4)%4)),6) - ch3 = np.left_shift((np.left_shift(ba3,2) + (np.right_shift(ba4,6)%4)),6) + ch0 = np.left_shift((np.left_shift(ba0, 2) + (ba4%4)), 6) + ch1 = np.left_shift((np.left_shift(ba1, 2) + (np.right_shift(ba4, 2)%4)), 6) + ch2 = np.left_shift((np.left_shift(ba2, 2) + (np.right_shift(ba4, 4)%4)), 6) + ch3 = np.left_shift((np.left_shift(ba3, 2) + (np.right_shift(ba4, 6)%4)), 6) """ interleave bits """ - mat = np.empty((self.h,self.w),dtype=ch0.dtype) + mat = np.empty((self.h, self.w), dtype=ch0.dtype) - mat[...,0::4] = ch0 - mat[...,1::4] = ch1 - mat[...,2::4] = ch2 - mat[...,3::4] = ch3 + mat[..., 0::4] = ch0 + mat[..., 1::4] = ch1 + mat[..., 2::4] = ch2 + mat[..., 3::4] = ch3 """ There is som eleaking memory somewhere in the code. This code here @@ -132,25 +132,25 @@ class Image: reasonable numbers of images, however this is techincally just a workaround. (sorry) """ - ba0,ba1,ba2,ba3,ba4 = None,None,None,None,None - del ba0,ba1,ba2,ba3,ba4 - ch0,ch1,ch2,ch3 = None,None,None,None - del ch0,ch1,ch2,ch3 + ba0, ba1, ba2, ba3, ba4 = None, None, None, None, None + del ba0, ba1, ba2, ba3, ba4 + ch0, ch1, ch2, ch3 = None, None, None, None + del ch0, ch1, ch2, ch3 """ same as before but 12 bit case """ elif self.sigbits == 12: lin_len = ((((((self.w+self.pad+1)>>1)) * 3)+31)>>5) * 32 - raw = np.array(raw).reshape(-1,lin_len).astype(np.int64)[:self.h,...] - ba0 = raw[...,0:3*((self.w+1)>>1):3] - ba1 = raw[...,1:3*((self.w+1)>>1):3] - ba2 = raw[...,2:3*((self.w+1)>>1):3] - ch0 = np.left_shift((np.left_shift(ba0,4) + ba2%16),4) - ch1 = np.left_shift((np.left_shift(ba1,4) + (np.right_shift(ba2,4))%16),4) - mat = np.empty((self.h,self.w),dtype=ch0.dtype) - mat[...,0::2] = ch0 - mat[...,1::2] = ch1 + raw = np.array(raw).reshape(-1, lin_len).astype(np.int64)[:self.h, ...] + ba0 = raw[..., 0:3*((self.w+1)>>1):3] + ba1 = raw[..., 1:3*((self.w+1)>>1):3] + ba2 = raw[..., 2:3*((self.w+1)>>1):3] + ch0 = np.left_shift((np.left_shift(ba0, 4) + ba2%16), 4) + ch1 = np.left_shift((np.left_shift(ba1, 4) + (np.right_shift(ba2, 4))%16), 4) + mat = np.empty((self.h, self.w), dtype=ch0.dtype) + mat[..., 0::2] = ch0 + mat[..., 1::2] = ch1 else: """ @@ -162,21 +162,21 @@ class Image: """ separate bayer channels """ - c0 = mat[0::2,0::2] - c1 = mat[0::2,1::2] - c2 = mat[1::2,0::2] - c3 = mat[1::2,1::2] - self.channels = [c0,c1,c2,c3] + c0 = mat[0::2, 0::2] + c1 = mat[0::2, 1::2] + c2 = mat[1::2, 0::2] + c3 = mat[1::2, 1::2] + self.channels = [c0, c1, c2, c3] return 1 """ obtain 16x16 patch centred at macbeth square centre for each channel """ - def get_patches(self,cen_coords,size=16): + def get_patches(self, cen_coords, size=16): """ obtain channel widths and heights """ - ch_w,ch_h = self.w,self.h + ch_w, ch_h = self.w, self.h cen_coords = list(np.array((cen_coords[0])).astype(np.int32)) self.cen_coords = cen_coords """ @@ -184,10 +184,10 @@ class Image: left to right. Some useful patch indices: white = 3 black = 23 - 'reds' = 9,10 - 'blues' = 2,5,8,20,22 - 'greens' = 6,12,17 - greyscale = 3,7,11,15,19,23 + 'reds' = 9, 10 + 'blues' = 2, 5, 8, 20, 22 + 'greens' = 6, 12, 17 + greyscale = 3, 7, 11, 15, 19, 23 """ all_patches = [] for ch in self.channels: @@ -199,7 +199,7 @@ class Image: Patch pixels are sorted by pixel brightness so spatial information is lost. ''' - patch = ch[cen[1]-7:cen[1]+9,cen[0]-7:cen[0]+9].flatten() + patch = ch[cen[1]-7:cen[1]+9, cen[0]-7:cen[0]+9].flatten() patch.sort() if patch[-5] == (2**self.sigbits-1)*2**(16-self.sigbits): self.saturated = True @@ -218,7 +218,7 @@ def brcm_load_image(Cam, im_str): """ create byte array """ - with open(im_str,'rb') as image: + with open(im_str, 'rb') as image: f = image.read() b = bytearray(f) """ @@ -249,7 +249,7 @@ def brcm_load_image(Cam, im_str): """ note index is divided by two to go from string to hex """ - indices = [m.start()//2 for m in re.finditer(match_str,b_str)] + indices = [m.start()//2 for m in re.finditer(match_str, b_str)] # print(indices) try: start = indices[0] + 3 @@ -325,10 +325,10 @@ def dng_load_image(Cam, im_str): raw_im = raw.imread(im_str) raw_data = raw_im.raw_image shift = 16 - Img.sigbits - c0 = np.left_shift(raw_data[0::2,0::2].astype(np.int64), shift) - c1 = np.left_shift(raw_data[0::2,1::2].astype(np.int64), shift) - c2 = np.left_shift(raw_data[1::2,0::2].astype(np.int64), shift) - c3 = np.left_shift(raw_data[1::2,1::2].astype(np.int64), shift) + c0 = np.left_shift(raw_data[0::2, 0::2].astype(np.int64), shift) + c1 = np.left_shift(raw_data[0::2, 1::2].astype(np.int64), shift) + c2 = np.left_shift(raw_data[1::2, 0::2].astype(np.int64), shift) + c3 = np.left_shift(raw_data[1::2, 1::2].astype(np.int64), shift) Img.channels = [c0, c1, c2, c3] except: @@ -347,7 +347,7 @@ check correct filetype mac boolean is true if image is expected to contain macbeth chart and false if not (alsc images don't have macbeth charts) ''' -def load_image(Cam,im_str,mac_config=None,show=False,mac=True,show_meta=False): +def load_image(Cam, im_str, mac_config=None, show=False, mac=True, show_meta=False): """ check image is correct filetype """ @@ -363,7 +363,7 @@ def load_image(Cam,im_str,mac_config=None,show=False,mac=True,show_meta=False): """ find macbeth centres, discarding images that are too dark or light """ - av_chan = (np.mean(np.array(Img.channels),axis=0)/(2**16)) + av_chan = (np.mean(np.array(Img.channels), axis=0)/(2**16)) av_val = np.mean(av_chan) # print(av_val) if av_val < Img.blacklevel_16/(2**16)+1/64: @@ -371,7 +371,7 @@ def load_image(Cam,im_str,mac_config=None,show=False,mac=True,show_meta=False): print('\nError: Image too dark!') Cam.log += '\nWARNING: Image too dark!' else: - macbeth = find_macbeth(Cam,av_chan,mac_config) + macbeth = find_macbeth(Cam, av_chan, mac_config) """ if no macbeth found return error @@ -405,8 +405,8 @@ def load_image(Cam,im_str,mac_config=None,show=False,mac=True,show_meta=False): """ if show and __name__ == '__main__': copy = sum(Img.channels)/2**18 - copy = np.reshape(copy,(Img.h//2,Img.w//2)).astype(np.float64) - copy,_ = reshape(copy,800) + copy = np.reshape(copy, (Img.h//2, Img.w//2)).astype(np.float64) + copy, _ = reshape(copy, 800) represent(copy) return Img diff --git a/utils/raspberrypi/ctt/ctt_lux.py b/utils/raspberrypi/ctt/ctt_lux.py index 8a16d346..55b2aa29 100644 --- a/utils/raspberrypi/ctt/ctt_lux.py +++ b/utils/raspberrypi/ctt/ctt_lux.py @@ -8,7 +8,7 @@ from ctt_tools import * """ Find lux values from metadata and calculate Y """ -def lux(Cam,Img): +def lux(Cam, Img): shutter_speed = Img.exposure gain = Img.againQ8_norm aperture = 1 @@ -17,12 +17,12 @@ def lux(Cam,Img): Cam.log += '\nAperture = {}'.format(aperture) patches = [Img.patches[i] for i in Img.order] channels = [Img.channels[i] for i in Img.order] - return lux_calc(Cam,Img,patches,channels),shutter_speed,gain + return lux_calc(Cam, Img, patches, channels), shutter_speed, gain """ perform lux calibration on bayer channels """ -def lux_calc(Cam,Img,patches,channels): +def lux_calc(Cam, Img, patches, channels): """ find means color channels on grey patches """ @@ -30,14 +30,14 @@ def lux_calc(Cam,Img,patches,channels): ap_g = (np.mean(patches[1][3::4])+np.mean(patches[2][3::4]))/2 ap_b = np.mean(patches[3][3::4]) Cam.log += '\nAverage channel values on grey patches:' - Cam.log += '\nRed = {:.0f} Green = {:.0f} Blue = {:.0f}'.format(ap_r,ap_b,ap_g) - # print(ap_r,ap_g,ap_b) + Cam.log += '\nRed = {:.0f} Green = {:.0f} Blue = {:.0f}'.format(ap_r, ap_b, ap_g) + # print(ap_r, ap_g, ap_b) """ calculate channel gains """ gr = ap_g/ap_r gb = ap_g/ap_b - Cam.log += '\nChannel gains: Red = {:.3f} Blue = {:.3f}'.format(gr,gb) + Cam.log += '\nChannel gains: Red = {:.3f} Blue = {:.3f}'.format(gr, gb) """ find means color channels on image and scale by gain @@ -47,8 +47,8 @@ def lux_calc(Cam,Img,patches,channels): a_g = (np.mean(channels[1])+np.mean(channels[2]))/2 a_b = np.mean(channels[3])*gb Cam.log += '\nAverage channel values over entire image scaled by channel gains:' - Cam.log += '\nRed = {:.0f} Green = {:.0f} Blue = {:.0f}'.format(a_r,a_b,a_g) - # print(a_r,a_g,a_b) + Cam.log += '\nRed = {:.0f} Green = {:.0f} Blue = {:.0f}'.format(a_r, a_b, a_g) + # print(a_r, a_g, a_b) """ Calculate y with top row of yuv matrix """ diff --git a/utils/raspberrypi/ctt/ctt_macbeth_locator.py b/utils/raspberrypi/ctt/ctt_macbeth_locator.py index 583d5a69..591459aa 100644 --- a/utils/raspberrypi/ctt/ctt_macbeth_locator.py +++ b/utils/raspberrypi/ctt/ctt_macbeth_locator.py @@ -19,15 +19,15 @@ the clustering algorithm. This catches these warnings so they don't flood the output to the console """ def fxn(): - warnings.warn("runtime",RuntimeWarning) + warnings.warn("runtime", RuntimeWarning) """ Define the success message """ success_msg = 'Macbeth chart located successfully' -def find_macbeth(Cam,img,mac_config=(0,0)): - small_chart,show = mac_config +def find_macbeth(Cam, img, mac_config=(0, 0)): + small_chart, show = mac_config print('Locating macbeth chart') Cam.log += '\nLocating macbeth chart' """ @@ -40,20 +40,20 @@ def find_macbeth(Cam,img,mac_config=(0,0)): Reference macbeth chart is created that will be correlated with the located macbeth chart guess to produce a confidence value for the match. """ - ref = cv2.imread(Cam.path +'ctt_ref.pgm',flags=cv2.IMREAD_GRAYSCALE) + ref = cv2.imread(Cam.path +'ctt_ref.pgm', flags=cv2.IMREAD_GRAYSCALE) ref_w = 120 ref_h = 80 - rc1 = (0,0) - rc2 = (0,ref_h) - rc3 = (ref_w,ref_h) - rc4 = (ref_w,0) - ref_corns = np.array((rc1,rc2,rc3,rc4),np.float32) - ref_data = (ref,ref_w,ref_h,ref_corns) + rc1 = (0, 0) + rc2 = (0, ref_h) + rc3 = (ref_w, ref_h) + rc4 = (ref_w, 0) + ref_corns = np.array((rc1, rc2, rc3, rc4), np.float32) + ref_data = (ref, ref_w, ref_h, ref_corns) """ locate macbeth chart """ - cor,mac,coords,msg = get_macbeth_chart(img,ref_data) + cor, mac, coords, msg = get_macbeth_chart(img, ref_data) """ following bits of code tries to fix common problems with simple @@ -68,20 +68,20 @@ def find_macbeth(Cam,img,mac_config=(0,0)): """ if cor < 0.75: a = 2 - img_br = cv2.convertScaleAbs(img,alpha=a,beta=0) - cor_b,mac_b,coords_b,msg_b = get_macbeth_chart(img_br,ref_data) + img_br = cv2.convertScaleAbs(img, alpha=a, beta=0) + cor_b, mac_b, coords_b, msg_b = get_macbeth_chart(img_br, ref_data) if cor_b > cor: - cor,mac,coords,msg = cor_b,mac_b,coords_b,msg_b + cor, mac, coords, msg = cor_b, mac_b, coords_b, msg_b """ brighten image 4x """ if cor < 0.75: a = 4 - img_br = cv2.convertScaleAbs(img,alpha=a,beta=0) - cor_b,mac_b,coords_b,msg_b = get_macbeth_chart(img_br,ref_data) + img_br = cv2.convertScaleAbs(img, alpha=a, beta=0) + cor_b, mac_b, coords_b, msg_b = get_macbeth_chart(img_br, ref_data) if cor_b > cor: - cor,mac,coords,msg = cor_b,mac_b,coords_b,msg_b + cor, mac, coords, msg = cor_b, mac_b, coords_b, msg_b """ In case macbeth chart is too small, take a selection of the image and @@ -115,7 +115,7 @@ def find_macbeth(Cam,img,mac_config=(0,0)): get size of image """ shape = list(img.shape[:2]) - w,h = shape + w, h = shape """ set dimensions of the subselection and the step along each axis between selections @@ -129,9 +129,9 @@ def find_macbeth(Cam,img,mac_config=(0,0)): """ for i in range(3): for j in range(3): - w_s,h_s = i*w_inc,j*h_inc - img_sel = img[w_s:w_s+w_sel,h_s:h_s+h_sel] - cor_ij,mac_ij,coords_ij,msg_ij = get_macbeth_chart(img_sel,ref_data) + w_s, h_s = i*w_inc, j*h_inc + img_sel = img[w_s:w_s+w_sel, h_s:h_s+h_sel] + cor_ij, mac_ij, coords_ij, msg_ij = get_macbeth_chart(img_sel, ref_data) """ if the correlation is better than the best then record the scale and current subselection at which macbeth chart was @@ -139,9 +139,9 @@ def find_macbeth(Cam,img,mac_config=(0,0)): """ if cor_ij > cor: cor = cor_ij - mac,coords,msg = mac_ij,coords_ij,msg_ij - ii,jj = i,j - w_best,h_best = w_inc,h_inc + mac, coords, msg = mac_ij, coords_ij, msg_ij + ii, jj = i, j + w_best, h_best = w_inc, h_inc d_best = 1 @@ -151,21 +151,21 @@ def find_macbeth(Cam,img,mac_config=(0,0)): if cor < 0.75: imgs = [] shape = list(img.shape[:2]) - w,h = shape + w, h = shape w_sel = int(w/2) h_sel = int(h/2) w_inc = int(w/8) h_inc = int(h/8) for i in range(5): for j in range(5): - w_s,h_s = i*w_inc,j*h_inc - img_sel = img[w_s:w_s+w_sel,h_s:h_s+h_sel] - cor_ij,mac_ij,coords_ij,msg_ij = get_macbeth_chart(img_sel,ref_data) + w_s, h_s = i*w_inc, j*h_inc + img_sel = img[w_s:w_s+w_sel, h_s:h_s+h_sel] + cor_ij, mac_ij, coords_ij, msg_ij = get_macbeth_chart(img_sel, ref_data) if cor_ij > cor: cor = cor_ij - mac,coords,msg = mac_ij,coords_ij,msg_ij - ii,jj = i,j - w_best,h_best = w_inc,h_inc + mac, coords, msg = mac_ij, coords_ij, msg_ij + ii, jj = i, j + w_best, h_best = w_inc, h_inc d_best = 2 """ @@ -183,41 +183,41 @@ def find_macbeth(Cam,img,mac_config=(0,0)): if cor < 0.75 and d_best > 1 : imgs = [] shape = list(img.shape[:2]) - w,h = shape + w, h = shape w_sel = int(w/3) h_sel = int(h/3) w_inc = int(w/12) h_inc = int(h/12) for i in range(9): for j in range(9): - w_s,h_s = i*w_inc,j*h_inc - img_sel = img[w_s:w_s+w_sel,h_s:h_s+h_sel] - cor_ij,mac_ij,coords_ij,msg_ij = get_macbeth_chart(img_sel,ref_data) + w_s, h_s = i*w_inc, j*h_inc + img_sel = img[w_s:w_s+w_sel, h_s:h_s+h_sel] + cor_ij, mac_ij, coords_ij, msg_ij = get_macbeth_chart(img_sel, ref_data) if cor_ij > cor: cor = cor_ij - mac,coords,msg = mac_ij,coords_ij,msg_ij - ii,jj = i,j - w_best,h_best = w_inc,h_inc + mac, coords, msg = mac_ij, coords_ij, msg_ij + ii, jj = i, j + w_best, h_best = w_inc, h_inc d_best = 3 if cor < 0.75 and d_best > 2: imgs = [] shape = list(img.shape[:2]) - w,h = shape + w, h = shape w_sel = int(w/4) h_sel = int(h/4) w_inc = int(w/16) h_inc = int(h/16) for i in range(13): for j in range(13): - w_s,h_s = i*w_inc,j*h_inc - img_sel = img[w_s:w_s+w_sel,h_s:h_s+h_sel] - cor_ij,mac_ij,coords_ij,msg_ij = get_macbeth_chart(img_sel,ref_data) + w_s, h_s = i*w_inc, j*h_inc + img_sel = img[w_s:w_s+w_sel, h_s:h_s+h_sel] + cor_ij, mac_ij, coords_ij, msg_ij = get_macbeth_chart(img_sel, ref_data) if cor_ij > cor: cor = cor_ij - mac,coords,msg = mac_ij,coords_ij,msg_ij - ii,jj = i,j - w_best,h_best = w_inc,h_inc + mac, coords, msg = mac_ij, coords_ij, msg_ij + ii, jj = i, j + w_best, h_best = w_inc, h_inc """ Transform coordinates from subselection to original image @@ -241,7 +241,7 @@ def find_macbeth(Cam,img,mac_config=(0,0)): if msg == success_msg: coords_fit = coords Cam.log += '\nMacbeth chart vertices:\n' - Cam.log += '{}'.format(2*np.round(coords_fit[0][0]),0) + Cam.log += '{}'.format(2*np.round(coords_fit[0][0]), 0) """ if correlation is lower than 0.75 there may be a risk of macbeth chart corners not having been located properly. It might be worth running @@ -253,8 +253,8 @@ def find_macbeth(Cam,img,mac_config=(0,0)): if cor < 0.75: print('Caution: Low confidence guess!') Cam.log += 'WARNING: Low confidence guess!' - # cv2.imshow('MacBeth',mac) - # represent(mac,'MacBeth chart') + # cv2.imshow('MacBeth', mac) + # represent(mac, 'MacBeth chart') """ extract data from coords_fit and plot on original image @@ -269,7 +269,7 @@ def find_macbeth(Cam,img,mac_config=(0,0)): """ for vert in verts: p = tuple(np.round(vert).astype(np.int32)) - cv2.circle(copy,p,10,1,-1) + cv2.circle(copy, p, 10, 1, -1) """ draw circles at centres of squares """ @@ -281,17 +281,17 @@ def find_macbeth(Cam,img,mac_config=(0,0)): grey circle everywhere else. """ if i == 3: - cv2.circle(copy,p,8,0,-1) + cv2.circle(copy, p, 8, 0, -1) elif i == 23: - cv2.circle(copy,p,8,1,-1) + cv2.circle(copy, p, 8, 1, -1) else: - cv2.circle(copy,p,8,0.5,-1) - copy,_ = reshape(copy,400) + cv2.circle(copy, p, 8, 0.5, -1) + copy, _ = reshape(copy, 400) represent(copy) return(coords_fit) -def get_macbeth_chart(img,ref_data): +def get_macbeth_chart(img, ref_data): """ function returns coordinates of macbeth chart vertices and square centres, along with an error/success message for debugging purposes. Additionally, @@ -316,7 +316,7 @@ def get_macbeth_chart(img,ref_data): """ get reference macbeth chart data """ - (ref,ref_w,ref_h,ref_corns) = ref_data + (ref, ref_w, ref_h, ref_corns) = ref_data """ the code will raise and catch a MacbethError in case of a problem, trying @@ -327,10 +327,10 @@ def get_macbeth_chart(img,ref_data): obtain image, convert to grayscale and normalise """ src = img - src,factor = reshape(src,200) + src, factor = reshape(src, 200) original=src.copy() a = 125/np.average(src) - src_norm = cv2.convertScaleAbs(src,alpha=a,beta=0) + src_norm = cv2.convertScaleAbs(src, alpha=a, beta=0) """ This code checks if there are seperate colour channels. In the past the macbeth locator ran on jpgs and this makes it robust to different @@ -338,11 +338,11 @@ def get_macbeth_chart(img,ref_data): average bayer channel so coordinates must be doubled. This is best done in img_load.py in the get_patches method. The - coordinates and image width,height must be divided by two if the + coordinates and image width, height must be divided by two if the macbeth locator has been run on a demosaicked image. """ if len(src_norm.shape) == 3: - src_bw = cv2.cvtColor(src_norm,cv2.COLOR_BGR2GRAY) + src_bw = cv2.cvtColor(src_norm, cv2.COLOR_BGR2GRAY) else: src_bw = src_norm original_bw = src_bw.copy() @@ -350,20 +350,20 @@ def get_macbeth_chart(img,ref_data): obtain image edges """ sigma=2 - src_bw = cv2.GaussianBlur(src_bw,(0,0),sigma) - t1,t2 = 50,100 - edges = cv2.Canny(src_bw,t1,t2) + src_bw = cv2.GaussianBlur(src_bw, (0, 0), sigma) + t1, t2 = 50, 100 + edges = cv2.Canny(src_bw, t1, t2) """ dilate edges to prevent self-intersections in contours """ k_size = 2 - kernel = np.ones((k_size,k_size)) + kernel = np.ones((k_size, k_size)) its = 1 - edges = cv2.dilate(edges,kernel,iterations=its) + edges = cv2.dilate(edges, kernel, iterations=its) """ find Contours in image """ - conts,_ = cv2.findContours(edges, + conts, _ = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE) if len(conts) == 0: @@ -380,11 +380,11 @@ def get_macbeth_chart(img,ref_data): epsilon = 0.07 conts_per = [] for i in range(len(conts)): - per = cv2.arcLength(conts[i],True) + per = cv2.arcLength(conts[i], True) poly = cv2.approxPolyDP(conts[i], - epsilon*per,True) + epsilon*per, True) if len(poly) == 4 and cv2.isContourConvex(poly): - conts_per.append((poly,per)) + conts_per.append((poly, per)) if len(conts_per) == 0: raise MacbethError( @@ -399,11 +399,11 @@ def get_macbeth_chart(img,ref_data): """ sort contours by perimeter and get perimeters within percent of median """ - conts_per = sorted(conts_per,key=lambda x:x[1]) + conts_per = sorted(conts_per, key=lambda x: x[1]) med_per = conts_per[int(len(conts_per)/2)][1] side = med_per/4 perc = 0.1 - med_low,med_high = med_per*(1-perc),med_per*(1+perc) + med_low, med_high = med_per*(1-perc), med_per*(1+perc) squares = [] for i in conts_per: if med_low <= i[1] and med_high >= i[1]: @@ -412,7 +412,7 @@ def get_macbeth_chart(img,ref_data): """ obtain coordinates of nomralised macbeth and squares """ - square_verts,mac_norm = get_square_verts(0.06) + square_verts, mac_norm = get_square_verts(0.06) """ for each square guess, find 24 possible macbeth chart centres """ @@ -432,11 +432,11 @@ def get_macbeth_chart(img,ref_data): """ reorder vertices to prevent 'hourglass shape' """ - square = sorted(square,key=lambda x:x[0]) - square_1 = sorted(square[:2],key=lambda x:x[1]) - square_2 = sorted(square[2:],key=lambda x:-x[1]) - square = np.array(np.concatenate((square_1,square_2)),np.float32) - square = np.reshape(square,(4,2)).astype(np.float32) + square = sorted(square, key=lambda x: x[0]) + square_1 = sorted(square[:2], key=lambda x: x[1]) + square_2 = sorted(square[2:], key=lambda x: -x[1]) + square = np.array(np.concatenate((square_1, square_2)), np.float32) + square = np.reshape(square, (4, 2)).astype(np.float32) squares[i] = square """ find 24 possible macbeth chart centres by trasnforming normalised @@ -444,8 +444,8 @@ def get_macbeth_chart(img,ref_data): """ for j in range(len(square_verts)): verts = square_verts[j] - p_mat = cv2.getPerspectiveTransform(verts,square) - mac_guess = cv2.perspectiveTransform(mac_norm,p_mat) + p_mat = cv2.getPerspectiveTransform(verts, square) + mac_guess = cv2.perspectiveTransform(mac_norm, p_mat) mac_guess = np.round(mac_guess).astype(np.int32) """ keep only if candidate macbeth is within image border @@ -465,7 +465,7 @@ def get_macbeth_chart(img,ref_data): if in_border: mac_mid = np.mean(mac_guess, axis=1) - mac_mids.append([mac_mid,(i,j)]) + mac_mids.append([mac_mid, (i, j)]) if len(mac_mids) == 0: raise MacbethError( @@ -497,14 +497,14 @@ def get_macbeth_chart(img,ref_data): special case of only one valid centre found (probably not needed) """ clus_list = [] - clus_list.append([mac_mids,len(mac_mids)]) + clus_list.append([mac_mids, len(mac_mids)]) else: clustering.fit(mac_mids_list) # try: # clustering.fit(mac_mids_list) # except RuntimeWarning as error: - # return(0,None,None,error) + # return(0, None, None, error) """ create list of all clusters @@ -512,19 +512,19 @@ def get_macbeth_chart(img,ref_data): clus_list = [] if clustering.n_clusters_ >1: for i in range(clustering.labels_.max()+1): - indices = [j for j,x in enumerate(clustering.labels_) if x == i] + indices = [j for j, x in enumerate(clustering.labels_) if x == i] clus = [] for index in indices: clus.append(mac_mids[index]) - clus_list.append([clus,len(clus)]) - clus_list.sort(key=lambda x:-x[1]) + clus_list.append([clus, len(clus)]) + clus_list.sort(key=lambda x: -x[1]) elif clustering.n_clusters_ == 1: """ special case of only one cluster found """ # print('only 1 cluster') - clus_list.append([mac_mids,len(mac_mids)]) + clus_list.append([mac_mids, len(mac_mids)]) else: raise MacbethError( '\nWARNING: No macebth chart found!' @@ -542,19 +542,19 @@ def get_macbeth_chart(img,ref_data): if clus_list[i][1] < clus_len_max * clus_tol: clus_list = clus_list[:i] break - cent = np.mean(clus_list[i][0],axis=0)[0] + cent = np.mean(clus_list[i][0], axis=0)[0] clus_list[i].append(cent) """ represent most popular cluster centroids """ # copy = original_bw.copy() - # copy = cv2.cvtColor(copy,cv2.COLOR_GRAY2RGB) - # copy = cv2.resize(copy,None,fx=2,fy=2) + # copy = cv2.cvtColor(copy, cv2.COLOR_GRAY2RGB) + # copy = cv2.resize(copy, None, fx=2, fy=2) # for clus in clus_list: # centroid = tuple(2*np.round(clus[2]).astype(np.int32)) - # cv2.circle(copy,centroid,7,(255,0,0),-1) - # cv2.circle(copy,centroid,2,(0,0,255),-1) + # cv2.circle(copy, centroid, 7, (255, 0, 0), -1) + # cv2.circle(copy, centroid, 2, (0, 0, 255), -1) # represent(copy) """ @@ -578,7 +578,7 @@ def get_macbeth_chart(img,ref_data): ref_cents = [] i_list = [p[1][0] for p in clus] for point in clus: - i,j = point[1] + i, j = point[1] """ remove any square that voted for two different points within the same cluster. This causes the same point in the image to be @@ -591,7 +591,7 @@ def get_macbeth_chart(img,ref_data): """ if i_list.count(i) == 1: square = squares_raw[i] - sq_cent = np.mean(square,axis=0) + sq_cent = np.mean(square, axis=0) ref_cent = reference[j] sq_cents.append(sq_cent) ref_cents.append(ref_cent) @@ -614,7 +614,7 @@ def get_macbeth_chart(img,ref_data): """ find best fit transform from normalised centres to image """ - h_mat,mask = cv2.findHomography(ref_cents,sq_cents) + h_mat, mask = cv2.findHomography(ref_cents, sq_cents) if 'None' in str(type(h_mat)): raise MacbethError( '\nERROR\n' @@ -623,8 +623,8 @@ def get_macbeth_chart(img,ref_data): """ transform normalised corners and centres into image space """ - mac_fit = cv2.perspectiveTransform(mac_norm,h_mat) - mac_cen_fit = cv2.perspectiveTransform(np.array([reference]),h_mat) + mac_fit = cv2.perspectiveTransform(mac_norm, h_mat) + mac_cen_fit = cv2.perspectiveTransform(np.array([reference]), h_mat) """ transform located corners into reference space """ @@ -633,18 +633,18 @@ def get_macbeth_chart(img,ref_data): np.array([ref_corns]) ) map_to_ref = cv2.warpPerspective( - original_bw,ref_mat, - (ref_w,ref_h) + original_bw, ref_mat, + (ref_w, ref_h) ) """ normalise brigthness """ a = 125/np.average(map_to_ref) - map_to_ref = cv2.convertScaleAbs(map_to_ref,alpha=a,beta=0) + map_to_ref = cv2.convertScaleAbs(map_to_ref, alpha=a, beta=0) """ find correlation with bw reference macbeth """ - cor = correlate(map_to_ref,ref) + cor = correlate(map_to_ref, ref) """ keep only if best correlation """ @@ -660,21 +660,21 @@ def get_macbeth_chart(img,ref_data): upside-down """ mac_fit_inv = np.array( - ([[mac_fit[0][2],mac_fit[0][3], - mac_fit[0][0],mac_fit[0][1]]]) + ([[mac_fit[0][2], mac_fit[0][3], + mac_fit[0][0], mac_fit[0][1]]]) ) - mac_cen_fit_inv = np.flip(mac_cen_fit,axis=1) + mac_cen_fit_inv = np.flip(mac_cen_fit, axis=1) ref_mat = cv2.getPerspectiveTransform( mac_fit_inv, np.array([ref_corns]) ) map_to_ref = cv2.warpPerspective( - original_bw,ref_mat, - (ref_w,ref_h) + original_bw, ref_mat, + (ref_w, ref_h) ) a = 125/np.average(map_to_ref) - map_to_ref = cv2.convertScaleAbs(map_to_ref,alpha=a,beta=0) - cor = correlate(map_to_ref,ref) + map_to_ref = cv2.convertScaleAbs(map_to_ref, alpha=a, beta=0) + cor = correlate(map_to_ref, ref) if cor > max_cor: max_cor = cor best_map = map_to_ref @@ -704,45 +704,45 @@ def get_macbeth_chart(img,ref_data): draw macbeth corners and centres on image """ copy = original.copy() - copy = cv2.resize(original,None,fx=2,fy=2) - # print('correlation = {}'.format(round(max_cor,2))) + copy = cv2.resize(original, None, fx=2, fy=2) + # print('correlation = {}'.format(round(max_cor, 2))) for point in best_fit[0]: - point = np.array(point,np.float32) + point = np.array(point, np.float32) point = tuple(2*np.round(point).astype(np.int32)) - cv2.circle(copy,point,4,(255,0,0),-1) + cv2.circle(copy, point, 4, (255, 0, 0), -1) for point in best_cen_fit[0]: - point = np.array(point,np.float32) + point = np.array(point, np.float32) point = tuple(2*np.round(point).astype(np.int32)) - cv2.circle(copy,point,4,(0,0,255),-1) + cv2.circle(copy, point, 4, (0, 0, 255), -1) copy = copy.copy() - cv2.circle(copy,point,4,(0,0,255),-1) + cv2.circle(copy, point, 4, (0, 0, 255), -1) """ represent coloured macbeth in reference space """ best_map_col = cv2.warpPerspective( - original,best_ref_mat,(ref_w,ref_h) + original, best_ref_mat, (ref_w, ref_h) ) best_map_col = cv2.resize( - best_map_col,None,fx=4,fy=4 + best_map_col, None, fx=4, fy=4 ) a = 125/np.average(best_map_col) best_map_col_norm = cv2.convertScaleAbs( - best_map_col,alpha=a,beta=0 + best_map_col, alpha=a, beta=0 ) - # cv2.imshow('Macbeth',best_map_col) + # cv2.imshow('Macbeth', best_map_col) # represent(copy) """ rescale coordinates to original image size """ - fit_coords = (best_fit/factor,best_cen_fit/factor) + fit_coords = (best_fit/factor, best_cen_fit/factor) - return(max_cor,best_map_col_norm,fit_coords,success_msg) + return(max_cor, best_map_col_norm, fit_coords, success_msg) """ catch macbeth errors and continue with code """ except MacbethError as error: - return(0,None,None,error) + return(0, None, None, error) diff --git a/utils/raspberrypi/ctt/ctt_noise.py b/utils/raspberrypi/ctt/ctt_noise.py index b84cf0ca..f258bc6d 100644 --- a/utils/raspberrypi/ctt/ctt_noise.py +++ b/utils/raspberrypi/ctt/ctt_noise.py @@ -12,7 +12,7 @@ Find noise standard deviation and fit to model: noise std = a + b*sqrt(pixel mean) """ -def noise(Cam,Img,plot): +def noise(Cam, Img, plot): Cam.log += '\nProcessing image: {}'.format(Img.name) stds = [] means = [] @@ -36,14 +36,14 @@ def noise(Cam,Img,plot): """ stds = np.array(stds) means = np.array(means) - means = np.clip(np.array(means),0,None) + means = np.clip(np.array(means), 0, None) sq_means = np.sqrt(means) """ least squares fit model """ - fit = np.polyfit(sq_means,stds,1) + fit = np.polyfit(sq_means, stds, 1) Cam.log += '\nBlack level = {}'.format(Img.blacklevel_16) Cam.log += '\nNoise profile: offset = {}'.format(int(fit[1])) Cam.log += ' slope = {:.3f}'.format(fit[0]) @@ -59,8 +59,8 @@ def noise(Cam,Img,plot): fit_score_norm = fit_score - fit_std anom_ind = np.where(fit_score_norm > 1) fit_score_norm.sort() - sq_means_clean = np.delete(sq_means,anom_ind) - stds_clean = np.delete(stds,anom_ind) + sq_means_clean = np.delete(sq_means, anom_ind) + stds_clean = np.delete(stds, anom_ind) removed = len(stds) - len(stds_clean) if removed != 0: Cam.log += '\nIdentified and removed {} anomalies.'.format(removed) @@ -68,7 +68,7 @@ def noise(Cam,Img,plot): """ recalculate fit with outliers removed """ - fit = np.polyfit(sq_means_clean,stds_clean,1) + fit = np.polyfit(sq_means_clean, stds_clean, 1) Cam.log += '\nNoise profile: offset = {}'.format(int(fit[1])) Cam.log += ' slope = {:.3f}'.format(fit[0]) @@ -81,7 +81,7 @@ def noise(Cam,Img,plot): corrected = 1 ones = np.ones(len(means)) y_data = stds/sq_means - fit2 = np.polyfit(ones,y_data,0) + fit2 = np.polyfit(ones, y_data, 0) Cam.log += '\nOffset below zero. Fit recalculated with zero offset' Cam.log += '\nNoise profile: offset = 0' Cam.log += ' slope = {:.3f}'.format(fit2[0]) @@ -94,13 +94,13 @@ def noise(Cam,Img,plot): if plot: x = np.arange(sq_means.max()//0.88) fit_plot = x*fit[0] + fit[1] - plt.scatter(sq_means,stds,label='data',color='blue') - plt.scatter(sq_means[anom_ind],stds[anom_ind],color='orange',label='anomalies') - plt.plot(x,fit_plot,label='fit',color='red',ls=':') + plt.scatter(sq_means, stds, label='data', color='blue') + plt.scatter(sq_means[anom_ind], stds[anom_ind], color='orange', label='anomalies') + plt.plot(x, fit_plot, label='fit', color='red', ls=':') if fit[1] < 0: fit_plot_2 = x*fit2[0] - plt.plot(x,fit_plot_2,label='fit 0 intercept',color='green',ls='--') - plt.plot(0,0) + plt.plot(x, fit_plot_2, label='fit 0 intercept', color='green', ls='--') + plt.plot(0, 0) plt.title('Noise Plot\nImg: {}'.format(Img.str)) plt.legend(loc = 'upper left') plt.xlabel('Sqrt Pixel Value') @@ -116,7 +116,7 @@ def noise(Cam,Img,plot): """ Cam.log += '\n' if corrected: - fit = [fit2[0],0] + fit = [fit2[0], 0] return fit else: diff --git a/utils/raspberrypi/ctt/ctt_ransac.py b/utils/raspberrypi/ctt/ctt_ransac.py index e7c57137..62d5cde8 100644 --- a/utils/raspberrypi/ctt/ctt_ransac.py +++ b/utils/raspberrypi/ctt/ctt_ransac.py @@ -11,59 +11,59 @@ scale = 2 """ constructs normalised macbeth chart corners for ransac algorithm """ -def get_square_verts(c_err = 0.05,scale = scale): +def get_square_verts(c_err = 0.05, scale = scale): """ define macbeth chart corners """ - b_bord_x,b_bord_y = scale*8.5,scale*13 + b_bord_x, b_bord_y = scale*8.5, scale*13 s_bord = 6*scale side = 41*scale x_max = side*6 + 5*s_bord + 2*b_bord_x y_max = side*4 + 3*s_bord + 2*b_bord_y - c1 = (0,0) - c2 = (0,y_max) - c3 = (x_max,y_max) - c4 = (x_max,0) - mac_norm = np.array((c1,c2,c3,c4),np.float32) + c1 = (0, 0) + c2 = (0, y_max) + c3 = (x_max, y_max) + c4 = (x_max, 0) + mac_norm = np.array((c1, c2, c3, c4), np.float32) mac_norm = np.array([ mac_norm ]) square_verts = [] - square_0 = np.array(((0,0),(0,side), - (side,side),(side,0)),np.float32) - offset_0 = np.array((b_bord_x,b_bord_y),np.float32) + square_0 = np.array(((0, 0), (0, side), + (side, side), (side, 0)), np.float32) + offset_0 = np.array((b_bord_x, b_bord_y), np.float32) c_off = side * c_err - offset_cont = np.array(((c_off,c_off),(c_off,-c_off), - (-c_off,-c_off),(-c_off,c_off)),np.float32) + offset_cont = np.array(((c_off, c_off), (c_off, -c_off), + (-c_off, -c_off), (-c_off, c_off)), np.float32) square_0 += offset_0 square_0 += offset_cont """ define macbeth square corners """ for i in range(6): - shift_i = np.array(((i*side,0),(i*side,0), - (i*side,0),(i*side,0)),np.float32) - shift_bord =np.array(((i*s_bord,0),(i*s_bord,0), - (i*s_bord,0),(i*s_bord,0)),np.float32) + shift_i = np.array(((i*side, 0), (i*side, 0), + (i*side, 0), (i*side, 0)), np.float32) + shift_bord =np.array(((i*s_bord, 0), (i*s_bord, 0), + (i*s_bord, 0), (i*s_bord, 0)), np.float32) square_i = square_0 + shift_i + shift_bord for j in range(4): - shift_j = np.array(((0,j*side),(0,j*side), - (0,j*side),(0,j*side)),np.float32) - shift_bord = np.array(((0,j*s_bord), - (0,j*s_bord),(0,j*s_bord), - (0,j*s_bord)),np.float32) + shift_j = np.array(((0, j*side), (0, j*side), + (0, j*side), (0, j*side)), np.float32) + shift_bord = np.array(((0, j*s_bord), + (0, j*s_bord), (0, j*s_bord), + (0, j*s_bord)), np.float32) square_j = square_i + shift_j + shift_bord square_verts.append(square_j) # print('square_verts') # print(square_verts) - return np.array(square_verts,np.float32),mac_norm + return np.array(square_verts, np.float32), mac_norm -def get_square_centres(c_err = 0.05,scale=scale): +def get_square_centres(c_err = 0.05, scale=scale): """ define macbeth square centres """ - verts,mac_norm = get_square_verts(c_err,scale=scale) + verts, mac_norm = get_square_verts(c_err, scale=scale) - centres = np.mean(verts,axis = 1) + centres = np.mean(verts, axis = 1) # print('centres') # print(centres) - return np.array(centres,np.float32) + return np.array(centres, np.float32) diff --git a/utils/raspberrypi/ctt/ctt_tools.py b/utils/raspberrypi/ctt/ctt_tools.py index 5a5cf54d..67e882a2 100644 --- a/utils/raspberrypi/ctt/ctt_tools.py +++ b/utils/raspberrypi/ctt/ctt_tools.py @@ -26,7 +26,7 @@ readability in the main files. obtain config values, unless it doesnt exist, in which case pick default Furthermore, it can check if the input is the correct type """ -def get_config(dictt,key,default,ttype): +def get_config(dictt, key, default, ttype): try: val = dictt[key] if ttype == 'string': @@ -57,16 +57,16 @@ def parse_input(): raise ArgError('\n\nERROR! Enter value for each arguent passed.') params = arguments [0::2] vals = arguments [1::2] - args_dict = dict(zip(params,vals)) - json_output = get_config(args_dict,'-o',None,'string') - directory = get_config(args_dict,'-i',None,'string') - config = get_config(args_dict,'-c',None,'string') - log_path = get_config(args_dict,'-l',None,'string') + args_dict = dict(zip(params, vals)) + json_output = get_config(args_dict, '-o', None, 'string') + directory = get_config(args_dict, '-i', None, 'string') + config = get_config(args_dict, '-c', None, 'string') + log_path = get_config(args_dict, '-l', None, 'string') if directory == None: raise ArgError('\n\nERROR! No input directory given.') if json_output == None: raise ArgError('\n\nERROR! No output json given.') - return json_output,directory,config,log_path + return json_output, directory, config, log_path """ custom arg and macbeth error class """ @@ -78,10 +78,10 @@ class MacbethError(Exception): """ correlation function to quantify match """ -def correlate(im1,im2): +def correlate(im1, im2): f1 = im1.flatten() f2 = im2.flatten() - cor = np.corrcoef(f1,f2) + cor = np.corrcoef(f1, f2) return cor[0][1] """ @@ -97,13 +97,13 @@ def get_photos(directory='photos'): """ display image for debugging... read at your own risk... """ -def represent(img,name='image'): +def represent(img, name='image'): # if type(img) == tuple or type(img) == list: # for i in range(len(img)): # name = 'image {}'.format(i) - # cv2.imshow(name,img[i]) + # cv2.imshow(name, img[i]) # else: - # cv2.imshow(name,img) + # cv2.imshow(name, img) # cv2.waitKey(0) # cv2.destroyAllWindows() # return 0 @@ -112,11 +112,11 @@ def represent(img,name='image'): with their mouse to close the window.... therefore matplotlib is used.... (thanks a lot opencv) """ - grid = plt.GridSpec(22,1) - plt.subplot(grid[:19,0]) - plt.imshow(img,cmap='gray') + grid = plt.GridSpec(22, 1) + plt.subplot(grid[:19, 0]) + plt.imshow(img, cmap='gray') plt.axis('off') - plt.subplot(grid[21,0]) + plt.subplot(grid[21, 0]) plt.title('press \'q\' to continue') plt.axis('off') plt.show() @@ -124,7 +124,7 @@ def represent(img,name='image'): # f = plt.figure() # ax = f.add_subplot(211) # ax2 = f.add_subplot(122) - # ax.imshow(img,cmap='gray') + # ax.imshow(img, cmap='gray') # ax.axis('off') # ax2.set_figheight(2) # ax2.title('press \'q\' to continue') @@ -136,6 +136,6 @@ def represent(img,name='image'): reshape image to fixed width without distorting returns image and scale factor """ -def reshape(img,width): +def reshape(img, width): factor = width/img.shape[0] - return cv2.resize(img,None,fx=factor,fy=factor),factor + return cv2.resize(img, None, fx=factor, fy=factor), factor |