8
8
9
9
import argparse
10
10
import json
11
+ import numpy as np
11
12
import sys
12
13
13
14
from ctt_pretty_print_json import pretty_print
15
+ from ctt_pisp import grid_size as grid_size_pisp
16
+ from ctt_pisp import json_template as json_template_pisp
17
+ from ctt_vc4 import grid_size as grid_size_vc4
18
+ from ctt_vc4 import json_template as json_template_vc4
14
19
15
20
16
- def convert_v2 ( in_json : dict ) -> str :
21
+ def interp_2d ( in_ls , src_w , src_h , dst_w , dst_h ) :
17
22
18
- if 'version' in in_json .keys () and in_json ['version' ] != 1.0 :
19
- print (f'The JSON config reports version { in_json ["version" ]} that is incompatible with this tool.' )
20
- sys .exit (- 1 )
23
+ out_ls = np .zeros ((dst_h , dst_w ))
24
+ for i in range (src_h ):
25
+ out_ls [i ] = np .interp (np .linspace (0 , dst_w - 1 , dst_w ),
26
+ np .linspace (0 , dst_w - 1 , src_w ),
27
+ in_ls [i ])
28
+ for i in range (dst_w ):
29
+ out_ls [:,i ] = np .interp (np .linspace (0 , dst_h - 1 , dst_h ),
30
+ np .linspace (0 , dst_h - 1 , src_h ),
31
+ out_ls [:src_h , i ])
32
+ return out_ls
21
33
22
- converted = {
23
- 'version' : 2.0 ,
24
- 'target' : 'bcm2835' ,
25
- 'algorithms' : [{algo : config } for algo , config in in_json .items ()]
26
- }
27
34
28
- return pretty_print (converted )
35
+ def convert_target (in_json : dict , target : str ):
36
+
37
+ src_w , src_h = grid_size_pisp if target == 'vc4' else grid_size_vc4
38
+ dst_w , dst_h = grid_size_vc4 if target == 'vc4' else grid_size_pisp
39
+ json_template = json_template_vc4 if target == 'vc4' else json_template_pisp
40
+
41
+ # ALSC grid sizes
42
+ alsc = next (algo for algo in in_json ['algorithms' ] if 'rpi.alsc' in algo )['rpi.alsc' ]
43
+ for colour in ['calibrations_Cr' , 'calibrations_Cb' ]:
44
+ if colour not in alsc :
45
+ continue
46
+ for temperature in alsc [colour ]:
47
+ in_ls = np .reshape (temperature ['table' ], (src_h , src_w ))
48
+ out_ls = interp_2d (in_ls , src_w , src_h , dst_w , dst_h )
49
+ temperature ['table' ] = np .round (out_ls .flatten (), 3 ).tolist ()
50
+
51
+ if 'luminance_lut' in alsc :
52
+ in_ls = np .reshape (alsc ['luminance_lut' ], (src_h , src_w ))
53
+ out_ls = interp_2d (in_ls , src_w , src_h , dst_w , dst_h )
54
+ alsc ['luminance_lut' ] = np .round (out_ls .flatten (), 3 ).tolist ()
55
+
56
+ # Denoise blocks
57
+ for i , algo in enumerate (in_json ['algorithms' ]):
58
+ if list (algo .keys ())[0 ] == 'rpi.sdn' :
59
+ in_json ['algorithms' ][i ] = {'rpi.denoise' : json_template ['rpi.sdn' ] if target == 'vc4' else json_template ['rpi.denoise' ]}
60
+ break
61
+
62
+ # AGC mode weights
63
+ agc = next (algo for algo in in_json ['algorithms' ] if 'rpi.agc' in algo )['rpi.agc' ]
64
+ if 'channels' in agc :
65
+ for i , channel in enumerate (agc ['channels' ]):
66
+ target_agc_metering = json_template ['rpi.agc' ]['channels' ][i ]['metering_modes' ]
67
+ for mode , v in channel ['metering_modes' ].items ():
68
+ v ['weights' ] = target_agc_metering [mode ]['weights' ]
69
+ else :
70
+ for mode , v in agc ["metering_modes" ].items ():
71
+ target_agc_metering = json_template ['rpi.agc' ]['channels' ][0 ]['metering_modes' ]
72
+ v ['weights' ] = target_agc_metering [mode ]['weights' ]
73
+
74
+ # HDR
75
+ if target == 'pisp' :
76
+ for i , algo in enumerate (in_json ['algorithms' ]):
77
+ if list (algo .keys ())[0 ] == 'rpi.hdr' :
78
+ in_json ['algorithms' ][i ] = {'rpi.hdr' : json_template ['rpi.hdr' ]}
79
+
80
+ return in_json
81
+
82
+
83
+ def convert_v2 (in_json : dict , target : str ) -> str :
84
+
85
+ if 'version' in in_json .keys () and in_json ['version' ] == 1.0 :
86
+ converted = {
87
+ 'version' : 2.0 ,
88
+ 'target' : target ,
89
+ 'algorithms' : [{algo : config } for algo , config in in_json .items ()]
90
+ }
91
+ else :
92
+ converted = in_json
93
+
94
+ # Convert between vc4 <-> pisp targets. This is a best effort thing.
95
+ if converted ['target' ] != target :
96
+ converted = convert_target (converted , target )
97
+ converted ['target' ] = target
98
+
99
+ grid_size = grid_size_vc4 [0 ] if target == 'vc4' else grid_size_pisp [0 ]
100
+ return pretty_print (converted , custom_elems = {'table' : grid_size , 'luminance_lut' : grid_size })
29
101
30
102
31
103
if __name__ == "__main__" :
32
104
parser = argparse .ArgumentParser (formatter_class = argparse .RawTextHelpFormatter , description =
33
- 'Convert the format of the Raspberry Pi camera tuning file from v1.0 to v2.0.\n ' )
105
+ 'Convert the format of the Raspberry Pi camera tuning file from v1.0 to v2.0 and/or the vc4 <-> pisp targets .\n ' )
34
106
parser .add_argument ('input' , type = str , help = 'Input tuning file.' )
107
+ parser .add_argument ('-t' , '--target' , type = str , help = 'Target platform.' ,
108
+ choices = ['pisp' , 'vc4' ], default = 'vc4' )
35
109
parser .add_argument ('output' , type = str , nargs = '?' ,
36
110
help = 'Output converted tuning file. If not provided, the input file will be updated in-place.' ,
37
111
default = None )
@@ -40,7 +114,7 @@ def convert_v2(in_json: dict) -> str:
40
114
with open (args .input , 'r' ) as f :
41
115
in_json = json .load (f )
42
116
43
- out_json = convert_v2 (in_json )
117
+ out_json = convert_v2 (in_json , args . target )
44
118
45
119
with open (args .output if args .output is not None else args .input , 'w' ) as f :
46
120
f .write (out_json )
0 commit comments