New Tuning File for Raspberry Pi HQ camera

I have posted a new tuning file for the IMX477 sensor used in the Raspberry Pi HQ camera over at the Raspberry Pi Camera forum.

Specifically, the ALSC-module has completely been dropped, as the data included in this module is certainly not applicable for most lens/sensor combinations we would use in a film scanner. Also, the color handling was completely modified; lastly, the existing gamma curve was replaced with the sRGB curve, resulting in better color reproduction (the pop-colors are gone, the highlights and shadows are better recovered).

This file is intended to be used with the new libcamera/picamera2 stack. Have a look.

4 Likes

Here’s an updated version 0.8 of the tuning file. Corrected a few oversights, change some minor things. More details below.

{
	"version": 2.0,
	"target": "IMX477 v0.8 - by cpixip 2022",
	"algorithms": [
		{
			"rpi.black_level": {
				"black_level": 4096
			}
		},
		{
			"rpi.dpc": {}
		},
		{
			"rpi.lux": {
				"reference_shutter_speed": 27242,
				"reference_gain": 1.0,
				"reference_aperture": 1.0,
				"reference_lux": 830,
				"reference_Y": 17755
			}
		},
		{
			"rpi.noise": {
				"reference_constant": 0,
				"reference_slope": 2.767
			}
		},
		{
			"rpi.geq": {
				"offset": 204,
				"slope": 0.01078
			}
		},
		{
			"rpi.sdn": {}
		},
		{
			"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
						]
					}
				],
				"modes": {
					"auto": {
						"lo": 2500,
						"hi": 8000
					},
					"incandescent": {
						"lo": 2500,
						"hi": 3000
					},
					"tungsten": {
						"lo": 3000,
						"hi": 3500
					},
					"fluorescent": {
						"lo": 4000,
						"hi": 4700
					},
					"indoor": {
						"lo": 3000,
						"hi": 5000
					},
					"daylight": {
						"lo": 5500,
						"hi": 6500
					},
					"cloudy": {
						"lo": 7000,
						"hi": 8600
					}
				},
				"bayes": 1,
				"ct_curve": [
					2000.0,
					0.6331025775790707,
					0.27424225990946918,
					2200.0,
					0.5696117366212947,
					0.3116091368689487,
					2400.0,
					0.5204264653110015,
					0.34892179554105876,
					2600.0,
					0.48148675531667226,
					0.38565229719076796,
					2800.0,
					0.450085403501908,
					0.42145684622485049,
					3000.0,
					0.42436130159169019,
					0.45611835670028819,
					3200.0,
					0.40300023695527339,
					0.48950766215198596,
					3400.0,
					0.3850520052612984,
					0.5215567075837261,
					3600.0,
					0.36981508088230316,
					0.5522397906415475,
					4100.0,
					0.333468007836758,
					0.5909770465167908,
					4600.0,
					0.31196097364221378,
					0.6515706327327178,
					5100.0,
					0.2961860409294588,
					0.7068178946570284,
					5600.0,
					0.2842607232745885,
					0.7564837749584288,
					6100.0,
					0.2750265787051251,
					0.8006183524920533,
					6600.0,
					0.2677057225584924,
					0.8398879225373039,
					7100.0,
					0.2617955199757274,
					0.8746456080032437,
					7600.0,
					0.25693714288250127,
					0.905569559506562,
					8100.0,
					0.25287531441063318,
					0.9331696750390895,
					8600.0,
					0.24946601483331994,
					0.9576820904825795
				],
				"sensitivity_r": 1.05,
				"sensitivity_b": 1.05,
				"transverse_pos": 0.0238,
				"transverse_neg": 0.04429,
				"coarse_step": 0.1
			}
		},
		{
			"rpi.agc": {
				"metering_modes": {
					"centre-weighted": {
						"weights": [
							3,
							3,
							3,
							2,
							2,
							2,
							2,
							1,
							1,
							1,
							1,
							0,
							0,
							0,
							0
						]
					},
					"spot": {
						"weights": [
							2,
							1,
							1,
							0,
							0,
							0,
							0,
							0,
							0,
							0,
							0,
							0,
							0,
							0,
							0
						]
					},
					"matrix": {
						"weights": [
							1,
							1,
							1,
							1,
							1,
							1,
							1,
							1,
							1,
							1,
							1,
							1,
							1,
							1,
							1
						]
					}
				},
				"exposure_modes": {
					"normal": {
						"shutter": [
							100,
							10000,
							30000,
							60000,
							66666
						],
						"gain": [
							1.0,
							2.0,
							4.0,
							6.0,
							8.0
						]
					},
					"short": {
						"shutter": [
							100,
							5000,
							10000,
							20000,
							33333
						],
						"gain": [
							1.0,
							2.0,
							4.0,
							6.0,
							8.0
						]
					},
					"long": {
						"shutter": [
							100,
							10000,
							30000,
							60000,
							120000
						],
						"gain": [
							1.0,
							2.0,
							4.0,
							6.0,
							12.0
						]
					}
				},
				"constraint_modes": {
					"normal": [
						{
							"bound": "LOWER",
							"q_lo": 0.98,
							"q_hi": 1.0,
							"y_target": [
								0,
								0.3,
								1000,
								0.3
							]
						}
					],
					"highlight": [
						{
							"bound": "LOWER",
							"q_lo": 0.98,
							"q_hi": 1.0,
							"y_target": [
								0,
								0.3,
								1000,
								0.3
							]
						},
						{
							"bound": "UPPER",
							"q_lo": 0.98,
							"q_hi": 1.0,
							"y_target": [
								0,
								0.8,
								1000,
								0.8
							]
						}
					],
					"shadows": [
						{
							"bound": "LOWER",
							"q_lo": 0.0,
							"q_hi": 0.5,
							"y_target": [
								0,
								0.17,
								1000,
								0.17
							]
						}
					]
				},
				"y_target": [
					0,
					0.16,
					1000,
					0.165,
					10000,
					0.17
				]
			}
		},
		{
			"rpi.contrast": {
				"ce_enable": 0,
				"gamma_curve": [
					0,
					0,
					512,
					2304,
					1024,
					4608,
					1536,
					6573,
					2048,
					8401,
					2560,
					9992,
					3072,
					11418,
					3584,
					12719,
					4096,
					13922,
					4608,
					15045,
					5120,
					16103,
					5632,
					17104,
					6144,
					18056,
					6656,
					18967,
					7168,
					19839,
					7680,
					20679,
					8192,
					21488,
					9216,
					23028,
					10240,
					24477,
					11264,
					25849,
					12288,
					27154,
					13312,
					28401,
					14336,
					29597,
					15360,
					30747,
					16384,
					31856,
					17408,
					32928,
					18432,
					33966,
					19456,
					34973,
					20480,
					35952,
					22528,
					37832,
					24576,
					39621,
					26624,
					41330,
					28672,
					42969,
					30720,
					44545,
					32768,
					46065,
					34816,
					47534,
					36864,
					48956,
					38912,
					50336,
					40960,
					51677,
					43008,
					52982,
					45056,
					54253,
					47104,
					55493,
					49152,
					56704,
					51200,
					57888,
					53248,
					59046,
					55296,
					60181,
					57344,
					61292,
					59392,
					62382,
					61440,
					63452,
					63488,
					64503,
					65535,
					65535
				]
			}
		},
		{
			"rpi.ccm": {
				"ccms": [
					{
						"ct": 2000,
						"ccm": [
							1.5813882365848005,
							-0.35293683714581117,
							-0.27378771561617717,
							-0.4347297185453639,
							1.5792631087746075,
							-0.12102601986382337,
							0.2322290578987574,
							-1.4382672640468129,
							2.1386425781770757
						]
					},
					{
						"ct": 2200,
						"ccm": [
							1.6322048484088306,
							-0.45932286857238488,
							-0.21373542690252199,
							-0.3970719209901105,
							1.5877868651467202,
							-0.17249380832122455,
							0.20753774825903413,
							-1.2660673594740142,
							2.005654261091916
						]
					},
					{
						"ct": 2400,
						"ccm": [
							1.6766610071470399,
							-0.5447101051688111,
							-0.16838641107407677,
							-0.3659845183388154,
							1.592223692670396,
							-0.2127091997471162,
							0.1833964516767549,
							-1.1339155942419322,
							1.9089342978542397
						]
					},
					{
						"ct": 2600,
						"ccm": [
							1.7161984340622155,
							-0.6152585785678794,
							-0.1331100845092582,
							-0.33972082628066277,
							1.5944888273736966,
							-0.2453979465898787,
							0.1615577497676328,
							-1.0298684958833109,
							1.8357854177422053
						]
					},
					{
						"ct": 2800,
						"ccm": [
							1.7519307259815729,
							-0.6748682080165339,
							-0.10515169074540848,
							-0.3171703484479931,
							1.5955820297498487,
							-0.2727395854813966,
							0.14230870739974306,
							-0.9460976023551511,
							1.778709391659538
						]
					},
					{
						"ct": 3000,
						"ccm": [
							1.7846716625128374,
							-0.7261240476375332,
							-0.08274697420358428,
							-0.2975654035173307,
							1.5960425637021738,
							-0.2961043416505157,
							0.12546426281675097,
							-0.8773434727076518,
							1.7330356805246686
						]
					},
					{
						"ct": 3200,
						"ccm": [
							1.8150085872943436,
							-0.7708109672515514,
							-0.06469468211419174,
							-0.2803468940646277,
							1.596168842967451,
							-0.3164044170681625,
							0.11071494533513807,
							-0.8199772290209191,
							1.69572135046367
						]
					},
					{
						"ct": 3400,
						"ccm": [
							1.8433668304932088,
							-0.8102060605062592,
							-0.05013485852801454,
							-0.2650934036324084,
							1.5961288492969295,
							-0.33427554893845537,
							0.0977478941863518,
							-0.7714303112098978,
							1.6647070820146964
						]
					},
					{
						"ct": 3600,
						"ccm": [
							1.8700575831917468,
							-0.8452518300291346,
							-0.03842644337477299,
							-0.2514794528347016,
							1.5960178299141877,
							-0.3501774949366156,
							0.08628520830733246,
							-0.729841503339915,
							1.638553343939267
						]
					},
					{
						"ct": 4100,
						"ccm": [
							1.8988700903560716,
							-0.8911278803351247,
							-0.018848644425650694,
							-0.21487101487384095,
							1.599236541382614,
							-0.39405450457918209,
							0.08251488056482173,
							-0.7178919368326191,
							1.6267009056502704
						]
					},
					{
						"ct": 4600,
						"ccm": [
							1.960355191764125,
							-0.9624344812121991,
							-0.0017122408632169206,
							-0.19444620905212899,
							1.5978493736948448,
							-0.416727638296156,
							0.06310261513271085,
							-0.6483790952487849,
							1.5834605477213093
						]
					},
					{
						"ct": 5100,
						"ccm": [
							2.014680536961399,
							-1.0195930302148566,
							0.007728256612638915,
							-0.17751999660735497,
							1.5977081555831,
							-0.4366085498741474,
							0.04741267583041334,
							-0.5950327902073489,
							1.5512919847321854
						]
					},
					{
						"ct": 5600,
						"ccm": [
							2.062652337917251,
							-1.0658386679125478,
							0.011886354256281267,
							-0.16319197721451496,
							1.598363237584736,
							-0.45422061523742238,
							0.03465810928795378,
							-0.5535454108047286,
							1.5269025836946853
						]
					},
					{
						"ct": 6100,
						"ccm": [
							2.104985902038069,
							-1.103597868736314,
							0.012503517136539277,
							-0.15090797064906179,
							1.5994703078166095,
							-0.4698414300864995,
							0.02421766063474242,
							-0.5208922818196823,
							1.5081270847783788
						]
					},
					{
						"ct": 6600,
						"ccm": [
							2.1424988751299716,
							-1.134760232367728,
							0.010730356010435523,
							-0.14021846798466235,
							1.600822462230719,
							-0.48379204794526489,
							0.015521315410496622,
							-0.49463630325832277,
							1.4933313534840327
						]
					},
					{
						"ct": 7100,
						"ccm": [
							2.1758034100130927,
							-1.1607558481037359,
							0.007452724895469076,
							-0.13085694672641827,
							1.6022648614493245,
							-0.4962330524084075,
							0.008226943206113427,
							-0.4733077192319791,
							1.4815336120437468
						]
					},
					{
						"ct": 7600,
						"ccm": [
							2.205529206931895,
							-1.1826662383072109,
							0.0032019529917605169,
							-0.122572009780486,
							1.6037258133595754,
							-0.5073973734282445,
							0.0020132587619863427,
							-0.4556590236414181,
							1.471939788496745
						]
					},
					{
						"ct": 8100,
						"ccm": [
							2.232224969223067,
							-1.2013672897252886,
							-0.0016234598095482985,
							-0.11518026734442415,
							1.6051544769439803,
							-0.5174558699422255,
							-0.0033378143542219837,
							-0.4408590373867774,
							1.4640252230667453
						]
					},
					{
						"ct": 8600,
						"ccm": [
							2.256082295891265,
							-1.2173210549996634,
							-0.0067231350481711678,
							-0.10860272839843167,
							1.6065150139140594,
							-0.5264728573611494,
							-0.007952618707984149,
							-0.4284003574050791,
							1.4574646927117559
						]
					}
				]
			}
		},
		{
			"rpi.sharpen": {}
		},
		{
			"rpi.focus": {}
		}
	]
}

