diff --git a/utils/raspberrypi/ctt/convert_tuning.py b/utils/raspberrypi/ctt/convert_tuning.py
new file mode 100755
index 000000000000..3396bebe8f4e
--- /dev/null
+++ b/utils/raspberrypi/ctt/convert_tuning.py
@@ -0,0 +1,94 @@
+#!/bin/python3
+# Script to convert version 1.0 Raspberry Pi camera tuning files to version 2.0
+# and later.
+#
+# Copyright 2022 Raspberry Pi Ltd.
+
+import argparse
+import json
+import textwrap
+
+
+class Encoder(json.JSONEncoder):
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.indentation_level = 0
+        self.soft_break = 80
+        self.hard_break = 120
+
+    def encode(self, o):
+        if isinstance(o, (list, tuple)):
+            if not any(isinstance(el, (list, tuple, dict)) for el in o):
+                s = ', '.join(json.dumps(el) for el in o)
+                if len(s) > self.soft_break:
+                    self.indentation_level += 1
+                    t = textwrap.wrap(s, self.hard_break, break_long_words=False,
+                                      initial_indent=self.indent_str, subsequent_indent=self.indent_str)
+                    self.indentation_level -= 1
+                    output = '\n'.join(t)
+                    output = f'\n{self.indent_str}[\n{output}\n{self.indent_str}]'
+                else:
+                    output = f' [ {s} ]'
+                return output
+            else:
+                self.indentation_level += 1
+                output = [self.indent_str + self.encode(el) for el in o]
+                self.indentation_level -= 1
+                output = ',\n'.join(output)
+                return f' [\n{output}\n{self.indent_str}]'
+
+        elif isinstance(o, dict):
+            self.indentation_level += 1
+            output = []
+            for k, v in o.items():
+                sep = f'\n{self.indent_str}' if isinstance(v, dict) else ''
+                output.append(self.indent_str + f'{json.dumps(k)}:{sep}{self.encode(v)}')
+            self.indentation_level -= 1
+            output = ',\n'.join(output)
+            return f'{{\n{output}\n{self.indent_str}}}'
+
+        else:
+            return ' ' + json.dumps(o)
+
+    @property
+    def indent_str(self) -> str:
+        return ' ' * self.indentation_level * self.indent
+
+    def iterencode(self, o, **kwargs):
+        return self.encode(o)
+
+
+def convert_v2(in_json):
+
+    ver = 1.0 if 'version' not in in_json.keys() else in_json['version']
+
+    if ver != 1.0:
+        print(f'Cannot convert version {ver} format to version 2.0!')
+        exit(-1)
+
+    converted = {}
+    converted['version'] = 2.0
+    converted['algorithms'] = []
+
+    for k, v in in_json.items():
+        if k == 'version':
+            continue
+        converted['algorithms'].append(dict(zip([k], [v])))
+
+    return json.dumps(converted, cls=Encoder, indent=4, sort_keys=False)
+
+
+if __name__ == "__main__":
+    parser = argparse.ArgumentParser(description='Convert the format of the Raspberry Pi camera tuning file from v1 to v2.')
+    parser.add_argument('input', type=str, nargs=1, help='Input config file')
+    parser.add_argument('output', type=str, nargs='?', help='Output converted config file', default=None)
+    args = parser.parse_args()
+
+    with open(args.input[0], 'r') as f:
+        in_json = json.load(f)
+
+    out_json = convert_v2(in_json)
+
+    with open(args.output if args.output is not None else args.input[0], 'w') as f:
+        f.write(out_json)
