関数 | |
INT FVALGAPI | fnFIE_calib_calc_intrinsic_parameters (FHANDLE hcalib, F_CAMERA_PARAM *pcamera) |
![]() | |
INT FVALGAPI | fnFIE_calib_calc_1shot (FHANDLE hcalib, INT view_num, F_CAMERA_PARAM *pcamera, FMATRIX *homography) |
![]() | |
INT FVALGAPI | fnFIE_calib_calc_extrinsic_parameters (F_CAMERA_PARAM camera, DPNT_T *model_points, DPNT_T *marker_points, INT num_points, FMATRIX *rotation, FVECTOR *translation, FMATRIX *homography) |
![]() | |
INT FVALGAPI | fnFIE_calib_calc_homography_matrix (F_CAMERA_PARAM camera, FMATRIX *rotation, FVECTOR *translation, FMATRIX *homography) |
![]() | |
INT FVALGAPI | fnFIE_calib_calc_error (FHANDLE hcalib, F_CAMERA_PARAM camera, DOUBLE *min_error, DOUBLE *max_error, DOUBLE *average_error) |
![]() | |
INT FVALGAPI | fnFIE_calib_calc_error2 (FHANDLE hcalib, F_CAMERA_PARAM camera, INT view_num, DPNT_T *diff, INT num_points) |
![]() | |
INT FVALGAPI | fnFIE_calib_calc_error3 (FHANDLE hcalib, F_CAMERA_PARAM camera, DPNT_T *points, DPNT_T *diff, INT num_points) |
![]() |
INT FVALGAPI fnFIE_calib_calc_intrinsic_parameters | ( | FHANDLE | hcalib, | |
F_CAMERA_PARAM * | pcamera | |||
) |
カメラ内部パラメータの算出
1カメラのカメラキャリブレーションを実施し、カメラ内部パラメータを算出します。 fnFIE_calib_add_data() を使って異なる視野のデータを3回以上追加している必要があります。
よいカメラ内部パラメータを計算するためには、下記の点に注意して入力データを作成してください。
[in] | hcalib | キャリブレーションデータオブジェクト |
[out] | pcamera | カメラ内部パラメータ構造体 |
F_ERR_NONE | 正常終了 | |
F_ERR_INVALID_OBJECT | オブジェクト異常 | |
F_ERR_INVALID_PARAM | パラメータ異常 | |
F_ERR_NOMEMORY | メモリ不足 | |
F_ERR_CALC_IMPOSSIBLE | 計算不能
| |
F_ERR_NO_LICENCE | ライセンスエラー、または未初期化エラー |
//エラー処理は省略しているので注意してください。 #include <stdio.h> #include "fie.h" //カメラ内部パラメータと歪み係数を求めます。 INT main(VOID) { //キャリブレーションテンプレート座標系における、モデルの座標データを用意します。 DPNT_T model[36] = { { 0, 0},{ 4, 0},{ 8, 0}, {12, 0},{16, 0},{20, 0}, { 0, 4},{ 4, 4},{ 8, 4}, {12, 4},{16, 4},{20, 4}, { 0, 8},{ 4, 8},{ 8, 8}, {12, 8},{16, 8},{20, 8}, { 0,12},{ 4,12},{ 8,12}, {12,12},{16,12},{20,12}, { 0,16},{ 4,16},{ 8,16}, {12,16},{16,16},{20,16}, { 0,20},{ 4,20},{ 8,20}, {12,20},{16,20},{20,20} }; //カメラ画像座標系における、特徴点の検出データを用意します。 //各座標値はmodelと同じ順番に並んでいます。 //ここでは5組用意しています。 DPNT_T points_0[36] = { { 350.2, 338.7 },{ 483.1, 338.8 },{ 616.2, 339.0 }, { 749.9, 339.3 },{ 883.1, 340.0 },{ 1016.0, 340.8 }, { 339.2, 408.9 },{ 476.0, 409.2 },{ 612.9, 409.8 }, { 750.0, 410.1 },{ 887.2, 410.9 },{ 1024.1, 411.1 }, { 327.9, 484.2 },{ 468.1, 484.8 },{ 609.1, 485.2 }, { 750.8, 485.8 },{ 891.8, 486.1 },{ 1032.8, 486.8 }, { 315.3, 563.9 },{ 460.2, 564.2 },{ 605.2, 564.9 }, { 751.0, 565.2 },{ 896.2, 565.9 },{ 1041.8, 566.1 }, { 302.8, 648.9 },{ 451.9, 649.2 },{ 601.2, 650.1 }, { 751.8, 650.9 },{ 901.2, 651.1 },{ 1051.1, 651.7 }, { 288.9, 738.2 },{ 442.9, 739.1 },{ 597.0, 740.0 }, { 752.0, 740.7 },{ 906.8, 741.0 },{ 1061.0, 741.2 } }; DPNT_T points_1[36] = { { 311.8, 345.8 },{ 461.0, 344.1 },{ 611.1, 342.8 }, { 762.1, 341.2 },{ 912.9, 340.2 },{ 1063.9, 339.1 }, { 326.1, 443.8 },{ 471.8, 442.2 },{ 617.8, 441.0 }, { 764.2, 440.0 },{ 910.9, 438.9 },{ 1057.8, 437.9 }, { 340.0, 537.2 },{ 481.7, 536.2 },{ 623.8, 535.2 }, { 766.2, 534.7 },{ 909.0, 533.1 },{ 1051.9, 532.0 }, { 353.2, 625.0 },{ 491.0, 624.1 },{ 629.7, 623.2 }, { 768.2, 622.2 },{ 907.1, 621.8 },{ 1046.0, 620.8 }, { 366.0, 708.9 },{ 500.0, 708.1 },{ 634.9, 707.7 }, { 770.1, 706.9 },{ 905.1, 705.9 },{ 1040.9, 705.0 }, { 378.0, 787.7 },{ 508.9, 787.1 },{ 640.1, 786.8 }, { 771.9, 786.0 },{ 903.7, 785.1 },{ 1035.2, 784.1 } }; DPNT_T points_2[36] = { { 263.1, 175.2 },{ 374.9, 156.8 },{ 491.2, 138.5 }, { 612.0, 119.1 },{ 737.4, 99.2 },{ 867.7, 78.9 }, { 275.4, 312.2 },{ 387.7, 296.7 },{ 504.4, 280.6 }, { 625.7, 264.1 },{ 751.6, 246.9 },{ 882.3, 229.3 }, { 288.2, 449.6 },{ 400.8, 436.8 },{ 517.8, 423.3 }, { 639.4, 409.3 },{ 765.7, 395.1 },{ 896.8, 380.1 }, { 301.1, 587.3 },{ 413.9, 577.0 },{ 531.1, 566.2 }, { 653.1, 555.2 },{ 779.8, 543.8 },{ 911.1, 531.3 }, { 314.2, 725.1 },{ 427.2, 717.2 },{ 544.9, 709.2 }, { 667.0, 701.0 },{ 793.9, 692.1 },{ 925.3, 682.9 }, { 327.8, 862.3 },{ 440.9, 857.2 },{ 558.2, 852.0 }, { 680.9, 846.2 },{ 807.8, 840.1 },{ 939.2, 833.8 } }; DPNT_T points_3[36] = { { 288.1, 66.6 },{ 444.8, 78.8 },{ 596.1, 90.8 }, { 743.0, 103.0 },{ 884.9, 114.9 },{ 1021.9, 126.7 }, { 286.9, 232.9 },{ 444.2, 242.2 },{ 596.9, 252.0 }, { 744.2, 261.3 },{ 887.0, 270.8 },{ 1024.3, 279.9 }, { 286.0, 400.8 },{ 444.1, 407.9 },{ 597.1, 414.8 }, { 745.8, 421.7 },{ 888.8, 428.1 },{ 1026.9, 434.3 }, { 285.2, 570.8 },{ 444.0, 574.8 },{ 597.9, 579.0 }, { 746.9, 583.0 },{ 890.1, 587.0 },{ 1028.9, 590.8 }, { 285.1, 741.2 },{ 444.1, 743.0 },{ 598.2, 744.2 }, { 747.9, 745.8 },{ 891.9, 746.9 },{ 1030.8, 747.7 }, { 285.1, 912.9 },{ 444.8, 911.9 },{ 599.1, 910.2 }, { 748.9, 908.9 },{ 892.9, 907.1 },{ 1032.1, 905.1 } }; DPNT_T points_4[36] = { { 328.0, 193.2 },{ 469.8, 192.8 },{ 611.9, 192.3 }, { 754.7, 192.2 },{ 897.0, 192.3 },{ 1039.2, 192.8 }, { 326.9, 335.2 },{ 469.0, 335.0 },{ 611.8, 334.9 }, { 754.8, 334.9 },{ 897.2, 334.9 },{ 1040.0, 335.0 }, { 326.1, 477.9 },{ 468.3, 477.9 },{ 611.1, 477.9 }, { 754.7, 477.9 },{ 897.7, 478.0 },{ 1040.2, 477.9 }, { 325.8, 621.0 },{ 468.0, 621.0 },{ 611.0, 621.1 }, { 754.2, 621.2 },{ 897.7, 621.2 },{ 1040.7, 621.2 }, { 325.2, 764.0 },{ 467.9, 764.3 },{ 610.9, 764.9 }, { 754.1, 765.0 },{ 897.2, 765.0 },{ 1040.7, 764.9 }, { 325.1, 907.0 },{ 467.8, 907.8 },{ 610.8, 908.1 }, { 754.0, 908.2 },{ 897.0, 908.2 },{ 1040.1, 908.1 } }; FHANDLE hcalib = NULL; F_CAMERA_PARAM camera; // FIEライブラリの使用前に必ずコールする必要があります。 fnFIE_setup(); //カメラキャリブレーションデータオブジェクトを生成します。 hcalib = fnFIE_calib_open( model, 36, NULL ); //データを追加します。 fnFIE_calib_add_data( hcalib, points_0, 36 ); fnFIE_calib_add_data( hcalib, points_1, 36 ); fnFIE_calib_add_data( hcalib, points_2, 36 ); fnFIE_calib_add_data( hcalib, points_3, 36 ); fnFIE_calib_add_data( hcalib, points_4, 36 ); //カメラ内部パラメータと歪み係数を計算します。 fnFIE_calib_calc_intrinsic_parameters( hcalib, &camera ); printf( "alpha\t:%f\nbeta\t:%f\ngamma\t:%f\nu0\t:%f\nv0\t:%f\nk1\t:%f\nk2\t:%f\n", camera.a, camera.b, camera.g, camera.u, camera.v, camera.k1, camera.k2 ); fnFIE_free_object( hcalib ); // 終了処理 fnFIE_teardown(); return 0; }
INT FVALGAPI fnFIE_calib_calc_1shot | ( | FHANDLE | hcalib, | |
INT | view_num, | |||
F_CAMERA_PARAM * | pcamera, | |||
FMATRIX * | homography | |||
) |
1視野による特殊カメラキャリブレーションの実行
1視野のみのデータによる特殊なカメラキャリブレーションを実施し、 カメラ内部パラメータ pcamera 及び カメラ混合パラメータ homography を算出します。
本関数の実行前に fnFIE_calib_add_data() により 1回以上データを追加していなければなりません。
本関数では一回分の撮像結果だけでキャリブレーションを行うため、 全てのカメラ内部パラメータを求めることができません(情報が足りない)。 そのため、カメラ内部パラメータのうち、歪み中心 u0, v0 と、 歪み係数 k1, k2 のみを推定します。alpha, beta, gamma は内部で仮定した定数(1,1,0)が使用されます。 つまり、スケールは1、スキュー無しという過程の元で計算が 行われるということです。
より良いパラメータを推定するためには、 下記の事項に注意してデータを作成してください。
[in] | hcalib | キャリブレーションデータオブジェクト |
[in] | view_num | hcalib に何番目に追加したデータを使うか (0 <= view_num < fnFIE_calib_add_data() を呼んだ回数) |
[out] | pcamera | カメラ内部パラメータ構造体 |
[out] | homography | 指定した視野データに対応するカメラ混合パラメータ サイズ3*3の行列 |
F_ERR_NONE | 正常終了 | |
F_ERR_INVALID_OBJECT | オブジェクト異常 | |
F_ERR_INVALID_PARAM | パラメータ異常 | |
F_ERR_NOMEMORY | メモリ不足 | |
F_ERR_CALC_IMPOSSIBLE | 計算不能 | |
F_ERR_NO_LICENCE | ライセンスエラー、または未初期化エラー |
INT FVALGAPI fnFIE_calib_calc_extrinsic_parameters | ( | F_CAMERA_PARAM | camera, | |
DPNT_T * | model_points, | |||
DPNT_T * | marker_points, | |||
INT | num_points, | |||
FMATRIX * | rotation, | |||
FVECTOR * | translation, | |||
FMATRIX * | homography | |||
) |
カメラ外部パラメータとカメラ混合パラメータの算出
基準モデル座標データと、 そのモデルを撮像した撮像画像から抽出した座標データを fnFIE_calib_undistort_points() で歪み補正した座標データの対から、 カメラ外部パラメータ(回転行列 rotation , 並進ベクトル
translation)と カメラ混合パラメータ
homography を算出します。
model_points と marker_points は対応する点を同じ順番で格納して与える必要があります。 また、どちらも同じ点数 num_points である必要があります。 キャリブレーションテンプレートはカメラ内部パラメータの算出に用いたものと 数値の単位が同一であればテンプレート自体が同一でなくてもかまいません。 与えるモデルデータ座標値は fnFIE_calib_rectify_matrix() や fnFIE_calib_rectify_ud_image_map() に与える ppm の単位に影響します。
fnFIE_calib_calc_1shot() で求めたカメラ内部パラメータを用いて当関数でカメラ混合パラメータやカメラ外部パラメータを算出することはできません。 fnFIE_calib_calc_1shot() でカメラ内部パラメータと同時に算出したホモグラフィ行列を利用してください。
[in] | camera | カメラ内部パラメータ構造体 |
[in] | model_points | モデルデータの配列 |
[in] | marker_points | 画像から検出して歪み補正を適用済みの特徴点座標の配列 |
[in] | num_points | 配列の要素数 |
[out] | rotation | カメラ外部パラメータ(回転行列) 3*3の行列 |
[out] | translation | カメラ外部パラメータ(並進ベクトル) 要素3のベクトル |
[out] | homography | カメラ混合パラメータ 3*3の行列 |
F_ERR_NONE | 正常終了 | |
F_ERR_NOMEMORY | メモリ不足 | |
F_ERR_CALC_IMPOSSIBLE | 計算不能 | |
F_ERR_INVALID_PARAM | パラメータ異常
| |
F_ERR_NO_LICENCE | ライセンスエラー、または未初期化エラー |
//エラー処理は省略しているので注意してください。 #include <stdio.h> #include "fie.h" //カメラ外部パラメータを求めます。 INT main(VOID) { //キャリブレーションテンプレート座標系における、モデルの座標データを用意します。 DPNT_T model[36] = { { 0, 0},{ 4, 0},{ 8, 0}, {12, 0},{16, 0},{20, 0}, { 0, 4},{ 4, 4},{ 8, 4}, {12, 4},{16, 4},{20, 4}, { 0, 8},{ 4, 8},{ 8, 8}, {12, 8},{16, 8},{20, 8}, { 0,12},{ 4,12},{ 8,12}, {12,12},{16,12},{20,12}, { 0,16},{ 4,16},{ 8,16}, {12,16},{16,16},{20,16}, { 0,20},{ 4,20},{ 8,20}, {12,20},{16,20},{20,20} }; //カメラ画像座標系における、特徴点の検出データを1つだけ用意します。 //各座標値はmodelと同じ順番に並んでいます。 DPNT_T points[36] = { { 263.1, 175.2 },{ 374.9, 156.8 },{ 491.2, 138.5 }, { 612.0, 119.1 },{ 737.4, 99.2 },{ 867.7, 78.9 }, { 275.4, 312.2 },{ 387.7, 296.7 },{ 504.4, 280.6 }, { 625.7, 264.1 },{ 751.6, 246.9 },{ 882.3, 229.3 }, { 288.2, 449.6 },{ 400.8, 436.8 },{ 517.8, 423.3 }, { 639.4, 409.3 },{ 765.7, 395.1 },{ 896.8, 380.1 }, { 301.1, 587.3 },{ 413.9, 577.0 },{ 531.1, 566.2 }, { 653.1, 555.2 },{ 779.8, 543.8 },{ 911.1, 531.3 }, { 314.2, 725.1 },{ 427.2, 717.2 },{ 544.9, 709.2 }, { 667.0, 701.0 },{ 793.9, 692.1 },{ 925.3, 682.9 }, { 327.8, 862.3 },{ 440.9, 857.2 },{ 558.2, 852.0 }, { 680.9, 846.2 },{ 807.8, 840.1 },{ 939.2, 833.8 } }; F_CAMERA_PARAM camera; FMATRIX *rotation = NULL, *homography = NULL; FVECTOR *translation = NULL; // FIEライブラリの使用前に必ずコールする必要があります。 fnFIE_setup(); //カメラ内部パラメータを用意します。 camera.a = 4004.927964; camera.b = 4013.092279; camera.g = -3.073555; camera.u = 681.768416; camera.v = 515.571246; camera.k1 = -0.286936; camera.k2 = 1.420280; //出力先を用意します。 rotation = fnFIE_mat_aalloc( 3, 3 ); homography = fnFIE_mat_aalloc( 3, 3 ); translation = fnFIE_mat_valloc( 3 ); //カメラ外部パラメータを計算します。 fnFIE_calib_calc_extrinsic_parameters( camera, model, points, 36, rotation, translation, homography ); printf( "%f\t%f\t%f\n%f\t%f\t%f\n%f\t%f\t%f\n", homography->m[0][0],homography->m[0][1],homography->m[0][2], homography->m[1][0],homography->m[1][1],homography->m[1][2], homography->m[2][0],homography->m[2][1],homography->m[2][2] ); fnFIE_mat_afree( rotation ); fnFIE_mat_afree( homography ); fnFIE_mat_vfree( translation ); // 終了処理 fnFIE_teardown(); return 0; }
INT FVALGAPI fnFIE_calib_calc_homography_matrix | ( | F_CAMERA_PARAM | camera, | |
FMATRIX * | rotation, | |||
FVECTOR * | translation, | |||
FMATRIX * | homography | |||
) |
カメラ混合パラメータの算出
カメラ内部パラメータ camera の線形成分 と カメラ外部パラメータの回転成分 rotation 及び 並進成分 translation より、カメラ混合パラメータ homography を算出します。
なお、本関数によって得られる変換行列 homography は カメラ外部パラメータの回転成分 rotation 及び 並進成分 translation に加工をしない限り fnFIE_calib_calc_extrinsic_parameters() で得られる homography と同一になります。 本関数は rotation や translation の値を自分で変更した後に カメラ混合パラメータを作成したい場合に使用してください。
としたとき
を計算し、 を1に正規化した
を出力します。
[in] | camera | カメラ内部パラメータ構造体 |
[in] | rotation | カメラ外部パラメータ(回転行列) サイズ3x3の行列 |
[in] | translation | カメラ外部パラメータ(並進ベクトル) サイズ3のベクトル |
[out] | homography | カメラ混合パラメータ サイズ3x3の行列 |
F_ERR_NONE | 正常終了 | |
F_ERR_NOMEMORY | メモリ不足 | |
F_ERR_INVALID_PARAM | パラメータ異常
| |
F_ERR_NO_LICENCE | ライセンスエラー、または未初期化エラー |
INT FVALGAPI fnFIE_calib_calc_error | ( | FHANDLE | hcalib, | |
F_CAMERA_PARAM | camera, | |||
DOUBLE * | min_error, | |||
DOUBLE * | max_error, | |||
DOUBLE * | average_error | |||
) |
カメラ内部パラメータの精度の検証
算出済みのカメラ内部パラメータを利用して hcalib 内の基準モデル座標列をカメラ画像座標系に投影し、 hcalib 内のカメラ画像座標系でのデータと比較して逆投影誤差を計算します。
[in] | hcalib | キャリブレーションデータオブジェクト |
[in] | camera | カメラ内部パラメータ |
[out] | min_error | 最も近かった対応点間の距離 |
[out] | max_error | 最も遠かった対応点間の距離 |
[out] | average_error | 全ての対応点間の距離の平均 |
F_ERR_NONE | 正常終了 | |
F_ERR_INVALID_PARAM | パラメータ異常 | |
F_ERR_INVALID_OBJECT | オブジェクト異常 | |
F_ERR_NOMEMORY | メモリ不足 | |
F_ERR_NO_LICENCE | ライセンスエラー、または未初期化エラー |
INT FVALGAPI fnFIE_calib_calc_error2 | ( | FHANDLE | hcalib, | |
F_CAMERA_PARAM | camera, | |||
INT | view_num, | |||
DPNT_T * | diff, | |||
INT | num_points | |||
) |
カメラ内部パラメータの精度の検証2
算出済みのカメラ内部パラメータを利用して hcalib 内の基準モデル座標列をカメラ画像座標系に投影し、 hcalib 内に格納済みのモデル撮像結果座標列のうち view_num で指定したカメラ画像座標系でのデータと比較して逆投影誤差を計算します。 計算結果は、モデルをカメラ画像座標系へ投影した座標値からカメラ画像座標系でのデータを減算した値を基準モデル座標列に対応した順番で返します。 diff の単位はカメラ画像座標系におけるピクセルです。
fnFIE_calib_calc_error3() とは、当関数の場合キャリブレーションデータオブジェクトの内部に追加済みのモデル撮像結果座標列を用いる点が異なります。 内部に追加済みの座標列のうち、どの座標列のどの点が算出済みのカメラ内部パラメータとあまり適合しないのか調べるなどの目的で用います。
[in] | hcalib | キャリブレーションデータオブジェクト |
[in] | camera | カメラ内部パラメータ |
[in] | view_num | カメラ画像座標系番号 ( 0 <= view_num < fnFIE_calib_add_data() 又は fnFIE_calib_add_data2() を呼んだ回数 ) |
[out] | diff | 逆投影誤差配列 |
[out] | num_points | diff 配列が含む座標の個数。基準モデル座標列の個数と同じである必要があります。 |
F_ERR_NONE | 正常終了 | |
F_ERR_INVALID_PARAM | パラメータ異常
| |
F_ERR_INVALID_OBJECT | オブジェクト異常 | |
F_ERR_NOMEMORY | メモリ不足 | |
F_ERR_CALC_IMPOSSIBLE | 計算不能 ( 指定したモデル撮像結果座標列に対するカメラ外部パラメータ算出に失敗した ) | |
F_ERR_NO_LICENCE | ライセンスエラー、または未初期化エラー |
INT FVALGAPI fnFIE_calib_calc_error3 | ( | FHANDLE | hcalib, | |
F_CAMERA_PARAM | camera, | |||
DPNT_T * | points, | |||
DPNT_T * | diff, | |||
INT | num_points | |||
) |
カメラ内部パラメータの精度の検証3
算出済みのカメラ内部パラメータを利用して hcalib 内の基準モデル座標列をカメラ画像座標系に投影し、 points と比較して逆投影誤差を計算します。 points にて与える座標列は fnFIE_calib_open() で設定した基準モデル座標列と同じ数でなければなりません。 またその順序は、基準モデル座標列の指定時と同じ順序でなければなりません。 なお、points の座標はカメラ画像の座標系 (画像左上を原点として単位はピクセル)で与えてください。 計算結果は、基準モデル座標列をカメラ画像座標系へ投影した座標値からカメラ画像座標系でのデータである points を減算した値を、基準モデル座標列に対応した順番で返します。 diff の単位も points 同様にカメラ画像座標系におけるピクセルです。
fnFIE_calib_calc_error2() とは、 fnFIE_calib_add_data() や fnFIE_calib_add_data2() でキャリブレーションデータオブジェクトの内部に追加済みのモデル撮像結果座標列を用いるのではなく、 当関数に直接モデル撮像結果座標列を与える点で異なります。 当関数はカメラパラメータの算出に用いなかった座標列で誤差検証を行いたい場合などに利用します。
[in] | hcalib | キャリブレーションデータオブジェクト |
[in] | camera | カメラ内部パラメータ |
[in] | points | 画像から検出したモデル座標の配列。 hcalib の基準モデル座標列と対応した順番である必要があります。 |
[out] | diff | 逆投影誤差配列 |
[in] | num_points | points と diff 配列のサイズ。 基準モデル座標配列と同じ個数である必要があります。 |
F_ERR_NONE | 正常終了 | |
F_ERR_INVALID_PARAM | パラメータ異常
| |
F_ERR_INVALID_OBJECT | オブジェクト異常 | |
F_ERR_NOMEMORY | メモリ不足 | |
F_ERR_CALC_IMPOSSIBLE | 計算不能 ( points に対するカメラ外部パラメータ算出に失敗した ) | |
F_ERR_NO_LICENCE | ライセンスエラー、または未初期化エラー |