This new v 0.8 tuning file is based on the Raspberry Pi’s original tuning file.

The new v 0.8 tuning file features the following differences (in the order of appearance in the file) with respect to the original one:

CT-Curves

The new ct-curve is now based on the illumination spectrum of a black body radiator up to about 3600 K; for higher color temperatures, the CIE standard illuminant D is used. You notice the switch by the little kink in the blue curve below. That’s a difference from the previous version, which used black body radiator spectra over the whole range of color temperatures.

A further change happened in this section: I did reduce in this new file the “coarse_step” parameter from its default 0.2 to a value of 0.1 - as far as I understand it, the AWB will take slightly longer to converge, due to this change, but the sampling will be finer.

ALSC-section

This section is completely gone at the moment. The reason for this is that this section actually describes the current lens/camera combination. So it depends on the lens you are using at the moment. As the lens can be changed on the HQ camera, any data in the tuning file relating to the lens is most of the time not correct (only, if your lens happens to be the one used in the calibration).

Contrast Curve

I replaced the sRGB-contrast curve in my previous tuning file with the rec709 contrast curve in this version. rec709 is an industry standard. Here’s a plot of the difference

rec709 features a little bit less contrast than the contrast curve of the standard file. This has also an impact on color saturation. Images obtained with the v 0.8 tuning file will have slightly less color saturation than images captured with the standard file.

