static void draw_warp_line( double a, double b , double c ) { ARdouble x, y; ARdouble x0 = 0, y0 = 0; ARdouble x1, y1; int i; glLineWidth( 1.0f ); glBegin(GL_LINE_STRIP); if( a*a >= b*b ) { for( i = -20; i <= ysize+20; i+=10 ) { x = -(b*i + c)/a; y = i; arParamIdeal2Observ( dist_factor, x, y, &x1, &y1, dist_function_version ); if( i != -20 ) { argDrawLineByObservedPos( x0, y0, x1, y1 ); } x0 = x1; y0 = y1; } } else { for( i = -20; i <= xsize+20; i+=10 ) { x = i; y = -(a*i + c)/b; arParamIdeal2Observ( dist_factor, x, y, &x1, &y1, dist_function_version ); if( i != -20 ) { argDrawLineByObservedPos( x0, y0, x1, y1 ); } x0 = x1; y0 = y1; } } glEnd(); }
static void draw_warp_line( double a, double b , double c ) { double x, y; double x1, y1; // double d; // unreferenced int i; glLineWidth( 1.0 ); glBegin(GL_LINE_STRIP); if( a*a >= b*b ) { for( i = -20; i <= ysize+20; i+=10 ) { x = -(b*i + c)/a; y = i; arParamIdeal2Observ( dist_factor, x, y, &x1, &y1 ); glVertex2f( x1, ysize-1-y1 ); } } else { for( i = -20; i <= xsize+20; i+=10 ) { x = i; y = -(a*i + c)/b; arParamIdeal2Observ( dist_factor, x, y, &x1, &y1 ); glVertex2f( x1, ysize-1-y1 ); } } glEnd(); }
void lineSeg(double x1, double y1, double x2, double y2, ARGL_CONTEXT_SETTINGS_REF contextSettings, ARParam cparam, double zoom) { int enable; float ox, oy; double xx1, yy1, xx2, yy2; if (!contextSettings) return; arglDistortionCompensationGet(contextSettings, &enable); if (arglDrawModeGet(contextSettings) == AR_DRAW_BY_TEXTURE_MAPPING && enable) { xx1 = x1; yy1 = y1; xx2 = x2; yy2 = y2; } else { arParamIdeal2Observ(cparam.dist_factor, x1, y1, &xx1, &yy1); arParamIdeal2Observ(cparam.dist_factor, x2, y2, &xx2, &yy2); } xx1 *= zoom; yy1 *= zoom; xx2 *= zoom; yy2 *= zoom; ox = 0; oy = cparam.ysize - 1; glBegin(GL_LINES); glVertex2f(ox + xx1, oy - yy1); glVertex2f(ox + xx2, oy - yy2); glEnd(); glFlush(); }
/* * Class: net_towerdefender_image_MarkerInfo * Method: artoolkit_detectmarkers * Signature: ([B[D)I */ JNIEXPORT jint JNICALL Java_net_towerdefender_image_ARToolkit_artoolkit_1detectmarkers( JNIEnv *env, jobject object, jbyteArray image, jobject transMatMonitor) { ARUint8 *dataPtr; ARMarkerInfo *marker_info; double *matrixPtr; int marker_num; int j, k = -1; Object* curObject; /* grab a vide frame */ dataPtr = (*env)->GetByteArrayElements(env, image, JNI_FALSE); if (count == 0) arUtilTimerReset(); count++; /* detect the markers in the video frame */ if (arDetectMarker(dataPtr, thresh, &marker_info, &marker_num) < 0) { __android_log_write(ANDROID_LOG_ERROR, "AR native", "arDetectMarker failed!!"); jclass exc = (*env)->FindClass(env, "net/towerdefender/exceptions/ARException"); if (exc != NULL) (*env)->ThrowNew(env, exc, "failed to detect marker"); } #ifdef DEBUG_LOGGING __android_log_print(ANDROID_LOG_INFO,"AR native","detected %d markers",marker_num); #endif //lock the matrix /*(*env)->MonitorEnter(env, transMatMonitor); cur_marker_id = k; argConvGlpara(patt_trans, gl_para); (*env)->MonitorExit(env, transMatMonitor);*/ static jfieldID visibleField = NULL; static jfieldID glMatrixField = NULL; static jfieldID transMatField = NULL; static jfieldID vertexField = NULL; //static jfieldID dirField = NULL; jclass arObjectClass = NULL; jfloatArray glMatrixArrayObj = NULL; jdoubleArray transMatArrayObj = NULL; jdoubleArray vertexArrayObj = NULL; //jint dirObj = NULL; #ifdef DEBUG_LOGGING __android_log_write(ANDROID_LOG_INFO,"AR native","done detecting markers, going to iterate over markers now"); #endif //iterate over objects: list_iterator_start(&objects); /* starting an iteration "session" */ int itCount = 0; while (list_iterator_hasnext(&objects)) { /* tell whether more values available */ curObject = (Object *) list_iterator_next(&objects); /* get the next value */ #ifdef DEBUG_LOGGING __android_log_print(ANDROID_LOG_INFO,"AR native","now handling object with id %d, in %d iteration",curObject->name, itCount); #endif itCount++; // //get field ID' if (visibleField == NULL) { if (arObjectClass == NULL) { if (curObject->objref != NULL) arObjectClass = (*env)->GetObjectClass(env, curObject->objref); } if (arObjectClass != NULL) { visibleField = (*env)->GetFieldID(env, arObjectClass, "visible", "Z"); //Z means boolean } } if (glMatrixField == NULL) { if (arObjectClass == NULL) { if (curObject->objref != NULL) arObjectClass = (*env)->GetObjectClass(env, curObject->objref); } if (arObjectClass != NULL) { glMatrixField = (*env)->GetFieldID(env, arObjectClass, "glMatrix", "[F"); //[F means array of floats } } if (transMatField == NULL) { if (arObjectClass == NULL) { if (curObject->objref != NULL) arObjectClass = (*env)->GetObjectClass(env, curObject->objref); } if (arObjectClass != NULL) { transMatField = (*env)->GetFieldID(env, arObjectClass, "transMat", "[D"); //[D means array of doubles } } if (vertexField == NULL) { if (arObjectClass == NULL) { if (curObject->objref != NULL) arObjectClass = (*env)->GetObjectClass(env, curObject->objref); } if (arObjectClass != NULL) { vertexField = (*env)->GetFieldID(env, arObjectClass, "vertexMat", "[D"); //[F means array of floats } } /*if (dirField == NULL) { if (arObjectClass == NULL) { if (curObject->objref != NULL) arObjectClass = (*env)->GetObjectClass(env, curObject->objref); } if (arObjectClass != NULL) { dirField = (*env)->GetFieldID(env, arObjectClass, "dir", "I"); //[F means array of floats } } */ if (visibleField == NULL || glMatrixField == NULL || transMatField == NULL /*|| dirField == NULL*/) { //something went wrong.. #ifdef DEBUG_LOGGING __android_log_write(ANDROID_LOG_INFO,"AR native","error: either visibleField or glMatrixField or transMatField null"); #endif continue; } // check for object visibility k = -1; for (j = 0; j < marker_num; j++) { #ifdef DEBUG_LOGGING __android_log_print(ANDROID_LOG_INFO,"AR native","marker with id: %d", marker_info[j].id); #endif if (curObject->id == marker_info[j].id) { if (k == -1) { k = j; #ifdef DEBUG_LOGGING __android_log_print(ANDROID_LOG_INFO,"AR native","detected object %d with marker %d and object marker %d",curObject->name,k,curObject->id); #endif } else if (marker_info[k].cf < marker_info[j].cf) { #ifdef DEBUG_LOGGING __android_log_print(ANDROID_LOG_INFO,"AR native","detected better object %d with marker %d and object marker %d",curObject->name,k,curObject->id); #endif k = j; } } } if (k == -1) { //object not visible curObject->contF = 0; (*env)->SetBooleanField(env, curObject->objref, visibleField, JNI_FALSE); #ifdef DEBUG_LOGGING __android_log_print(ANDROID_LOG_INFO,"AR native","object %d not visible, with marker ID %d",curObject->name,curObject->id); #endif continue; } //object visible //lock the object #ifdef DEBUG_LOGGING __android_log_write(ANDROID_LOG_INFO,"AR native","locking object"); #endif (*env)->MonitorEnter(env, curObject->objref); #ifdef DEBUG_LOGGING __android_log_write(ANDROID_LOG_INFO,"AR native","done locking object...obtaining arrays"); #endif //access the arrays of the current object glMatrixArrayObj = (*env)->GetObjectField(env, curObject->objref, glMatrixField); transMatArrayObj = (*env)->GetObjectField(env, curObject->objref, transMatField); vertexArrayObj = (*env)->GetObjectField(env, curObject->objref, vertexField); /*dirObj = (*env)->GetObjectField(env, curObject->objref, dirField);*/ if (transMatArrayObj == NULL || glMatrixArrayObj == NULL || vertexArrayObj == NULL /*|| dirObj == NULL*/) { #ifdef DEBUG_LOGGING __android_log_write(ANDROID_LOG_INFO,"AR native","failed to fetch the matrix arrays objects"); #endif continue; //something went wrong } float *glMatrix = (*env)->GetFloatArrayElements(env, glMatrixArrayObj, JNI_FALSE); if (glMatrix == NULL) { #ifdef DEBUG_LOGGING __android_log_write(ANDROID_LOG_INFO,"AR native","failed to fetch the matrix arrays"); #endif continue; //something went wrong } double *vertexMatrix = (*env)->GetDoubleArrayElements(env, vertexArrayObj, JNI_FALSE); if (vertexMatrix == NULL) { #ifdef DEBUG_LOGGING __android_log_write(ANDROID_LOG_INFO,"AR native","failed to fetch the vertex arrays"); #endif continue; //something went wrong } double* transMat = (*env)->GetDoubleArrayElements(env, transMatArrayObj, JNI_FALSE); if (transMat == NULL) { #ifdef DEBUG_LOGGING __android_log_write(ANDROID_LOG_INFO,"AR native","failed to fetch the matrix arrays"); #endif continue; //something went wrong } #ifdef DEBUG_LOGGING __android_log_write(ANDROID_LOG_INFO,"AR native","calculating trans mat now"); #endif /*int* dirPtr = (*env)->GetIntArrayElements(env, dirObj, JNI_FALSE); if (dirPtr == NULL) { #ifdef DEBUG_LOGGING __android_log_write(ANDROID_LOG_INFO,"AR native","failed to fetch the matrix arrays"); #endif continue; //something went wrong } #ifdef DEBUG_LOGGING __android_log_write(ANDROID_LOG_INFO,"AR native","calculating trans mat now"); #endif */ // get the transformation between the marker and the real camera if (curObject->contF == 0) { arGetTransMat(&marker_info[k], curObject->marker_center, curObject->marker_width, transMat); } else { arGetTransMatCont(&marker_info[k], transMat, curObject->marker_center, curObject->marker_width, transMat); } curObject->contF = 1; #ifdef DEBUG_LOGGING __android_log_write(ANDROID_LOG_INFO,"AR native","calculating OpenGL trans mat now"); #endif argConvGlpara(transMat, glMatrix); int vertexId = 0; double inx,iny,outx,outy; for (vertexId = 0 ; vertexId < 8 ; vertexId+=2) { inx = ((double *)marker_info[k].vertex)[vertexId]; iny = ((double *)marker_info[k].vertex)[vertexId+1]; arParamIdeal2Observ ( arParam.dist_factor, inx,iny,&outx,&outy); vertexMatrix[vertexId] = outx; vertexMatrix[vertexId+1] = outy; } //*dirPtr = marker_info[k].dir; //argConvGlpara(patt_trans, gl_para); #ifdef DEBUG_LOGGING __android_log_write(ANDROID_LOG_INFO,"AR native","releasing arrays"); #endif (*env)->ReleaseFloatArrayElements(env, glMatrixArrayObj, glMatrix, 0); (*env)->ReleaseDoubleArrayElements(env, transMatArrayObj, transMat, 0); (*env)->ReleaseDoubleArrayElements(env, vertexArrayObj, vertexMatrix, 0); //(*env)->ReleaseDoubleArrayElements(env, dirObj, dirPtr, 0); (*env)->SetBooleanField(env, curObject->objref, visibleField, JNI_TRUE); #ifdef DEBUG_LOGGING __android_log_write(ANDROID_LOG_INFO,"AR native","releasing lock"); #endif //release the lock on the object (*env)->MonitorExit(env, curObject->objref); #ifdef DEBUG_LOGGING __android_log_write(ANDROID_LOG_INFO,"AR native","done releasing lock"); #endif } list_iterator_stop(&objects); /* starting the iteration "session" */ #ifdef DEBUG_LOGGING __android_log_write(ANDROID_LOG_INFO,"AR native","releasing image array"); #endif (*env)->ReleaseByteArrayElements(env, image, dataPtr, 0); #ifdef DEBUG_LOGGING __android_log_write(ANDROID_LOG_INFO,"AR native","releasing image array"); #endif return marker_num; }
static double arGetTransMatSub( double rot[3][3], double ppos2d[][2], double pos3d[][3], int num, double conv[3][4], double *dist_factor, double cpara[3][4] ) { ARMat *mat_a, *mat_b, *mat_c, *mat_d, *mat_e, *mat_f; double trans[3]; double wx, wy, wz; double ret; int i, j; mat_a = arMatrixAlloc( num*2, 3 ); mat_b = arMatrixAlloc( 3, num*2 ); mat_c = arMatrixAlloc( num*2, 1 ); mat_d = arMatrixAlloc( 3, 3 ); mat_e = arMatrixAlloc( 3, 1 ); mat_f = arMatrixAlloc( 3, 1 ); if( arFittingMode == AR_FITTING_TO_INPUT ) { for( i = 0; i < num; i++ ) { arParamIdeal2Observ(dist_factor, ppos2d[i][0], ppos2d[i][1], &pos2d[i][0], &pos2d[i][1]); } } else { for( i = 0; i < num; i++ ) { pos2d[i][0] = ppos2d[i][0]; pos2d[i][1] = ppos2d[i][1]; } } for( j = 0; j < num; j++ ) { wx = rot[0][0] * pos3d[j][0] + rot[0][1] * pos3d[j][1] + rot[0][2] * pos3d[j][2]; wy = rot[1][0] * pos3d[j][0] + rot[1][1] * pos3d[j][1] + rot[1][2] * pos3d[j][2]; wz = rot[2][0] * pos3d[j][0] + rot[2][1] * pos3d[j][1] + rot[2][2] * pos3d[j][2]; mat_a->m[j*6+0] = mat_b->m[num*0+j*2] = cpara[0][0]; mat_a->m[j*6+1] = mat_b->m[num*2+j*2] = cpara[0][1]; mat_a->m[j*6+2] = mat_b->m[num*4+j*2] = cpara[0][2] - pos2d[j][0]; mat_c->m[j*2+0] = wz * pos2d[j][0] - cpara[0][0]*wx - cpara[0][1]*wy - cpara[0][2]*wz; mat_a->m[j*6+3] = mat_b->m[num*0+j*2+1] = 0.0; mat_a->m[j*6+4] = mat_b->m[num*2+j*2+1] = cpara[1][1]; mat_a->m[j*6+5] = mat_b->m[num*4+j*2+1] = cpara[1][2] - pos2d[j][1]; mat_c->m[j*2+1] = wz * pos2d[j][1] - cpara[1][1]*wy - cpara[1][2]*wz; } arMatrixMul( mat_d, mat_b, mat_a ); arMatrixMul( mat_e, mat_b, mat_c ); arMatrixSelfInv( mat_d ); arMatrixMul( mat_f, mat_d, mat_e ); trans[0] = mat_f->m[0]; trans[1] = mat_f->m[1]; trans[2] = mat_f->m[2]; ret = arModifyMatrix( rot, trans, cpara, pos3d, pos2d, num ); for( j = 0; j < num; j++ ) { wx = rot[0][0] * pos3d[j][0] + rot[0][1] * pos3d[j][1] + rot[0][2] * pos3d[j][2]; wy = rot[1][0] * pos3d[j][0] + rot[1][1] * pos3d[j][1] + rot[1][2] * pos3d[j][2]; wz = rot[2][0] * pos3d[j][0] + rot[2][1] * pos3d[j][1] + rot[2][2] * pos3d[j][2]; mat_a->m[j*6+0] = mat_b->m[num*0+j*2] = cpara[0][0]; mat_a->m[j*6+1] = mat_b->m[num*2+j*2] = cpara[0][1]; mat_a->m[j*6+2] = mat_b->m[num*4+j*2] = cpara[0][2] - pos2d[j][0]; mat_c->m[j*2+0] = wz * pos2d[j][0] - cpara[0][0]*wx - cpara[0][1]*wy - cpara[0][2]*wz; mat_a->m[j*6+3] = mat_b->m[num*0+j*2+1] = 0.0; mat_a->m[j*6+4] = mat_b->m[num*2+j*2+1] = cpara[1][1]; mat_a->m[j*6+5] = mat_b->m[num*4+j*2+1] = cpara[1][2] - pos2d[j][1]; mat_c->m[j*2+1] = wz * pos2d[j][1] - cpara[1][1]*wy - cpara[1][2]*wz; } arMatrixMul( mat_d, mat_b, mat_a ); arMatrixMul( mat_e, mat_b, mat_c ); arMatrixSelfInv( mat_d ); arMatrixMul( mat_f, mat_d, mat_e ); trans[0] = mat_f->m[0]; trans[1] = mat_f->m[1]; trans[2] = mat_f->m[2]; ret = arModifyMatrix( rot, trans, cpara, pos3d, pos2d, num ); arMatrixFree( mat_a ); arMatrixFree( mat_b ); arMatrixFree( mat_c ); arMatrixFree( mat_d ); arMatrixFree( mat_e ); arMatrixFree( mat_f ); for( j = 0; j < 3; j++ ) { for( i = 0; i < 3; i++ ) conv[j][i] = rot[j][i]; conv[j][3] = trans[j]; } return ret; }
static void calib(void) { ARParam param; CvMat *objectPoints; CvMat *imagePoints; CvMat *pointCounts; CvMat *intrinsics; CvMat *distortionCoeff; CvMat *rotationVectors; CvMat *translationVectors; CvMat *rotationVector; CvMat *rotationMatrix; float intr[3][4]; float dist[4]; ARdouble trans[3][4]; ARdouble cx, cy, cz, hx, hy, h, sx, sy, ox, oy, err; int i, j, k, l; objectPoints = cvCreateMat(capturedImageNum * chessboardCornerNumX * chessboardCornerNumY, 3, CV_32FC1); imagePoints = cvCreateMat(capturedImageNum * chessboardCornerNumX * chessboardCornerNumY, 2, CV_32FC1); pointCounts = cvCreateMat(capturedImageNum, 1, CV_32SC1); intrinsics = cvCreateMat(3, 3, CV_32FC1); distortionCoeff = cvCreateMat(1, 4, CV_32FC1); rotationVectors = cvCreateMat(capturedImageNum, 3, CV_32FC1); translationVectors = cvCreateMat(capturedImageNum, 3, CV_32FC1); rotationVector = cvCreateMat(1, 3, CV_32FC1); rotationMatrix = cvCreateMat(3, 3, CV_32FC1); l = 0; for (k = 0; k < capturedImageNum; k++) { for (i = 0; i < chessboardCornerNumX; i++) { for (j = 0; j < chessboardCornerNumY; j++) { ((float*)(objectPoints->data.ptr + objectPoints->step * l))[0] = patternWidth * i; ((float*)(objectPoints->data.ptr + objectPoints->step * l))[1] = patternWidth * j; ((float*)(objectPoints->data.ptr + objectPoints->step * l))[2] = 0.0f; ((float*)(imagePoints->data.ptr + imagePoints->step * l))[0] = cornerSet[l].x; ((float*)(imagePoints->data.ptr + imagePoints->step * l))[1] = cornerSet[l].y; l++; } } ((int*)(pointCounts->data.ptr))[k] = chessboardCornerNumX * chessboardCornerNumY; } cvCalibrateCamera2(objectPoints, imagePoints, pointCounts, cvSize(xsize, ysize), intrinsics, distortionCoeff, rotationVectors, translationVectors, 0); for (j = 0; j < 3; j++) { for (i = 0; i < 3; i++) { intr[j][i] = ((float*)(intrinsics->data.ptr + intrinsics->step * j))[i]; } intr[j][3] = 0.0f; } for (i = 0; i < 4; i++) { dist[i] = ((float*)(distortionCoeff->data.ptr))[i]; } convParam(intr, dist, xsize, ysize, ¶m); // COVHI10434 ignored. arParamDisp(¶m); l = 0; for (k = 0; k < capturedImageNum; k++) { for (i = 0; i < 3; i++) { ((float*)(rotationVector->data.ptr))[i] = ((float*)(rotationVectors->data.ptr + rotationVectors->step * k))[i]; } cvRodrigues2(rotationVector, rotationMatrix); for (j = 0; j < 3; j++) { for (i = 0; i < 3; i++) { trans[j][i] = ((float*)(rotationMatrix->data.ptr + rotationMatrix->step * j))[i]; } trans[j][3] = ((float*)(translationVectors->data.ptr + translationVectors->step * k))[j]; } // arParamDispExt(trans); err = 0.0; for (i = 0; i < chessboardCornerNumX; i++) { for (j = 0; j < chessboardCornerNumY; j++) { cx = trans[0][0] * patternWidth * i + trans[0][1] * patternWidth * j + trans[0][3]; cy = trans[1][0] * patternWidth * i + trans[1][1] * patternWidth * j + trans[1][3]; cz = trans[2][0] * patternWidth * i + trans[2][1] * patternWidth * j + trans[2][3]; hx = param.mat[0][0] * cx + param.mat[0][1] * cy + param.mat[0][2] * cz + param.mat[0][3]; hy = param.mat[1][0] * cx + param.mat[1][1] * cy + param.mat[1][2] * cz + param.mat[1][3]; h = param.mat[2][0] * cx + param.mat[2][1] * cy + param.mat[2][2] * cz + param.mat[2][3]; if (h == 0.0) continue; sx = hx / h; sy = hy / h; arParamIdeal2Observ(param.dist_factor, sx, sy, &ox, &oy, param.dist_function_version); sx = ((float*)(imagePoints->data.ptr + imagePoints->step * l))[0]; sy = ((float*)(imagePoints->data.ptr + imagePoints->step * l))[1]; err += (ox - sx) * (ox - sx) + (oy - sy) * (oy - sy); l++; } } err = sqrt(err / (chessboardCornerNumX * chessboardCornerNumY)); ARLOG("Err[%2d]: %f[pixel]\n", k + 1, err); } saveParam(¶m); cvReleaseMat(&objectPoints); cvReleaseMat(&imagePoints); cvReleaseMat(&pointCounts); cvReleaseMat(&intrinsics); cvReleaseMat(&distortionCoeff); cvReleaseMat(&rotationVectors); cvReleaseMat(&translationVectors); cvReleaseMat(&rotationVector); cvReleaseMat(&rotationMatrix); }
void findMarkers(ARUint8* dataPtr) { ARMarkerInfo *marker_info; int marker_num; int j, k; int thresh = 100; // detect the markers in the video frame int rv = arDetectMarker(dataPtr, thresh, &marker_info, &marker_num); if (rv < 0) { fprintf(stderr,"arDetectMarker failed\n"); exit(0); } fprintf(stderr,"%d markers_found \n", marker_num); /* // check for object visibility k = -1; if ( patt_id == marker_info[j].id ) { if( k == -1 ) k = j; else if( marker_info[k].cf < marker_info[j].cf ) k = j; } } */ for ( k = 0; k < marker_num; k++ ) { if (1) { double ox,oy; arParamIdeal2Observ(cparam.dist_factor , marker_info[k].pos[0], marker_info[k].pos[1], &ox, &oy); printf("%d,\t", frame_ind); //printf("%g,\t%d,\t%g,\t%g,\t%g,\t%g,\t%g,\t", printf("%d,\t%g,\t%g,\t%g,\t%g,\t", marker_info[k].id, marker_info[k].cf, (float)marker_info[k].area/(float)(xsize*ysize), // marker_info[k].pos[0]/(float)xsize, marker_info[k].pos[1]/(float)(ysize), // ox, oy, marker_info[k].pos[0], marker_info[k].pos[1] // marker_info[k].vertex[0][0]/(float)xsize, marker_info[k].vertex[0][1]/(float)(ysize)); // marker_info[k].vertex[0][0], marker_info[k].vertex[0][1] ); } /// print rotation matrix if (1) { double patt_trans[3][4]; //fprintf("%f,\t%f,\t", patt_center[0], patt_center[1]); double patt_width = 80.0; double patt_center[2] = {0.0, 0.0}; /* get the transformation between the marker and the real camera */ arGetTransMat(&marker_info[k], patt_center, patt_width, patt_trans); /// what is patt_center, it seems to be zeros //fprintf("%f,\t%f,\t", patt_center[0], patt_center[1]); int i; for (j = 0; j < 3; j++) { for (i = 0; i < 4; i++) { printf("%f,\t", patt_trans[j][i]); } printf("\t"); } } printf("\n"); } }