taotoolkit 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
taotoolkit/__init__.py ADDED
@@ -0,0 +1,81 @@
1
+ from .tao_common import (
2
+ debugCtrl,
3
+ logd,
4
+ logi,
5
+ logw,
6
+ loge,
7
+ logh,
8
+ logCallDebug,
9
+ logCallInfo,
10
+ logCallWarn,
11
+ logCallHigh,
12
+ logCallErr,
13
+ pCmd,
14
+ rCmd,
15
+ oCmd,
16
+ exit,
17
+ eExit,
18
+ iExit,
19
+ createFolder,
20
+ fileExist,
21
+ findFilesBySuffixKeyword,
22
+ normalize_args,
23
+ register_command,
24
+ )
25
+
26
+ # 导入各模块
27
+
28
+ from .tao_device import deviceMain as deviceMain, printHelp as deviceHelp, DevOp
29
+ from .tao_flash import flashMain as flashMain, printHelp as flashHelp, jenkinsTool
30
+ from .tao_tuning import tuningMain as tuningMain, printHelp as tuningHelp, asrCamOp
31
+ from .tao_cmdTool import cmdToolMain as cmdToolMain, printHelp as toolHelp
32
+ from .tao_vrfTool import vrfToolMain as vrfToolMain, printHelp as vrfHelp
33
+ from .tao_camDvt import camDvtMain as camDvtMain, printHelp as camDvtHelp, CamDvt
34
+
35
+
36
+ from .asrVrf import Vrf
37
+
38
+ __version__ = "1.0.0"
39
+
40
+ __all__ = [
41
+ "debugCtrl",
42
+ "logd",
43
+ "logi",
44
+ "logw",
45
+ "loge",
46
+ "logh",
47
+ "logCallDebug",
48
+ "logCallInfo",
49
+ "logCallWarn",
50
+ "logCallHigh",
51
+ "logCallErr",
52
+ "pCmd",
53
+ "rCmd",
54
+ "oCmd",
55
+ "exit",
56
+ "eExit",
57
+ "iExit",
58
+ "createFolder",
59
+ "fileExist",
60
+ "findFilesBySuffixKeyword",
61
+ "normalize_args",
62
+ "register_command",
63
+ "deviceMain",
64
+ "deviceHelp",
65
+ "DevOp",
66
+ "flashMain",
67
+ "flashHelp",
68
+ "jenkinsTool",
69
+ "tuningMain",
70
+ "tuningHelp",
71
+ "asrCamOp",
72
+ "cmdToolMain",
73
+ "toolHelp",
74
+ "vrfToolMain",
75
+ "vrfHelp",
76
+ "camDvtMain",
77
+ "camDvtHelp",
78
+ "CamDvt",
79
+ "Vrf",
80
+ "__version__",
81
+ ]
taotoolkit/asrVrf.py ADDED
@@ -0,0 +1,322 @@
1
+ import sys
2
+ import os
3
+ import numpy as np
4
+ from typing import Optional, Tuple, Union, Any
5
+
6
+ try:
7
+ import matplotlib.pyplot as plt
8
+
9
+ HAS_PLT = True
10
+ except ImportError:
11
+ HAS_PLT = False
12
+
13
+
14
+ class VrfTail:
15
+ def __init__(self):
16
+ self.dataSize: int = 0
17
+ self.packPixelNum: int = 0
18
+ self.rowSize: int = 0
19
+ self.fileSize: int = 0
20
+ self.metaSize: int = 128
21
+ self.Width: np.uint16 = np.uint16(640)
22
+ self.Height: np.uint16 = np.uint16(480)
23
+ self.TGain: np.uint16 = np.uint16(16)
24
+ """ np.uint16: total gain, Q4 """
25
+ self.ExpoLine: np.uint16 = np.uint16(10)
26
+ self.VTS: np.uint16 = np.uint16(0)
27
+ self.AWBGainB: np.uint16 = np.uint16(128)
28
+ """ np.uint16: AWB B gain, Q7 """
29
+ self.AWBGainG: np.uint16 = np.uint16(128)
30
+ """ np.uint16: AWB G gain, Q7 """
31
+ self.AWBGainR: np.uint16 = np.uint16(128)
32
+ """ np.uint16: AWB R gain, Q7 """
33
+ self.AWBGainWriteB: np.uint16 = self.AWBGainB
34
+ self.AWBGainWriteGb: np.uint16 = self.AWBGainG
35
+ self.AWBGainWriteGr: np.uint16 = self.AWBGainG
36
+ self.AWBGainWriteR: np.uint16 = self.AWBGainR
37
+ self.BLC10b: np.uint8 = np.uint8(64)
38
+ """ np.uint16: Black Value in 10bit """
39
+ self.BayerOrder: np.uint8 = np.uint8(0)
40
+ """ np.uint16: Bayer pattern - 0:BGGR, 1:GBRG, 2:GRBG, 3:RGGB """
41
+ self.BLC12b: np.uint16 = np.uint16(int(self.BLC10b) * 4)
42
+ self.Reserve: np.ndarray = np.zeros(78, dtype=np.uint8)
43
+ self.WBGoldenRG: np.uint16 = np.uint16(0)
44
+ self.WBModuleBG: np.uint16 = np.uint16(0)
45
+ self.DrcGainDark: np.uint8 = np.uint8(16)
46
+ """ np.uint16: DrcGainDark, Q4 """
47
+ self.DrcGain: np.uint8 = np.uint8(16)
48
+ """ np.uint16: DrcGain, Q4 """
49
+ self.ExpoTime_us: np.uint32 = np.uint32(10)
50
+ """ np.uint16: exposure time, us """
51
+ self.Packed: np.uint8 = np.uint8(0) # 0-nopack, 1-pack
52
+ self.BitDepth: np.uint8 = np.uint8(10)
53
+ """ np.uint16: BitDepth - 8,10,12,14,16 """
54
+ self.AGain: np.uint16 = np.uint16(16)
55
+ """ np.uint16: Analog Gain, Q4 """
56
+ self.VRFRevision: np.uint16 = np.uint16(41) # VRF 2.9
57
+ self.IDString: list[str] = ["V", "R", "F"]
58
+ self.unpackImage: np.ndarray = np.zeros((self.Height, self.Width), dtype=np.uint16)
59
+
60
+ def GetMeta(self) -> np.ndarray:
61
+ "Get Meta in np.uint16 format"
62
+ meta = np.zeros(64, dtype=np.uint16)
63
+ meta[0] = self.Width
64
+ meta[1] = self.Height
65
+ meta[2] = self.TGain
66
+ meta[3] = self.ExpoLine
67
+ meta[4] = self.VTS
68
+ meta[5] = self.AWBGainB
69
+ meta[6] = self.AWBGainG
70
+ meta[7] = self.AWBGainR
71
+ meta[8] = self.AWBGainB
72
+ meta[9] = self.AWBGainG
73
+ meta[10] = self.AWBGainG
74
+ meta[11] = self.AWBGainR
75
+ meta[12] = self.BLC10b + self.BayerOrder.astype(np.uint16) * 256
76
+ meta[13] = self.BLC12b
77
+ high = self.Reserve[1::2].astype(np.uint16) << 8 # 左移 8 位相当于 * 256
78
+ low = self.Reserve[::2].astype(np.uint16)
79
+ meta[14:53] = high + low
80
+ meta[53] = self.WBGoldenRG
81
+ meta[54] = self.WBModuleBG
82
+ meta[55] = self.WBGoldenRG
83
+ meta[56] = self.WBModuleBG
84
+ meta[57] = self.DrcGain.astype(np.uint16) * 256 + self.DrcGainDark.astype(np.uint16)
85
+ meta[58] = np.bitwise_and(self.ExpoTime_us, 65535)
86
+ meta[59] = np.right_shift(self.ExpoTime_us, 16)
87
+ meta[60] = self.BitDepth.astype(np.uint16) * 256 + self.Packed.astype(np.uint16)
88
+ meta[61] = self.AGain
89
+ meta[62] = self.VRFRevision + ord(self.IDString[0]) * 256
90
+ meta[63] = ord(self.IDString[1]) + ord(self.IDString[2]) * 256
91
+ return meta
92
+
93
+ def SetMeta(self, meta: np.ndarray) -> None:
94
+ "Set Meta in np.uint16 format"
95
+ if meta.shape != (64,):
96
+ print("SetMeta: meta.shape mismatch!")
97
+ return
98
+
99
+ self.Width = meta[0]
100
+ self.Height = meta[1]
101
+ self.TGain = meta[2]
102
+ self.ExpoLine = meta[3]
103
+ self.VTS = meta[4]
104
+ self.AWBGainB = meta[5]
105
+ self.AWBGainG = meta[6]
106
+ self.AWBGainR = meta[7]
107
+ self.AWBGainWriteB = self.AWBGainB
108
+ self.AWBGainWriteGb = self.AWBGainG
109
+ self.AWBGainWriteGr = self.AWBGainG
110
+ self.AWBGainWriteR = self.AWBGainR
111
+ self.BLC10b = np.bitwise_and(meta[12], 255)
112
+ self.BayerOrder = np.right_shift(meta[12], 8)
113
+ self.BLC12b = meta[13]
114
+ self.Reserve[1::2] = np.right_shift(meta[14:53], 8)
115
+ self.Reserve[::2] = np.bitwise_and(meta[14:53], 255)
116
+ self.WBGoldenRG = meta[53]
117
+ self.WBModuleBG = meta[54]
118
+ self.WBGoldenRG = meta[55]
119
+ self.WBModuleBG = meta[56]
120
+ self.DrcGainDark = np.bitwise_and(meta[57], 255)
121
+ self.DrcGain = np.right_shift(meta[57], 8)
122
+ self.ExpoTime_us = np.uint32(meta[58] + np.left_shift(meta[59], 16))
123
+ self.Packed = np.bitwise_and(meta[60], 255)
124
+ self.BitDepth = np.right_shift(meta[60], 8)
125
+ self.AGain = meta[61]
126
+ self.VRFRevision = np.bitwise_and(meta[62], 255)
127
+ self.IDString[0] = chr(np.right_shift(meta[62], 8))
128
+ self.IDString[1] = chr(np.bitwise_and(meta[63], 255))
129
+ self.IDString[2] = chr(np.right_shift(meta[63], 8))
130
+
131
+
132
+ class Vrf(VrfTail):
133
+ "VRF File Class"
134
+
135
+ def __init__(self):
136
+ VrfTail.__init__(self)
137
+
138
+ def Read(self, fname: str) -> None:
139
+ "Read Vrf File"
140
+ with open(fname, "rb") as fp:
141
+ data = np.fromfile(fp, dtype=np.uint16)
142
+
143
+ self.fileSize = os.path.getsize(fname)
144
+ self.SetMeta(data[-64:])
145
+ self._checkVrf()
146
+
147
+ if self.Packed:
148
+ # data[:-64] 是 uint16 数组,需要转为 bytes 传给 _unpackVrf
149
+ packed_data = data[:-64].tobytes()
150
+ self.unpackImage = self._unpackVrf(packed_data)
151
+ self.Packed = np.uint8(0)
152
+ else:
153
+ # 确保数据是 uint16 类型
154
+ self.unpackImage = data[:-64].astype(np.uint16)
155
+
156
+ # 重塑图像数据
157
+ self.unpackImage = self.unpackImage.reshape((int(self.Height), int(self.Width)))
158
+
159
+ def _getPackVrfSize(self) -> int:
160
+ if self.BitDepth == 8:
161
+ self.packPixelNum = 16
162
+ elif self.BitDepth == 10:
163
+ self.packPixelNum = 12
164
+ elif self.BitDepth == 12:
165
+ self.packPixelNum = 10
166
+ elif self.BitDepth == 16:
167
+ self.packPixelNum = 8
168
+ else:
169
+ print("VRF BitDepth wrong, please check it")
170
+ sys.exit()
171
+
172
+ self.rowSize = int(self.Width / self.packPixelNum) # in 128bit
173
+ if self.rowSize * self.packPixelNum < self.Width:
174
+ self.rowSize += 1
175
+ self.rowSize = self.rowSize << 4 # in byte
176
+ return self.rowSize * int(self.Height)
177
+
178
+ def _unpackPixels(self, packed: bytes) -> np.ndarray:
179
+ width = int(self.Width)
180
+ height = int(self.Height)
181
+ bitDepth = int(self.BitDepth)
182
+
183
+ if bitDepth == 10:
184
+ """
185
+ PackedRaw10 → Unpacked Raw16(每像素2字节,uint16 little-endian,值范围 0~1023)
186
+ 输出大小 = width * height * 2 字节
187
+ """
188
+ bytes_per_line_src = (width + 11) // 12 * 16
189
+
190
+ src = np.frombuffer(packed, dtype=np.uint8)
191
+ src = src[: height * bytes_per_line_src].reshape(height, bytes_per_line_src)
192
+
193
+ groups_per_line = (width + 11) // 12
194
+
195
+ # shape: (height, groups_per_line, 3, 5)
196
+ src_grouped = src[:, : groups_per_line * 16].reshape(height, groups_per_line, 16)
197
+ s = np.stack(
198
+ [
199
+ src_grouped[:, :, 0:5],
200
+ src_grouped[:, :, 5:10],
201
+ src_grouped[:, :, 10:15],
202
+ ],
203
+ axis=2,
204
+ )
205
+
206
+ s0 = s[:, :, :, 0].astype(np.uint16)
207
+ s1 = s[:, :, :, 1].astype(np.uint16)
208
+ s2 = s[:, :, :, 2].astype(np.uint16)
209
+ s3 = s[:, :, :, 3].astype(np.uint16)
210
+ s4 = s[:, :, :, 4].astype(np.uint16)
211
+
212
+ # 直接解出4个10bit像素,shape: (height, groups_per_line, 3, 4)
213
+ p = np.zeros((height, groups_per_line, 3, 4), dtype=np.uint16)
214
+ p[:, :, :, 0] = (((s0 & 0xFC) >> 2) | ((s1 & 0x03) << 6)) << 2 | (s0 & 0x03)
215
+ p[:, :, :, 1] = (((s1 & 0xF0) >> 4) | ((s2 & 0x0F) << 4)) << 2 | ((s1 & 0x0C) >> 2)
216
+ p[:, :, :, 2] = (((s2 & 0xC0) >> 6) | ((s3 & 0x3F) << 2)) << 2 | ((s2 & 0x30) >> 4)
217
+ p[:, :, :, 3] = s4 << 2 | ((s3 & 0xC0) >> 6)
218
+
219
+ # reshape 成 (height, groups_per_line * 3 * 4) 再裁到实际宽度
220
+ pixels = p.reshape(height, groups_per_line * 3 * 4)[:, :width]
221
+
222
+ return pixels.astype(np.uint16)
223
+ else:
224
+ print("unpackVrf: currently only support 10bit packed image")
225
+ sys.exit()
226
+ return np.array([], dtype=np.uint16) # 为类型检查器添加返回
227
+
228
+ def _unpackVrf(self, src: bytes) -> np.ndarray:
229
+ if self.Packed == 1:
230
+ return self._unpackPixels(src)
231
+ else:
232
+ print("unpackVrf: image is not packed")
233
+ return np.array([], dtype=np.uint16) # 返回空数组
234
+
235
+ def rot(self, mode: str) -> None:
236
+ if self.Packed == 1:
237
+ print("can't rotate packed image")
238
+ return
239
+
240
+ choices = ["mirror", "flip", "mirror_flip"]
241
+ if mode == "mirror":
242
+ """水平镜像(左右翻转)"""
243
+ self.unpackImage = np.fliplr(self.unpackImage)
244
+ self.BayerOrder = np.uint8(int(self.BayerOrder) ^ 1)
245
+ elif mode == "flip":
246
+ """垂直翻转(上下翻转)"""
247
+ self.unpackImage = np.flipud(self.unpackImage)
248
+ self.BayerOrder = np.uint8(int(self.BayerOrder) ^ 2)
249
+ elif mode == "mirror_flip":
250
+ """同时镜像和翻转(旋转 180 度)"""
251
+ self.unpackImage = np.rot90(self.unpackImage, 2)
252
+ self.BayerOrder = np.uint8(int(self.BayerOrder) ^ 3)
253
+ else:
254
+ print(f"{mode} is not a valid choice, must be one of {choices}")
255
+
256
+ def _checkVrf(self) -> None:
257
+ if self.IDString[0] == "V" and self.IDString[1] == "R" and self.IDString[2] == "F":
258
+ if self.Packed and self.VRFRevision >= 0x26:
259
+ self.dataSize = self._getPackVrfSize()
260
+ elif not self.Packed and self.BitDepth == 8:
261
+ self.dataSize = int(self.Width) * int(self.Height) # raw8 size 待确认
262
+ else:
263
+ self.dataSize = int(self.Width) * int(self.Height) * 2
264
+
265
+ if self.dataSize != self.fileSize - self.metaSize:
266
+ print("VRF size wrong, please check it")
267
+ sys.exit()
268
+ if self.BayerOrder > 4:
269
+ print("VRF BayerOrder wrong, please check it")
270
+ sys.exit()
271
+ else:
272
+ print(f"VRF tag wrong, please check it {self.IDString}")
273
+ sys.exit()
274
+
275
+ def SaveVrf(self, fname: str) -> None:
276
+ data = np.ravel(self.unpackImage)
277
+ meta = self.GetMeta()
278
+ data = np.append(data, meta)
279
+ data.tofile(fname)
280
+ print(f"save {fname}")
281
+
282
+ def PrintVrf(self) -> None:
283
+ "Print Vrf info"
284
+ print("vrf Width: ", self.Width)
285
+ print("vrf Height: ", self.Height)
286
+ print("vrf BitDepth: ", self.BitDepth)
287
+ print("vrf BayerOrder(0:BGGR, 1:GBRG, 2:GRBG, 3:RGGB): ", self.BayerOrder)
288
+ print("vrf BLC10b: ", self.BLC10b)
289
+ print("vrf RGB_GAIN(Q7): ", self.AWBGainR, self.AWBGainG, self.AWBGainB)
290
+ print("vrf TGain(Q4): ", self.TGain)
291
+ print("vrf AGain(Q4): ", self.AGain)
292
+ print("vrf DrcGainDark(Q4): ", self.DrcGainDark)
293
+ print("vrf DrcGain(Q4): ", self.DrcGain)
294
+ print("")
295
+
296
+ def Plot(self) -> None:
297
+ "Plot Vrf Image"
298
+ if HAS_PLT:
299
+ import matplotlib.pyplot as plt
300
+
301
+ img = np.uint8(np.right_shift(self.unpackImage, int(self.BitDepth) - 8))
302
+ plt.imshow(img, cmap="gray")
303
+ plt.show()
304
+
305
+
306
+ if __name__ == "__main__":
307
+ srcFile = r"tmp\random_noise10.vrf"
308
+ dstFile = r"tmp\2.vrf"
309
+ vrfObj = Vrf()
310
+ vrfObj.Read(srcFile)
311
+ vrfObj.AWBGainB = np.uint16(129)
312
+ vrfObj.AWBGainG = np.uint16(130)
313
+ vrfObj.AWBGainR = np.uint16(131)
314
+ vrfObj.TGain = np.uint16(64)
315
+ vrfObj.AGain = np.uint16(32)
316
+ vrfObj.BayerOrder = np.uint8(1)
317
+ vrfObj.DrcGain = np.uint8(20)
318
+ vrfObj.DrcGainDark = np.uint8(30)
319
+ vrfObj.ExpoTime_us = np.uint32(1000)
320
+ vrfObj.SaveVrf(dstFile)
321
+ # vrfObj.Plot()
322
+ print("convert ", srcFile, "to ", dstFile, "success.")