Furthermore, in the contrast-section the “ce_enable”-parameter is now set to zero in order to get rid of the automatic algorithm running in the background. Occasionally, users will have to tune the brightness and contrast controls by themselves, but I guess, users who care about tuning files know how to do this.

CCM-section

The CCMs in this section have been all calculated new and work in association with the new ct-curve introduced above. Generally, they vary much smoother than the values in the original tuning file. Here’s a plot of the principal red component of the CCMs over color temperature to show what I mean:

In the tiny range from 3700 K to 4000 K, the principle red component varies in the original file quite a bit, resulting in noticeable color changes within small deviations of the estimated color temperature. In contrast, the variation of the matrices components in the new tuning file is much smoother.

Conclusion

Well, this concludes the list of differences between the original tuning file and my current version.

Additional Hint

The Raspberry Pi Foundation indicated that soon HQ cameras will feature a slightly different IR-blockfilter, as the old one is no longer manufactured. From the information I have, I’d say the differences between the filters are minor. The Raspberry Pi Foundation already distributed a new IMX477 tuning file, claimed to “give best results with both old and new camera modules”. If you did an update on your Raspberry Pi software recently, chances are that you are already working with their new tuning file. The comparison plots above (the red curves) are already based on the new Raspberry Pi tuning file.

4 Likes

