📄 nyarqrcodedetector.java
字号:
package jp.nyatla.nyartoolkit.sandbox.qrcode;
import jp.nyatla.nyartoolkit.NyARException;
import jp.nyatla.nyartoolkit.core.INyARSquareDetector;
import jp.nyatla.nyartoolkit.core.NyARSquare;
import jp.nyatla.nyartoolkit.core.NyARSquareStack;
import jp.nyatla.nyartoolkit.core.NyARVertexCounter;
import jp.nyatla.nyartoolkit.core.labeling.INyARLabeling;
import jp.nyatla.nyartoolkit.core.labeling.NyARLabelingImage;
import jp.nyatla.nyartoolkit.core.labeling.NyARLabelingLabel;
import jp.nyatla.nyartoolkit.core.labeling.NyARLabelingLabelStack;
import jp.nyatla.nyartoolkit.core.labeling.NyARLabeling_ARToolKit;
import jp.nyatla.nyartoolkit.core.param.NyARCameraDistortionFactor;
import jp.nyatla.nyartoolkit.core.pca2d.INyARPca2d;
import jp.nyatla.nyartoolkit.core.pca2d.*;
import jp.nyatla.nyartoolkit.core.raster.NyARBinRaster;
import jp.nyatla.nyartoolkit.core.types.NyARDoublePoint2d;
import jp.nyatla.nyartoolkit.core.types.NyARIntPoint;
import jp.nyatla.nyartoolkit.core.types.NyARIntSize;
import jp.nyatla.nyartoolkit.core.types.NyARLinear;
import jp.nyatla.nyartoolkit.core.types.matrix.NyARDoubleMatrix22;
public class NyARQrCodeDetector implements INyARSquareDetector
{
private NyARQrCodeSymbolBinder _binder;
private static final double VERTEX_FACTOR = 2.0;// 線検出のファクタ
private static final int AR_AREA_MAX = 10000;
private static final int AR_AREA_MIN = 50;
private final int _width;
private final int _height;
private final NyARLabeling_ARToolKit _labeling;
private final NyARLabelingImage _limage;
private final NyARCameraDistortionFactor _dist_factor_ref;
private final double[] _xpos;
private final double[] _ypos;
/**
* 最大i_squre_max個のマーカーを検出するクラスを作成する。
*
* @param i_param
*/
public NyARQrCodeDetector(NyARCameraDistortionFactor i_dist_factor_ref, NyARIntSize i_size) throws NyARException
{
this._width = i_size.w;
this._height = i_size.h;
this._dist_factor_ref = i_dist_factor_ref;
this._labeling = new NyARLabeling_ARToolKit();
this._limage = new NyARLabelingImage(this._width, this._height);
this._labeling.attachDestination(this._limage);
this._binder=new NyARQrCodeSymbolBinder(i_dist_factor_ref);
// 輪郭の最大長はMAX_COORD_NUMの2倍に制限
int number_of_coord = MAX_COORD_NUM* 2;
// 輪郭バッファはnumber_of_coordの2倍
this._max_coord = number_of_coord;
this._xcoord = new int[number_of_coord * 2];
this._ycoord = new int[number_of_coord * 2];
this._xpos=new double[this._width+this._height];//最大辺長はthis._width+this._height
this._ypos=new double[this._width+this._height];//最大辺長はthis._width+this._height
}
private final int _max_coord;
private final int[] _xcoord;
private final int[] _ycoord;
private void normalizeCoord(int[] i_coord_x, int[] i_coord_y, int i_index, int i_coord_num)
{
// vertex1を境界にして、後方に配列を連結
System.arraycopy(i_coord_x, 1, i_coord_x, i_coord_num, i_index);
System.arraycopy(i_coord_y, 1, i_coord_y, i_coord_num, i_index);
}
private final int[] __detectMarker_mkvertex = new int[5];
/**
* ARMarkerInfo2 *arDetectMarker2( ARInt16 *limage, int label_num, int *label_ref,int *warea, double *wpos, int *wclip,int area_max, int area_min, double
* factor, int *marker_num ) 関数の代替品 ラベリング情報からマーカー一覧を作成してo_marker_listを更新します。 関数はo_marker_listに重なりを除外したマーカーリストを作成します。
*
* @param i_raster
* 解析する2値ラスタイメージを指定します。
* @param o_square_stack
* 抽出した正方形候補を格納するリスト
* @throws NyARException
*/
public final void detectMarker(NyARBinRaster i_raster, NyARSquareStack o_square_stack) throws NyARException
{
final INyARLabeling labeling_proc = this._labeling;
final NyARLabelingImage limage = this._limage;
// 初期化
// マーカーホルダをリセット
o_square_stack.clear();
// ラベリング
labeling_proc.labeling(i_raster);
// ラベル数が0ならここまで
final int label_num = limage.getLabelStack().getLength();
if (label_num < 1) {
return;
}
final NyARLabelingLabelStack stack = limage.getLabelStack();
final NyARLabelingLabel[] labels = (NyARLabelingLabel[]) stack.getArray();
// ラベルを大きい順に整列
stack.sortByArea();
// デカいラベルを読み飛ばし
int i;
for (i = 0; i < label_num; i++) {
// 検査対象内のラベルサイズになるまで無視
if (labels[i].area <= AR_AREA_MAX) {
break;
}
}
final int xsize = this._width;
final int ysize = this._height;
final int[] xcoord = this._xcoord;
final int[] ycoord = this._ycoord;
final int coord_max = this._max_coord;
final int[] mkvertex = this.__detectMarker_mkvertex;
final int[][] buf = (int[][]) limage.getBufferReader().getBuffer();
final int[] indextable = limage.getIndexArray();
int coord_num;
int label_area;
NyARLabelingLabel label_pt;
NyARSquareStack wk_stack=new NyARSquareStack(10);
wk_stack.clear();
for (; i < label_num; i++) {
label_pt = labels[i];
label_area = label_pt.area;
// 検査対象サイズよりも小さくなったら終了
if (label_area < AR_AREA_MIN) {
break;
}
// クリップ領域が画面の枠に接していれば除外
if (label_pt.clip_l == 1 || label_pt.clip_r == xsize - 2) {// if(wclip[i*4+0] == 1 || wclip[i*4+1] ==xsize-2){
continue;
}
if (label_pt.clip_t == 1 || label_pt.clip_b == ysize - 2) {// if( wclip[i*4+2] == 1 || wclip[i*4+3] ==ysize-2){
continue;
}
// 特徴点候補であるかを確認する。
if (!hasQrEdgeFeature(buf, indextable, label_pt)) {
continue;
}
// 輪郭を取得
coord_num = limage.getContour(i, coord_max, xcoord, ycoord);
if (coord_num == coord_max) {
// 輪郭が大きすぎる。
continue;
}
// 頂点候補のインデクスを取得
final int vertex1 = scanVertex(xcoord, ycoord, coord_num);
// 頂点候補(vertex1)を先頭に並べなおした配列を作成する。
normalizeCoord(xcoord, ycoord, vertex1, coord_num);
// 頂点情報を取得
if (!getSquareVertex(xcoord, ycoord, vertex1, coord_num, label_area, mkvertex)) {
continue;
}
NyARSquare square=(NyARSquare)wk_stack.prePush();
//矩形からラインと観察座標を取得
if(!getSquareLine(mkvertex,xcoord,ycoord,square.line,square.imvertex)){
wk_stack.pop();
continue;
}
}
//シンボルの関連付け
bindQrcodeEdge(wk_stack,o_square_stack);
//エッジ同士の相関関係をしらべる。
return;
}
/**
* QRコードのエッジグループを作る
* @param i_square_stack
*/
public void bindQrcodeEdge(NyARSquareStack i_square_stack,NyARSquareStack o_square_stack) throws NyARException
{
NyARSquare[] group=new NyARSquare[3];
int number_of_edge=i_square_stack.getLength();
if(number_of_edge<3){
return;
}
NyARSquare[] sa=(NyARSquare[])i_square_stack.getArray();
for(int i=0;i<number_of_edge-2;i++)
{
group[0]=sa[i];
for(int i2=i+1;i2<number_of_edge-1;i2++)
{
group[1]=sa[i2];
for(int i3=i2+1;i3<number_of_edge;i3++){
group[2]=sa[i3];
//3個のエッジの関連性を確認する。
NyARSquare new_square=(NyARSquare)o_square_stack.prePush();
if(!this._binder.composeSquare(group,new_square)){
o_square_stack.pop();
}
}
}
}
return;
}
private static int MAX_COORD_NUM=(320+240)*2;//サイズの1/2の長方形の編程度が目安(VGAなら(320+240)*2)
private final INyARPca2d _pca=new NyARPca2d_MatrixPCA_O2();
private final NyARDoubleMatrix22 __getSquareLine_evec=new NyARDoubleMatrix22();
private final NyARDoublePoint2d __getSquareLine_mean=new NyARDoublePoint2d();
private final NyARDoublePoint2d __getSquareLine_ev=new NyARDoublePoint2d();
/**
* 頂点インデクスと輪郭配列から、Ideal座標系とLineを作成して変数に返す
* @param i_cparam
* @return
* @throws NyARException
*/
private boolean getSquareLine(int[] i_mkvertex, int[] i_xcoord, int[] i_ycoord, NyARLinear[] o_line,NyARIntPoint[] o_imvertex) throws NyARException
{
final NyARDoubleMatrix22 evec=this.__getSquareLine_evec;
final NyARDoublePoint2d mean=this.__getSquareLine_mean;
final NyARDoublePoint2d ev=this.__getSquareLine_ev;
for (int i = 0; i < 4; i++) {
final double w1 = (double) (i_mkvertex[i + 1] - i_mkvertex[i] + 1) * 0.05 + 0.5;
final int st = (int) (i_mkvertex[i] + w1);
final int ed = (int) (i_mkvertex[i + 1] - w1);
final int n = ed - st + 1;
if (n < 2 || n>MAX_COORD_NUM) {
// nが2以下、又はMAX_COORD_NUM以上なら主成分分析をしない。
return false;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -