}\r
}\r
\r
+\r
// RleImageをラベリングする。\r
public class NyARLabeling_Rle\r
{\r
}\r
\r
/**\r
- * i_bin_bufのbinイメージをREL圧縮する。\r
- * \r
- * @param i_bin_raster\r
+ * i_bin_bufのgsイメージをREL圧縮する。\r
+ * @param i_bin_buf\r
+ * @param i_st\r
+ * @param i_len\r
+ * @param i_out\r
+ * @param i_th\r
+ * BINラスタのときは0,GSラスタの時は閾値を指定する。\r
+ * この関数は、閾値を暗点と認識します。\r
+ * 暗点<=th<明点\r
+ * @return\r
*/\r
- private int toRel(int[] i_bin_buf, int i_st, int i_len, RleElement[] i_out)\r
+ private int toRel(int[] i_bin_buf, int i_st, int i_len, RleElement[] i_out,int i_th)\r
{\r
int current = 0;\r
int r = -1;\r
final int right_edge = i_st + i_len - 1;\r
while (x < right_edge) {\r
// 暗点(0)スキャン\r
- if (i_bin_buf[x] != 0) {\r
- x++;\r
+ if (i_bin_buf[x] > i_th) {\r
+ x++;//明点\r
continue;\r
}\r
// 暗点発見→暗点長を調べる\r
r++;// 暗点+1\r
x++;\r
while (x < right_edge) {\r
- if (i_bin_buf[x] != 0) {\r
+ if (i_bin_buf[x] > i_th) {\r
// 明点(1)→暗点(0)配列終了>登録\r
i_out[current].r = r;\r
current++;\r
}\r
}\r
// 最後の1点だけ判定方法が少し違うの。\r
- if (i_bin_buf[x] != 0) {\r
+ if (i_bin_buf[x] > i_th) {\r
// 明点→rカウント中なら暗点配列終了>登録\r
if (r >= 0) {\r
i_out[current].r = r;\r
\r
return;\r
}\r
-\r
- //\r
+ //所望のラスタからBIN-RLEに変換しながらの低速系も準備しようかな\r
+ \r
+ /**\r
+ * 単一閾値を使ってGSラスタをBINラスタに変換しながらラベリングします。\r
+ * @param i_gs_raster\r
+ * @param i_top\r
+ * @param i_bottom\r
+ * @param o_stack\r
+ * @return\r
+ * @throws NyARException\r
+ */\r
public int labeling(NyARBinRaster i_bin_raster, int i_top, int i_bottom,RleLabelFragmentInfoStack o_stack) throws NyARException\r
{\r
+ return this.imple_labeling(i_bin_raster,0,i_top,i_bottom,o_stack);\r
+ }\r
+ /**\r
+ * BINラスタをラベリングします。\r
+ * @param i_gs_raster\r
+ * @param i_th\r
+ * 画像を2値化するための閾値。暗点<=th<明点となります。\r
+ * @param i_top\r
+ * @param i_bottom\r
+ * @param o_stack\r
+ * @return\r
+ * @throws NyARException\r
+ */\r
+ public int labeling(NyARGrayscaleRaster i_gs_raster,int i_th, int i_top, int i_bottom,RleLabelFragmentInfoStack o_stack) throws NyARException\r
+ {\r
+ return this.imple_labeling(i_gs_raster,i_th,i_top,i_bottom,o_stack);\r
+ }\r
+ private int imple_labeling(INyARRaster i_raster,int i_th,int i_top, int i_bottom,RleLabelFragmentInfoStack o_stack) throws NyARException\r
+ {\r
// リセット処理\r
final RleInfoStack rlestack=this._rlestack;\r
rlestack.clear();\r
RleElement[] rle_current = this._rle2;\r
int len_prev = 0;\r
int len_current = 0;\r
- final int width = i_bin_raster.getWidth();\r
- int[] in_buf = (int[]) i_bin_raster.getBufferReader().getBuffer();\r
+ final int width = i_raster.getWidth();\r
+ int[] in_buf = (int[]) i_raster.getBufferReader().getBuffer();\r
\r
int id_max = 0;\r
int label_count=0;\r
// 初段登録\r
\r
- len_prev = toRel(in_buf, i_top, width, rle_prev);\r
+ len_prev = toRel(in_buf, i_top, width, rle_prev,i_th);\r
for (int i = 0; i < len_prev; i++) {\r
// フラグメントID=フラグメント初期値、POS=Y値、RELインデクス=行\r
addFragment(rle_prev[i], id_max, i_top,rlestack);\r
// 次段結合\r
for (int y = i_top + 1; y < i_bottom; y++) {\r
// カレント行の読込\r
- len_current = toRel(in_buf, y * width, width, rle_current);\r
+ len_current = toRel(in_buf, y * width, width, rle_current,i_th);\r
int index_prev = 0;\r
\r
SCAN_CUR: for (int i = 0; i < len_current; i++) {\r
{\r
/**\r
* 通常のPCA\r
- * @param i_x\r
- * @param i_y\r
+ * @param i_v1\r
+ * @param i_v2\r
* @param i_start\r
* @param i_number_of_point\r
* @param o_evec\r
+ * 要素2の変数を指定してください。\r
* @param o_ev\r
+ * 要素2の変数を指定してください。\r
* @param o_mean\r
* @throws NyARException\r
*/\r
- public void pca(double[] i_x,double[] i_y,int i_number_of_point,NyARDoubleMatrix22 o_evec, NyARDoublePoint2d o_ev,NyARDoublePoint2d o_mean) throws NyARException;\r
+ public void pca(double[] i_v1,double[] i_v2,int i_number_of_point,NyARDoubleMatrix22 o_evec, double[] o_ev,double[] o_mean) throws NyARException;\r
/**\r
* カメラ歪み補正つきのPCA\r
* @param i_x\r
import jp.nyatla.nyartoolkit.NyARException;\r
import jp.nyatla.nyartoolkit.core.NyARMat;\r
import jp.nyatla.nyartoolkit.core.NyARVec;\r
-import jp.nyatla.nyartoolkit.core.types.NyARDoublePoint2d;\r
import jp.nyatla.nyartoolkit.core.types.matrix.NyARDoubleMatrix22;\r
/**\r
* NyARMatrixを利用した主成分分析\r
private final NyARVec __pca_ev = new NyARVec(2);\r
private final NyARVec __pca_mean = new NyARVec(2); \r
\r
- public void pca(double[] i_x,double[] i_y,int i_number_of_point,NyARDoubleMatrix22 o_evec, NyARDoublePoint2d o_ev,NyARDoublePoint2d o_mean) throws NyARException\r
+ public void pca(double[] i_v1,double[] i_v2,int i_number_of_point,NyARDoubleMatrix22 o_evec, double[] o_ev,double[] o_mean) throws NyARException\r
{\r
final NyARMat input = this.__pca_input;// 次処理で初期化される。 \r
// pcaの準備\r
input.realloc(i_number_of_point, 2);\r
final double[][] input_array=input.getArray();\r
for(int i=0;i<i_number_of_point;i++){\r
- input_array[i][0]=i_x[i];\r
- input_array[i][1]=i_y[i];\r
+ input_array[i][0]=i_v1[i];\r
+ input_array[i][1]=i_v2[i];\r
}\r
// 主成分分析\r
input.pca(this.__pca_evec, this.__pca_ev, this.__pca_mean);\r
o_evec.m01=evec_array[0][1];\r
o_evec.m10=evec_array[1][0];\r
o_evec.m11=evec_array[1][1];\r
- o_ev.x=ev_array[0];\r
- o_ev.y=ev_array[1];\r
- o_mean.x=mean_array[0];\r
- o_mean.y=mean_array[1];\r
+ o_ev[0]=ev_array[0];\r
+ o_ev[1]=ev_array[1];\r
+ o_mean[0]=mean_array[0];\r
+ o_mean[1]=mean_array[1];\r
return;\r
}\r
}\r
* @param dv\r
* @throws NyARException\r
*/\r
- private static void PCA_QRM(NyARDoubleMatrix22 o_matrix, NyARDoublePoint2d dv) throws NyARException\r
+ private static void PCA_QRM(NyARDoubleMatrix22 o_matrix, double[] dv) throws NyARException\r
{\r
double w, t, s, x, y, c;\r
double ev1;\r
o_matrix.m10 = mat10; \r
o_matrix.m11 = mat11;\r
}\r
- dv.x=dv_x;\r
- dv.y=dv_y;\r
+ dv[0]=dv_x;\r
+ dv[1]=dv_y;\r
return;\r
}\r
\r
* @param o_ev\r
* @throws NyARException\r
*/\r
- private void PCA_PCA(double[] i_x,double[] i_y,int i_number_of_data,NyARDoubleMatrix22 o_matrix, NyARDoublePoint2d o_ev,NyARDoublePoint2d o_mean) throws NyARException\r
+ private void PCA_PCA(double[] i_v1,double[] i_v2,int i_number_of_data,NyARDoubleMatrix22 o_matrix, double[] o_ev,double[] o_mean) throws NyARException\r
{\r
// double[] mean_array=mean.getArray();\r
// mean.zeroClear();\r
double sx = 0;\r
double sy = 0;\r
for (int i = 0; i < i_number_of_data; i++) {\r
- sx += i_x[i];\r
- sy += i_y[i];\r
+ sx += i_v1[i];\r
+ sy += i_v2[i];\r
}\r
sx = sx / i_number_of_data;\r
sy = sy / i_number_of_data;\r
double w00, w11, w10;\r
w00 = w11 = w10 = 0.0;// *out = 0.0;\r
for (int i = 0; i < i_number_of_data; i++) {\r
- final double x = (i_x[i] - sx) / srow;\r
- final double y = (i_y[i] - sy) / srow;\r
+ final double x = (i_v1[i] - sx) / srow;\r
+ final double y = (i_v2[i] - sy) / srow;\r
w00 += (x * x);// *out += *in1 * *in2;\r
w10 += (x * y);// *out += *in1 * *in2;\r
w11 += (y * y);// *out += *in1 * *in2;\r
//PCA_PCAの処理\r
PCA_QRM(o_matrix, o_ev);\r
// m2 = o_output.m;// m2 = output->m;\r
- if (o_ev.x < PCA_VZERO) {// if( ev->v[i] < VZERO ){\r
- o_ev.x = 0.0;// ev->v[i] = 0.0;\r
+ if (o_ev[0] < PCA_VZERO) {// if( ev->v[i] < VZERO ){\r
+ o_ev[0] = 0.0;// ev->v[i] = 0.0;\r
o_matrix.m00 = 0.0;// *(m2++) = 0.0;\r
o_matrix.m01 = 0.0;// *(m2++) = 0.0;\r
}\r
\r
- if (o_ev.y < PCA_VZERO) {// if( ev->v[i] < VZERO ){\r
- o_ev.y = 0.0;// ev->v[i] = 0.0;\r
+ if (o_ev[1] < PCA_VZERO) {// if( ev->v[i] < VZERO ){\r
+ o_ev[1] = 0.0;// ev->v[i] = 0.0;\r
o_matrix.m10 = 0.0;// *(m2++) = 0.0;\r
o_matrix.m11 = 0.0;// *(m2++) = 0.0;\r
}\r
- o_mean.x=sx;\r
- o_mean.y=sy;\r
+ o_mean[0]=sx;\r
+ o_mean[1]=sy;\r
// }\r
return;\r
}\r
- public void pca(double[] i_x,double[] i_y,int i_number_of_point,NyARDoubleMatrix22 o_evec, NyARDoublePoint2d o_ev,NyARDoublePoint2d o_mean) throws NyARException\r
+ public void pca(double[] i_v1,double[] i_v2,int i_number_of_point,NyARDoubleMatrix22 o_evec, double[] o_ev,double[] o_mean) throws NyARException\r
{\r
- PCA_PCA(i_x,i_y,i_number_of_point,o_evec, o_ev,o_mean);\r
+ PCA_PCA(i_v1,i_v2,i_number_of_point,o_evec, o_ev,o_mean);\r
\r
- final double sum = o_ev.x + o_ev.y;\r
+ final double sum = o_ev[0] + o_ev[1];\r
// For順変更禁止\r
- o_ev.x /= sum;// ev->v[i] /= sum;\r
- o_ev.y /= sum;// ev->v[i] /= sum;\r
+ o_ev[0] /= sum;// ev->v[i] /= sum;\r
+ o_ev[1] /= sum;// ev->v[i] /= sum;\r
return; \r
}\r
\r
{\r
return this._buffer_reader;\r
}\r
+ /**\r
+ * 4近傍の画素ベクトルを取得します。\r
+ * 0,1,0\r
+ * 1,x,1\r
+ * 0,1,0\r
+ * @param i_raster\r
+ * @param x\r
+ * @param y\r
+ * @param o_v\r
+ */\r
+ public void getPixelVector4(int x,int y,NyARIntPoint2d o_v)\r
+ {\r
+ int[] buf=this._ref_buf;\r
+ int w=this._size.w;\r
+ int idx=w*y+x;\r
+ o_v.x=buf[idx+1]-buf[idx-1];\r
+ o_v.y=buf[idx+w]-buf[idx-w];\r
+ }\r
+ /**\r
+ * 8近傍画素ベクトル\r
+ * 1,2,1\r
+ * 2,x,2\r
+ * 1,2,1\r
+ * @param i_raster\r
+ * @param x\r
+ * @param y\r
+ * @param o_v\r
+ */\r
+ public void getPixelVector8(int x,int y,NyARIntPoint2d o_v)\r
+ {\r
+ int[] buf=this._ref_buf;\r
+ NyARIntSize s=this._size;\r
+ int idx_0 =s.w*y+x;\r
+ int idx_p1=idx_0+s.w;\r
+ int idx_m1=idx_0-s.w;\r
+ int b=buf[idx_m1-1];\r
+ int d=buf[idx_m1+1];\r
+ int h=buf[idx_p1-1];\r
+ int f=buf[idx_p1+1];\r
+ o_v.x=buf[idx_0+1]-buf[idx_0-1]+(d-b+f-h)/2;\r
+ o_v.y=buf[idx_p1]-buf[idx_m1]+(f-d+h-b)/2;\r
+ } \r
}\r
//初期化\r
this._threshold=i_initial_threshold;\r
}\r
+ /**\r
+ * 2値化の閾値を設定する。\r
+ * 暗点<=th<明点となります。\r
+ * @throws NyARException\r
+ */\r
public NyARRasterFilter_ConstantThrshold() throws NyARException\r
{\r
this._threshold=0;\r
\r
\r
}\r
+ /**\r
+ * 画像を2値化するための閾値。暗点<=th<明点となります。\r
+ * @param i_threshold\r
+ */\r
public void setThreshold(int i_threshold)\r
{\r
this._threshold = i_threshold;\r
public static final int BUFFERFORMAT_INT2D_GRAY_8 = INT2D|0x0001;\r
/**\r
* int[][]で0/1の2値画像\r
+ * これは、階調値1bitのBUFFERFORMAT_INT2D_GRAY_1と同じです。\r
*/\r
public static final int BUFFERFORMAT_INT2D_BIN_8 = INT2D|0x0002;\r
\r
public static final int BUFFERFORMAT_INT1D_GRAY_8 = INT1D|0x0001;\r
/**\r
* int[]で0/1の2値画像\r
+ * これは、階調1bitのBUFFERFORMAT_INT1D_GRAY_1と同じです。\r
*/\r
public static final int BUFFERFORMAT_INT1D_BIN_8 = INT1D|0x0002;\r
\r
// 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6\r
protected final static int[] _getContour_xdir = { 0, 1, 1, 1, 0,-1,-1,-1 , 0, 1, 1, 1, 0,-1,-1};\r
protected final static int[] _getContour_ydir = {-1,-1, 0, 1, 1, 1, 0,-1 ,-1,-1, 0, 1, 1, 1, 0};\r
+ public int getContour(NyARBinRaster i_raster,int i_entry_x,int i_entry_y,int i_array_size,int[] o_coord_x,int[] o_coord_y) throws NyARException\r
+ {\r
+ return impl_getContour(i_raster,0,i_entry_x,i_entry_y,i_array_size,o_coord_x,o_coord_y);\r
+ }\r
+ /**\r
+ * \r
+ * @param i_raster\r
+ * @param i_th\r
+ * 画像を2値化するための閾値。暗点<=i_th<明点となります。\r
+ * @param i_entry_x\r
+ * 輪郭の追跡開始点を指定します。\r
+ * @param i_entry_y\r
+ * @param i_array_size\r
+ * @param o_coord_x\r
+ * @param o_coord_y\r
+ * @return\r
+ * @throws NyARException\r
+ */\r
+ public int getContour(NyARGrayscaleRaster i_raster,int i_th,int i_entry_x,int i_entry_y,int i_array_size,int[] o_coord_x,int[] o_coord_y) throws NyARException\r
+ {\r
+ return impl_getContour(i_raster,i_th,i_entry_x,i_entry_y,i_array_size,o_coord_x,o_coord_y);\r
+ }\r
\r
/**\r
* ラスタのエントリポイントから辿れる輪郭線を配列に返します。\r
* @param i_raster\r
+ * @param i_th\r
+ * 暗点<=th<明点\r
* @param i_entry_x\r
* @param i_entry_y\r
* @param i_array_size\r
* 輪郭線の長さを返します。\r
* @throws NyARException\r
*/\r
- public int getContour(NyARBinRaster i_raster,int i_entry_x,int i_entry_y,int i_array_size,int[] o_coord_x,int[] o_coord_y) throws NyARException\r
+ public int impl_getContour(INyARRaster i_raster,int i_th,int i_entry_x,int i_entry_y,int i_array_size,int[] o_coord_x,int[] o_coord_y) throws NyARException\r
{\r
final int[] xdir = _getContour_xdir;// static int xdir[8] = { 0, 1, 1, 1, 0,-1,-1,-1};\r
final int[] ydir = _getContour_ydir;// static int ydir[8] = {-1,-1, 0, 1, 1, 1, 0,-1};\r
//4隅以外の境界接地の場合に、境界チェックを省略するとかね。\r
if(c>=1 && c<width-1 && r>=1 && r<height-1){\r
for(;;){//gotoのエミュレート用のfor文\r
- //境界に接していないとき\r
- if (i_buf[(r + ydir[dir])*width+(c + xdir[dir])] == 0) {\r
+ //境界に接していないとき(暗点判定)\r
+ if (i_buf[(r + ydir[dir])*width+(c + xdir[dir])] <= i_th) {\r
break;\r
}\r
dir++;\r
- if (i_buf[(r + ydir[dir])*width+(c + xdir[dir])] == 0) {\r
+ if (i_buf[(r + ydir[dir])*width+(c + xdir[dir])] <= i_th) {\r
break;\r
}\r
dir++;\r
- if (i_buf[(r + ydir[dir])*width+(c + xdir[dir])] == 0) {\r
+ if (i_buf[(r + ydir[dir])*width+(c + xdir[dir])] <= i_th) {\r
break;\r
}\r
dir++;\r
- if (i_buf[(r + ydir[dir])*width+(c + xdir[dir])] == 0) {\r
+ if (i_buf[(r + ydir[dir])*width+(c + xdir[dir])] <= i_th) {\r
break;\r
}\r
dir++;\r
- if (i_buf[(r + ydir[dir])*width+(c + xdir[dir])] == 0) {\r
+ if (i_buf[(r + ydir[dir])*width+(c + xdir[dir])] <= i_th) {\r
break;\r
}\r
dir++;\r
- if (i_buf[(r + ydir[dir])*width+(c + xdir[dir])] == 0) {\r
+ if (i_buf[(r + ydir[dir])*width+(c + xdir[dir])] <= i_th) {\r
break;\r
}\r
dir++;\r
- if (i_buf[(r + ydir[dir])*width+(c + xdir[dir])] == 0) {\r
+ if (i_buf[(r + ydir[dir])*width+(c + xdir[dir])] <= i_th) {\r
break;\r
}\r
dir++;\r
- if (i_buf[(r + ydir[dir])*width+(c + xdir[dir])] == 0) {\r
+ if (i_buf[(r + ydir[dir])*width+(c + xdir[dir])] <= i_th) {\r
break;\r
}\r
/*\r
final int y=r + ydir[dir];\r
//境界チェック\r
if(x>=0 && x<width && y>=0 && y<height){\r
- if (i_buf[(y)*width+(x)] == 0) {\r
+ if (i_buf[(y)*width+(x)] <= i_th) {\r
break;\r
}\r
}\r
private final NyARVertexCounter __getSquareVertex_wv2 = new NyARVertexCounter();\r
private final INyARPca2d _pca;\r
private final NyARDoubleMatrix22 __getSquareLine_evec=new NyARDoubleMatrix22();\r
- private final NyARDoublePoint2d __getSquareLine_mean=new NyARDoublePoint2d();\r
- private final NyARDoublePoint2d __getSquareLine_ev=new NyARDoublePoint2d(); \r
+ private final double[] __getSquareLine_mean=new double[2];\r
+ private final double[] __getSquareLine_ev=new double[2];\r
private final NyARObserv2IdealMap _dist_factor;\r
public SquareContourDetector(NyARIntSize i_size,NyARCameraDistortionFactor i_distfactor_ref)\r
{\r
{\r
final NyARLinear[] l_line = o_square.line;\r
final NyARDoubleMatrix22 evec=this.__getSquareLine_evec;\r
- final NyARDoublePoint2d mean=this.__getSquareLine_mean;\r
- final NyARDoublePoint2d ev=this.__getSquareLine_ev;\r
+ final double[] mean=this.__getSquareLine_mean;\r
+ final double[] ev=this.__getSquareLine_ev;\r
\r
\r
for (int i = 0; i < 4; i++) {\r
//主成分分析する。\r
this._pca.pca(this._xpos,this._ypos,n,evec, ev,mean);\r
final NyARLinear l_line_i = l_line[i];\r
- l_line_i.run = evec.m01;// line[i][0] = evec->m[1];\r
- l_line_i.rise = -evec.m00;// line[i][1] = -evec->m[0];\r
- l_line_i.intercept = -(l_line_i.run * mean.x + l_line_i.rise * mean.y);// line[i][2] = -(line[i][0]*mean->v[0] + line[i][1]*mean->v[1]);\r
+ l_line_i.dy = evec.m01;// line[i][0] = evec->m[1];\r
+ l_line_i.dx = -evec.m00;// line[i][1] = -evec->m[0];\r
+ l_line_i.c = -(l_line_i.dy * mean[0] + l_line_i.dx * mean[1]);// line[i][2] = -(line[i][0]*mean->v[0] + line[i][1]*mean->v[1]);\r
}\r
\r
final NyARDoublePoint2d[] l_sqvertex = o_square.sqvertex;\r
for (int i = 0; i < 4; i++) {\r
final NyARLinear l_line_i = l_line[i];\r
final NyARLinear l_line_2 = l_line[(i + 3) % 4];\r
- final double w1 = l_line_2.run * l_line_i.rise - l_line_i.run * l_line_2.rise;\r
+ final double w1 = l_line_2.dy * l_line_i.dx - l_line_i.dy * l_line_2.dx;\r
if (w1 == 0.0) {\r
return false;\r
}\r
- l_sqvertex[i].x = (l_line_2.rise * l_line_i.intercept - l_line_i.rise * l_line_2.intercept) / w1;\r
- l_sqvertex[i].y = (l_line_i.run * l_line_2.intercept - l_line_2.run * l_line_i.intercept) / w1;\r
+ l_sqvertex[i].x = (l_line_2.dx * l_line_i.c - l_line_i.dx * l_line_2.c) / w1;\r
+ l_sqvertex[i].y = (l_line_i.dy * l_line_2.c - l_line_2.dy * l_line_i.c) / w1;\r
// 頂点インデクスから頂点座標を得て保存\r
l_imvertex[i].x = i_xcoord[i_mkvertex[i]];\r
l_imvertex[i].y = i_ycoord[i_mkvertex[i]];\r
*/\r
package jp.nyatla.nyartoolkit.core.types;\r
\r
+/**\r
+ * 0=dx*x+dy*y+cのパラメータを格納します。\r
+ * x,yの増加方向は、x=L→R,y=B→Tです。 \r
+ *\r
+ */\r
public class NyARLinear\r
{\r
- public double rise;//y軸の増加量\r
- public double run;//x軸の増加量\r
- public double intercept;//切片\r
+ public double dx;//dx軸の増加量\r
+ public double dy;//dy軸の増加量\r
+ public double c;//切片\r
public static NyARLinear[] createArray(int i_number)\r
{\r
NyARLinear[] ret=new NyARLinear[i_number];\r
} \r
public final void copyFrom(NyARLinear i_source)\r
{\r
- this.rise=i_source.rise;\r
- this.run=i_source.run;\r
- this.intercept=i_source.intercept;\r
+ this.dx=i_source.dx;\r
+ this.dy=i_source.dy;\r
+ this.c=i_source.c;\r
return;\r
}\r
}\r