Thank you for sharing your work, it is invaluable for this community.

1 Like

Here is another plot showing the differences between the original Raspberry Pi tuning file (red) and the new tuning file above (blue) in the values of the color matrices:

Needless to say that I like the smooth variation of the new tuning file better than the wiggling of the standard tuning file. With the standard tuning file, small changes in estimated color temperature will lead to rather strong variations in the coefficients of color matrix. This is especially pronounced in the 4000 K to 4400 K range. Given, the color shifts introduced by this behavior might not really be noticeable for the viewer.

Actually, I think the above tuning file will soon be available as a “scientific” tuning file alternative in newer libcamera distributions; also the old tuning file will show up as “v1” file, in possibly a few weeks from now.

2 Likes

Outstanding. Thank you for your work and appreciate you sharing it for the benefit of all in this community.

– the new tuning file discussed here is now available in the latest RP update as “imx477_scientific.json”. You can get it with (together with other updates, including the latest version of libcamera/picamera2):

sudo apt update
sudo apt upgrade

Issue the following commands

libcamera-still -o old.jpg
libcamera-still -o new.jpg --tuning-file=/usr/share/libcamera/ipa/raspberrypi/imx477_scientific.json

and you should end up with an image “old.jpg” using the default tuning file as well as an image “new.jpg” using the new one. Compare and if you like, give some feedback! EDIT 20/01/23: as it turns out, you need to give the libcamera-apps the full path to the tuning file (like in the command above), or simply copy it from the default location into your current dir before calling the libcamera-app.

To use the new tuning file within the picamera2 context, try the following code

import time
from picamera2 import Picamera2, Preview

tuning = Picamera2.load_tuning_file("imx477_scientific.json")
picam2 = Picamera2(tuning=tuning)
picam2.configure(picam2.create_preview_configuration())
picam2.start_preview(Preview.QTGL)
picam2.start()
time.sleep(2)
2 Likes

Awesome, now I can stop manually editing the config file every time the library gets updated! :slight_smile:

FYI, I perform the update/upgrade on a Raspian OS Bullseye 64 and got an

WARN RPiController controller.cpp:34 Failed to open tuning file 'imx477_scientific.json'

Tried an update of the library and it is already the latest.

 $ sudo apt install -y python3-picamera2
python3-picamera2 is already the newest version (0.3.8-1).

PS. For clarity, with the file local it did work (downloading the zip).

@PM490 - well, did you perform a full upgrade? I am no Raspberry Pi expert, but I followed the above recipe as test on a RP4 as well as on a RP3. It did work for me.

For example, I get this here as output when taking an image:

pi@raspi-06:~ $ libcamera-still -o new.jpg --tuning-file=imx477_scientific.json
Made X/EGL preview window
[0:03:32.815215019] [2684]  INFO Camera camera_manager.cpp:299 libcamera v0.0.3+40-9b860a66
[0:03:32.872995078] [2688]  INFO RPI raspberrypi.cpp:1425 Registered camera /base/soc/i2c0mux/i2c@1/imx477@1a to Unicam device /dev/media0 and ISP device /dev/media2
[0:03:32.874143464] [2684]  INFO Camera camera.cpp:1028 configuring streams: (0) 2028x1520-YUV420
[0:03:32.874546315] [2688]  INFO RPI raspberrypi.cpp:805 Sensor: /base/soc/i2c0mux/i2c@1/imx477@1a - Selected sensor format: 2028x1520-SBGGR12_1X12 - Selected unicam format: 2028x1520-pBCC
[0:03:39.008091959] [2684]  INFO Camera camera.cpp:1028 configuring streams: (0) 4056x3040-YUV420 (1) 4056x3040-SBGGR12_CSI2P
[0:03:39.010788639] [2688]  INFO RPI raspberrypi.cpp:805 Sensor: /base/soc/i2c0mux/i2c@1/imx477@1a - Selected sensor format: 4056x3040-SBGGR12_1X12 - Selected unicam format: 4056x3040-pBCC
Still capture image received
pi@raspi-06:~ $ 

Is your libcamera-version the one listed above?

The new tuning file should be contained in the libcamera0-package (according to an apt-file search):

pi@raspi-06:~ $ apt-file search "imx477_scientific.json"
libcamera0: /usr/share/libcamera/ipa/raspberrypi/imx477_scientific.json
pi@raspi-06:~ $ 

You might want to check the directory listed in the above output. If I am doing that on my RP3, I get the following output:

pi@raspi-06:~ $ ls -al /usr/share/libcamera/ipa/raspberrypi/
total 372
drwxr-xr-x 2 root root  4096 Jan 27 20:04 .
drwxr-xr-x 4 root root  4096 Sep 22 04:51 ..
-rw-r--r-- 1 root root 23959 Jan 24 14:47 imx219.json
-rw-r--r-- 1 root root 21316 Jan 24 14:47 imx219_noir.json
-rw-r--r-- 1 root root  6837 Jan 24 14:47 imx290.json
-rw-r--r-- 1 root root 19305 Jan 24 14:47 imx296.json
-rw-r--r-- 1 root root 10419 Jan 24 14:47 imx296_mono.json
-rw-r--r-- 1 root root 18886 Jan 24 14:47 imx378.json
-rw-r--r-- 1 root root 25230 Jan 24 14:47 imx477.json
-rw-r--r-- 1 root root 22368 Jan 24 14:47 imx477_noir.json
-rw-r--r-- 1 root root 18139 Jan 24 14:47 imx477_scientific.json
-rw-r--r-- 1 root root 18886 Jan 24 14:47 imx519.json
-rw-r--r-- 1 root root 24046 Jan 24 14:47 imx708.json
-rw-r--r-- 1 root root 24046 Jan 24 14:47 imx708_noir.json
-rw-r--r-- 1 root root 20400 Jan 24 14:47 imx708_wide.json
-rw-r--r-- 1 root root 20400 Jan 24 14:47 imx708_wide_noir.json
-rw-r--r-- 1 root root 23983 Jan 24 14:47 ov5647.json
-rw-r--r-- 1 root root 21341 Jan 24 14:47 ov5647_noir.json
-rw-r--r-- 1 root root  3366 Jan 24 14:47 ov9281_mono.json
-rw-r--r-- 1 root root 18998 Jan 24 14:47 se327m12.json
-rw-r--r-- 1 root root  3248 Jan 24 14:47 uncalibrated.json
pi@raspi-06:~ $ 

Another check you might want to run is the following:

pi@raspi-10:~ $ dpkg -l libcamera0
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name             Version                  Architecture Description
+++-================-========================-============-=================================
ii  libcamera0:arm64 0~git20230124+9b860a66-1 arm64        complex camera support library
pi@raspi-10:~ $ 

Note the version information here. The new tuning file is only in the newest version.

Thanks Rolf. I am a novice with RPi, so no expert here.

No worries, I am using your file by having it at the directory invoking the call.

pm@rpi4b:~ $ libcamera-still -o new.jpg --tuning-file=imx477_scientific.json
Preview window unavailable
[0:16:58.381460084] [996]  INFO Camera camera_manager.cpp:299 libcamera v0.0.3+40-9b860a66
[0:16:58.426243238] [998]  WARN RPiController controller.cpp:34 Failed to open tuning file 'imx477_scientific.json'
[0:16:58.426349851] [998] ERROR IPARPI raspberrypi.cpp:254 Failed to load tuning data file imx477_scientific.json
[0:16:58.426402166] [998] ERROR RPI raspberrypi.cpp:1303 Failed to load a suitable IPA library
[0:16:58.426629261] [998] ERROR RPI raspberrypi.cpp:1228 Failed to register camera imx477 10-001a: -22
ERROR: *** no cameras available ***

As shown above, it is the same library version.

$ sudo apt-file search "imx477_scientific.json"
libcamera0: /usr/share/libcamera/ipa/raspberrypi/imx477_scientific.json

and the file is found.

pm@rpi4b:~ $ ls -al  /usr/share/libcamera/ipa/raspberrypi/
total 372
drwxr-xr-x 2 root root  4096 Jan 29 00:55 .
drwxr-xr-x 4 root root  4096 Sep 21 22:51 ..
-rw-r--r-- 1 root root 23959 Jan 24 08:47 imx219.json
-rw-r--r-- 1 root root 21316 Jan 24 08:47 imx219_noir.json
-rw-r--r-- 1 root root  6837 Jan 24 08:47 imx290.json
-rw-r--r-- 1 root root 19305 Jan 24 08:47 imx296.json
-rw-r--r-- 1 root root 10419 Jan 24 08:47 imx296_mono.json
-rw-r--r-- 1 root root 18886 Jan 24 08:47 imx378.json
-rw-r--r-- 1 root root 25230 Jan 24 08:47 imx477.json
-rw-r--r-- 1 root root 22368 Jan 24 08:47 imx477_noir.json
-rw-r--r-- 1 root root 18139 Jan 24 08:47 imx477_scientific.json
-rw-r--r-- 1 root root 18886 Jan 24 08:47 imx519.json
-rw-r--r-- 1 root root 24046 Jan 24 08:47 imx708.json
-rw-r--r-- 1 root root 24046 Jan 24 08:47 imx708_noir.json
-rw-r--r-- 1 root root 20400 Jan 24 08:47 imx708_wide.json
-rw-r--r-- 1 root root 20400 Jan 24 08:47 imx708_wide_noir.json
-rw-r--r-- 1 root root 23983 Jan 24 08:47 ov5647.json
-rw-r--r-- 1 root root 21341 Jan 24 08:47 ov5647_noir.json
-rw-r--r-- 1 root root  3366 Jan 24 08:47 ov9281_mono.json
-rw-r--r-- 1 root root 18998 Jan 24 08:47 se327m12.json
-rw-r--r-- 1 root root  3248 Jan 24 08:47 uncalibrated.json

and the dpkg is the same version too.

pm@rpi4b:~ $ dpkg -l libcamera0
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name             Version                  Architecture Description
+++-================-========================-============-====================>
ii  libcamera0:arm64 0~git20230124+9b860a66-1 arm64        complex camera suppo>
lines 1-6/6 (END)

And it shows the same version.

Thanks for the suggestions, again, not an issue at this time since when the file is where the call is made, it works.

pm@rpi4b:~/share $ ls
imx477_scientific.json
pm@rpi4b:~/share $ sudo libcamera-still -o new.jpg --tuning-file=imx477_scientific.json
Preview window unavailable
[0:33:08.138858163] [1812]  INFO Camera camera_manager.cpp:299 libcamera v0.0.3+40-9b860a66
[0:33:08.179649095] [1813]  INFO RPI raspberrypi.cpp:1425 Registered camera /base/soc/i2c0mux/i2c@1/imx477@1a to Unicam device /dev/media4 and ISP device /dev/media1
[0:33:08.180944628] [1812]  INFO Camera camera.cpp:1028 configuring streams: (0) 2028x1520-YUV420
[0:33:08.181322794] [1813]  INFO RPI raspberrypi.cpp:805 Sensor: /base/soc/i2c0mux/i2c@1/imx477@1a - Selected sensor format: 2028x1520-SBGGR12_1X12 - Selected unicam format: 2028x1520-pBCC
#0 (0.00 fps) exp 32987.00 ag 8.00 dg 1.00
#1 (30.01 fps) exp 32987.00 ag 8.00 dg 1.00
.. 
#142 (30.01 fps) exp 32987.00 ag 8.00 dg 1.00
[0:33:13.781900487] [1812]  INFO Camera camera.cpp:1028 configuring streams: (0) 4056x3040-YUV420 (1) 4056x3040-SBGGR12_CSI2P
[0:33:13.783529408] [1813]  INFO RPI raspberrypi.cpp:805 Sensor: /base/soc/i2c0mux/i2c@1/imx477@1a - Selected sensor format: 4056x3040-SBGGR12_1X12 - Selected unicam format: 4056x3040-pBCC
Still capture image received

I am going to rebuilt the system, since I am not sure what else may be broken.

Thanks again.

There is definitely something broken.
Steps taken:

  1. Using Raspberry Pi Imager, created card with 64bit OS.
  2. sudo apt update
  3. sudo apt full-upgrade
    nothing else… and then the results.
pm@rpi4b:~ $ libcamera-still -o old.jpg
Preview window unavailable
[0:17:44.249078545] [8922]  INFO Camera camera_manager.cpp:299 libcamera v0.0.3+40-9b860a66
[0:17:44.297720703] [8923]  INFO RPI raspberrypi.cpp:1425 Registered camera /base/soc/i2c0mux/i2c@1/imx477@1a to Unicam device /dev/media2 and ISP device /dev/media1
[0:17:44.298488064] [8922]  INFO Camera camera.cpp:1028 configuring streams: (0) 2028x1520-YUV420
[0:17:44.298762344] [8923]  INFO RPI raspberrypi.cpp:805 Sensor: /base/soc/i2c0mux/i2c@1/imx477@1a - Selected sensor format: 2028x1520-SBGGR12_1X12 - Selected unicam format: 2028x1520-pBCC
#0 (0.00 fps) exp 32987.00 ag 8.00 dg 1.00
#1 (30.01 fps) exp 32987.00 ag 8.00 dg 1.00
...
#140 (30.01 fps) exp 32987.00 ag 8.00 dg 1.00
#141 (30.01 fps) exp 32987.00 ag 8.00 dg 1.00
[0:17:49.844543272] [8922]  INFO Camera camera.cpp:1028 configuring streams: (0) 4056x3040-YUV420 (1) 4056x3040-SBGGR12_CSI2P
[0:17:49.846542393] [8923]  INFO RPI raspberrypi.cpp:805 Sensor: /base/soc/i2c0mux/i2c@1/imx477@1a - Selected sensor format: 4056x3040-SBGGR12_1X12 - Selected unicam format: 4056x3040-pBCC
Still capture image received
pm@rpi4b:~ $ libcamera-still -o new.jpg --tuning-file=imx477_scientific.json
Preview window unavailable
[0:18:14.563548155] [8932]  INFO Camera camera_manager.cpp:299 libcamera v0.0.3+40-9b860a66
[0:18:14.587032069] [8933]  WARN RPiController controller.cpp:34 Failed to open tuning file 'imx477_scientific.json'
[0:18:14.587152063] [8933] ERROR IPARPI raspberrypi.cpp:254 Failed to load tuning data file imx477_scientific.json
[0:18:14.587199875] [8933] ERROR RPI raspberrypi.cpp:1303 Failed to load a suitable IPA library
[0:18:14.587392975] [8933] ERROR RPI raspberrypi.cpp:1228 Failed to register camera imx477 10-001a: -22
ERROR: *** no cameras available ***
pm@rpi4b:~ $ ls -al /usr/share/libcamera/ipa/raspberrypi/
total 372
drwxr-xr-x 2 root root  4096 Jan 29 16:32 .
drwxr-xr-x 4 root root  4096 Sep 21 22:51 ..
-rw-r--r-- 1 root root 23959 Jan 24 08:47 imx219.json
-rw-r--r-- 1 root root 21316 Jan 24 08:47 imx219_noir.json
-rw-r--r-- 1 root root  6837 Jan 24 08:47 imx290.json
-rw-r--r-- 1 root root 19305 Jan 24 08:47 imx296.json
-rw-r--r-- 1 root root 10419 Jan 24 08:47 imx296_mono.json
-rw-r--r-- 1 root root 18886 Jan 24 08:47 imx378.json
-rw-r--r-- 1 root root 25230 Jan 24 08:47 imx477.json
-rw-r--r-- 1 root root 22368 Jan 24 08:47 imx477_noir.json
-rw-r--r-- 1 root root 18139 Jan 24 08:47 imx477_scientific.json
-rw-r--r-- 1 root root 18886 Jan 24 08:47 imx519.json
-rw-r--r-- 1 root root 24046 Jan 24 08:47 imx708.json
-rw-r--r-- 1 root root 24046 Jan 24 08:47 imx708_noir.json
-rw-r--r-- 1 root root 20400 Jan 24 08:47 imx708_wide.json
-rw-r--r-- 1 root root 20400 Jan 24 08:47 imx708_wide_noir.json
-rw-r--r-- 1 root root 23983 Jan 24 08:47 ov5647.json
-rw-r--r-- 1 root root 21341 Jan 24 08:47 ov5647_noir.json
-rw-r--r-- 1 root root  3366 Jan 24 08:47 ov9281_mono.json
-rw-r--r-- 1 root root 18998 Jan 24 08:47 se327m12.json
-rw-r--r-- 1 root root  3248 Jan 24 08:47 uncalibrated.json
pm@rpi4b:~ $

Posting only for your information… not a problem for me, I’ll live with the local file.
Thanks Rolf.

PS. Additional information.
The problem is the same with other tuning-files in the same directory.
Including the directory path explicitly in the libcamera-still call works. Looks like there is an error in the default path used by the library.

pm@rpi4b:~ $ libcamera-still -o new.jpg --tuning-file=/usr/share/libcamera/ipa/raspberrypi/imx477_scientific.json
Preview window unavailable
[0:08:13.035098944] [1641]  INFO Camera camera_manager.cpp:299 libcamera v0.0.3+40-9b860a66
[0:08:13.062460201] [1642]  INFO RPI raspberrypi.cpp:1425 Registered camera /base/soc/i2c0mux/i2c@1/imx477@1a to Unicam device /dev/media3 and ISP device /dev/media1
[0:08:13.063278701] [1641]  INFO Camera camera.cpp:1028 configuring streams: (0) 2028x1520-YUV420
[0:08:13.063573627] [1642]  INFO RPI raspberrypi.cpp:805 Sensor: /base/soc/i2c0mux/i2c@1/imx477@1a - Selected sensor format: 2028x1520-SBGGR12_1X12 - Selected unicam format: 2028x1520-pBCC
#0 (0.00 fps) exp 7052.00 ag 1.00 dg 1.08
#1 (30.01 fps) exp 7082.00 ag 1.00 dg 1.08
...
#140 (30.01 fps) exp 7507.00 ag 1.00 dg 1.00
#141 (30.01 fps) exp 7507.00 ag 1.00 dg 1.00
#142 (30.01 fps) exp 7492.00 ag 1.00 dg 1.00
[0:08:18.645634791] [1641]  INFO Camera camera.cpp:1028 configuring streams: (0) 4056x3040-YUV420 (1) 4056x3040-SBGGR12_CSI2P
[0:08:18.647689309] [1642]  INFO RPI raspberrypi.cpp:805 Sensor: /base/soc/i2c0mux/i2c@1/imx477@1a - Selected sensor format: 4056x3040-SBGGR12_1X12 - Selected unicam format: 4056x3040-pBCC
Still capture image received

1 Like

@PM490 - this is weird. Clearly, the file is present at the place where (as far as I know) libcamera is expecting the file. And as you mentioned, other files do not work either…

The only difference I see between your and my system is the little line “Preview window unavailable” after issuing the capture command. I do run VNC on both of my machines, so there is a preview-window available. Will test a little bit further this evening…

@PM490 - I just tried the libcamera-still command on my RP3 both on my RP4 as well as on my RP3, and it failed exactly like you described. Maybe I had the tuning file somewhere in my path when I tried it previously? I have no idea. Anyway, you already described a way to use it: either copy it from the default location to the directory you are calling libcamera-still from, or include the full path in order to make it work, like so:

libcamera-still -o new.jpg --tuning-file=/usr/share/libcamera/ipa/raspberrypi/imx477_scientific.json

Thanks for bringing this to my attention!

Thank you @cpixip
I am novice in RPi and even more in HQ camera. Glad is not something broken on my installation, and thanks again for sharing your great work with the HQ camera.

Hi Rolf, looks like in the current version of the library has an update to your file (version 2.0), and also an update to the location.

To get your tuning file working with libcamera-still, the call currently is:

$ libcamera-still --tuning-file=/usr/share/libcamera/ipa/rpi/vc4/imx477_scientific.json --output imagewithtuning.jpg

Thanks again for sharing this work, it is an invaluable contribution to the scanning projects.

3 Likes

just to add this here, a reply of David Plowman with respect to a recent question of mine:

Re: Libcamera Tuning-Files updated recently?

Wed Aug 23, 2023 10:52 am

Hi

Yes, we did remeasure the colour matrices so that the default matrices that users will get are slightly more accurate. Only the default tunings are changed, obviously not any others such as the scientific ones. Specifically, the files that have been changed are:
imx219.json
imx296.json
imx477.json
imx708.json
imx708_wide.json
ov5647.json

This change is not in the Raspberry Pi fork of libcamera yet, nor therefore in any of the packages that we distribute. The change is in mainline libcamera, though we recommend Raspberry Pi users to use the Raspberry Pi fork, because it contains better platform specific settings. So only users who are building and installing from the upstream (non-recommended) repository would notice any change currently.

The old tunings can obviously be retrieved from git (anything prior to commit 6213ec, which is the one where the change was made). Generally speaking, I don’t think we would commit to never changing the default tuning files, though perhaps we could include legacy versions (under a different name) when such updates occur. Would that be helpful?

If I understand that correctly: the standard tuning files will have a changed color science sometime in the near future, compared with the old ones. If you use one of these tuning files in your scanner, you might get results different compared to previous scans.

The “imx477_scientific.json” seems not to be affected; whether the new “imx477.json” (once it is officially puplished) gives noticably different colors than the old one remains to be seen.

2 Likes

Yeah, poking around the libcamera repository, outside of being moved to the new folder, imx477_scientific.json hasn’t been changed.

Here are both versions of imx477.json (before and after commit 6213ec) if anyone wanted to test the new change sooner: imx477.zip (7.3 KB)

1 Like

Well, well… - the Raspberry Pi Foundation seems to continue its trend of changing things under the hood without bothering to tell that their customers.

They did this behind-the-scene changing already at least one time, changing the whitebalancing guiding curve once (red/blue gain vs color temperature). Here’s a plot showing this

“imx477 - cpixip_0.8.json” (red curve) is the curve used in the “imx477_scientific.json” tuning file, “imx477_v1.json” (blue curve) was the original curve used when the HQ sensor came out, and finally “imx477 (after).json” is the currently used curve. The later is identical to the curve in the “imx477 (before).json” tuning file. So no change here.

The ccm (color matrices) show differences. From what I have seen in the libcamera repository, they upgraded the algorithm to optimize the color matches to operate no longer in RGB-space, but in Lab-space or so. They still look much too weird for me:

Here the red curves display the coefficients of the color matrix over color temperature as coded in the “imx477_scientific.json” (marked with my internal name “imx477 - cpixip_0.8.json”), the blue curves are the “imx477 (before).json”, the green curves the “imx477 (after).json”.

The new matrix data (green lines) shows less datapoints, so they have obviously used less calibration images this time. The jaginess of the curves remains.

I have checked also the contrast curve (gamma), and this function has not changed between the two tuning file version - it still creates a quite contrasty pop color image.

Whether all these changes result in any noticable improvement with respect to color fidelity is difficult to say; since the whitebalancing curves of the two versions of the imx477 tuning file are identical, as well as the contrast curve was left unchanged, the only difference is in the ccm-coefficients. Difficult to say whether this will lead to visually noticable differences between the tuning files…

Additional note: the lens-shading tables are unchanged in all versions available (“imx477_v1.json”, “imx477 (before).json”, “imx477 (after).json”). They are not present in the “imx477_scientific.json” = “imx477 - cpixip_0.8.json” tuning file, as previously described.

1 Like