//=////////////////////////////////////////////////////////////////////// //= //= moments //= //= @file moments.cxx //= @desc Calculation of image parameters //= @author J C Gonzalez //= @email gonzalez@mppmu.mpg.de //= @date Thu May 7 16:24:22 1998 //= //=---------------------------------------------------------------------- //= //= Created: Thu May 7 16:24:22 1998 //= Author: Jose Carlos Gonzalez //= Purpose: Program for reflector simulation //= Notes: See files README for details //= //=---------------------------------------------------------------------- //= //= $RCSfile: moments.cxx,v $ //= $Revision: 1.1.1.1 $ //= $Author: harald $ //= $Date: 1999-11-05 11:59:33 $ //= //=////////////////////////////////////////////////////////////////////// // @T \newpage //!@section Source code of |moments.cxx|. /*!@{ This section describes briefly the source code for the file |moments.cxx|. All the defines it uses are located in the file |moments.h|. @"*/ //!@subsection Includes and Global variables definition. /*!@" All the defines are located in the file |moments.h|. @"*/ //!@{ #include "moments.h" //!@} //!@subsection Definition of global variables. //!@{ static int npix; //@< number of pixels static float *q; //@< charges in the pixels static float xm, ym; //@< centroid (used in moments and lenwid) //@: structure with information about the image static Moments_Info m; //@: structure with information about islands static Islands_Info is; //@: structure with information about lenwid static LenWid_Info lw; //!@} //!@subsection The function |moments()|. //!----------------------------------------------------------- // @name moments // // @desc calculate moments on the image // // @var n Number of pixels // @var *image Vector of ph.e.s in pixels // @var **pix Array with information about the pixels // @var plateScale Plate scale for the CT in use // @var flag 1: initialize; other: normal // // @return Pointer to structure Moments_Info // // @date Mon Sep 14 15:22:44 MET DST 1998 //------------------------------------------------------------ // @function //!@{ Moments_Info * moments( int n, float *image, float **pix, float plateScale, int flag ) { register int i, k; float x, y; float x2m, xym, y2m; float x3m, x2ym, xy2m, y3m; float zz, zd, zu, zv; float ax, ay, unitx, unity, sigmaax; float sx2, sxy, sy2; float sx3, sx2y, sxy2, sy3; if ( flag == 1 ) { q = new float[n]; is.fi = new float[n]; is.vislands = new float[n]; is.islands = new int[n]; is.isl = new int[n]; for (i=1; i 0.0 ) { x = pix[i][0]; y = pix[i][1]; xm += x * q[i]; ym += y * q[i]; x2m += x * x * q[i]; xym += x * y * q[i]; y2m += y * y * q[i]; x3m += x * x * x * q[i]; x2ym += x * x * y * q[i]; xy2m += x * y * y * q[i]; y3m += y * y * y * q[i]; m.charge += q[i]; } xm *= plateScale; ym *= plateScale; x2m *= plateScale * plateScale; xym *= plateScale * plateScale; y2m *= plateScale * plateScale; x3m *= plateScale * plateScale * plateScale; x2ym *= plateScale * plateScale * plateScale; xy2m *= plateScale * plateScale * plateScale; y3m *= plateScale * plateScale * plateScale; //++++++++++++++++++++++++++++++++++++++++++++++++++ // extremes and charges //-------------------------------------------------- for (i=0; i<10; ++i) m.maxs[i] = 0.0; for (i=0; i m.maxs[0] ) { for (k=9; k>0; --k) m.maxs[k] = m.maxs[k-1]; for (k=9; k>0; --k) m.nmaxs[k] = m.nmaxs[k-1]; m.maxs[0] = q[i]; m.nmaxs[0] = i; } } // calculates weighted position of the maximum (6 pixels) m.xmax = m.ymax = m.smax = 0.0; for (i=0; i<6; ++i) { m.xmax += pix[m.nmaxs[i]][0] * q[m.nmaxs[i]]; m.ymax += pix[m.nmaxs[i]][1] * q[m.nmaxs[i]]; m.smax += q[m.nmaxs[i]]; } if (m.smax==0.) m.smax=1.; if (m.charge==0.) m.charge=1.; m.xmax = m.xmax * plateScale / m.smax; m.ymax = m.ymax * plateScale / m.smax; // calculate concentrations with 2,3,4...10 pixels m.conc[0] = q[ m.nmaxs[0] ] + q[ m.nmaxs[1] ]; for (i=2; i<10; ++i) m.conc[i-1] = m.conc[i-2] + q[ m.nmaxs[i] ]; for (i=0; i<9; ++i) m.conc[i] /= m.charge; //++++++++++++++++++++++++++++++++++++++++++++++++++ // 1st moments //-------------------------------------------------- xm /= m.charge; ym /= m.charge; m.m1x = xm; m.m1y = ym; //++++++++++++++++++++++++++++++++++++++++++++++++++ // 2nd moments //-------------------------------------------------- x2m /= m.charge; xym /= m.charge; y2m /= m.charge; // around the origin m.m2xx = x2m; m.m2xy = xym; m.m2yy = y2m; // around the mean sx2 = x2m - SQR(xm); sxy = xym - xm * ym; sy2 = y2m - SQR(ym); m.m2cxx = sx2; m.m2cxy = sxy; m.m2cyy = sy2; //++++++++++++++++++++++++++++++++++++++++++++++++++ // 3rd moments //-------------------------------------------------- x3m /= m.charge; x2ym /= m.charge; xy2m /= m.charge; y3m /= m.charge; // around the origin m.m3xxx = x3m; m.m3xxy = x2ym; m.m3xyy = xy2m; m.m3yyy = y3m; // around the mean sx3 = x3m - 3 * x2m * xm + 2 * xm * xm * xm; sx2y = x2ym - 2 * xym * xm + 2 * xm * xm * ym - x2m * ym; sxy2 = xy2m - 2 * xym * ym + 2 * xm * ym * ym - y2m * xm; sy3 = y3m - 3 * y2m * ym + 2 * ym * ym * ym; m.m3cxxx = x3m; m.m3cxxy = x2ym; m.m3cxyy = xy2m; m.m3cyyy = y3m; //++++++++++++++++++++++++++++++++++++++++++++++++++ // hillas' parameters //-------------------------------------------------- zd = sy2 - sx2; zz = sqrt( SQR(zd) + 4.*SQR( sxy ));; if ( (zz < 1.e-6) || (sxy == 0.) ) { m.dist = -1.; return &m; } zu = 1.0 + zd / zz; zv = 2.0 - zu; /* a = (zd + zz) / (2 * sxy); b = ym - a * xm; m.length = sqrt( fabs( sx2 + 2 * a * sxy + a * a * sy2 ) / (1+a*a) ); m.width = sqrt( fabs( sx2 - 2 * a * sxy + a * a * sy2 ) / (1+a*a) ); m.dist = sqrt( SQR(xm) + SQR(ym) ); m.xdist = sqrt( SQR( m.xmax ) + SQR( m.ymax ) ); m.azw = sqrt( fabs( SQR(xm)* y2m - 2.* xm * ym * xym + x2m*SQR(ym) ) ); m.miss = fabs( b / sqrt(1+a*a) ); m.alpha = DEG( asin( m.miss / m.dist ) ); */ m.length = sqrt( fabs(sx2 + sy2 + zz) / 2. ); m.width = sqrt( fabs(sx2 + sy2 - zz) / 2. ); m.dist = sqrt( SQR(xm) + SQR(ym) ); m.xdist = sqrt( SQR(m.xmax) + SQR(m.ymax) ); m.azw = sqrt( fabs( SQR(xm)*y2m - 2.*xm*ym*xym + x2m*SQR(ym) ) ) / m.dist; m.miss = sqrt( fabs( (SQR(xm)*zu + SQR(ym)*zv)/2. - (2.*sxy*xm*ym/zz) ) ); m.alpha = DEG( asin( m.miss/m.dist ) ); /* length = sqrt( fabs(sx2 + sy2 + zz) /2. ); width = sqrt( fabs(sx2 + sy2 - zz) / 2. ); dist = sqrt( SQR(xm) + SQR(ym) ); xdist = sqrt( SQR(m.xmax) + SQR(m.ymax) ); azw = sqrt( fabs( SQR(xm)*y2m - 2.*xm*ym*xym + x2m*SQR(ym) ) ); miss = sqrt( fabs( (SQR(xm)*zu + SQR(ym)*zv)/2. - (2.*sxy*xm*ym/zz) ) ); alpha = DEG( asin(miss/dist) ); */ //++++++++++++++++++++++++++++++++++++++++++++++++++ // asymetry //-------------------------------------------------- unitx = sqrt(0.5*zv); unity = SGN( sxy )*sqrt(0.5*zu); if ( m.xdist > 0.0 ) { m.phi = acos((unitx*m.xmax + unity*m.ymax )/m.xdist); sigmaax = sx3*CUB(cos(m.phi)) + 3.0*sx2y*SQR(cos(m.phi))*sin(m.phi) + 3.0*sxy2*cos(m.phi)*SQR(sin(m.phi)) + sy3*CUB(sin(m.phi)); sigmaax = pow(fabs(sigmaax),0.3333333)*SGN(sigmaax); ax = sigmaax*unitx; ay = sigmaax*unity; m.asymx = (ax*m.xmax + ay*m.ymax)/(m.xdist*m.length*cos(m.phi)); m.asymy = 0.0; } else { m.phi=-1000.0; m.asymx = -1000.0; m.asymy = -1000.0; } /* cout << "length "<< length << endl << "width "<< width << endl << "dist "<< dist << endl << "xdist "<< xdist << endl << "azw "<< azw << endl << "miss "<< miss << endl << "alpha "<< alpha << endl << flush; */ return &m; } //!@} // @T \newpage //!@subsection The function |islands()|. //!----------------------------------------------------------- // @name islands // // @desc implementation of the "islands" algorithm // // @var n Number of pixels // @var f Vector with the image (ph.e.s in pixels) // @var **pixneig Array with indices of neighbour pixels // @var *npixneig Vector with number of neighbours per pixel // @var cleanning TRUE: remove spurious islands // @var ipixcut Islands number cut // // @return Pointer to structure Islands_Info // // @date Mon Sep 14 15:22:44 MET DST 1998 //------------------------------------------------------------ // @function //!@{ Islands_Info * islands( int n, float *f, int **pixneig, int *npixneig, int cleanning, int ipixcut) { register int i; int j, k; int haschanged; is.numisl = 0; memcpy( is.fi, f, sizeof(float) * n ); // be aware: here we use the side effect of ++ // there are two possibilities of using the operator ++: // 1) a = ++i => is.first increments i, then evaluates expresion // 2) a = i++ => is.first evaluates expresion, then increments i // we INTENTIONALLY use the second form // algorithm to isolate/detect is.islands j=1; for (i=0; i0.0 ) { is.isl[i] = j; ++j; } else { is.isl[i] = 0; } haschanged = TRUE; while ( haschanged ) { haschanged = FALSE; for (i=0; i 0 ) for (j=0; (j-1); ++j) if ( (k=is.isl[pixneig[i][j]]) > 0 ) if ( is.isl[i] > is.isl[k] ) { is.isl[i] = is.isl[k]; haschanged=TRUE; } } // count is.islands for (i=0;i0) { is.islands[is.isl[i]]++; is.vislands[is.isl[i]] += is.fi[i]; } for (i=0,j=0,is.numisl=0; i0) { j++; //cout << '#' << j << ':' << is.islands[i] << " q=" << is.vislands[i] // << endl; if (is.islands[i] > ipixcut) is.numisl++; } } cout << j << '[' << is.numisl << "] is.islands\n" << flush; if ( cleanning ) { // cleanning image: pixcut = 3 (any is.island with <= 3 pixels is removed for (i=0;i forget that pixel if ( (fabs(dist_to_axis) > max_distance) && (SGN(dist_to_axis) != sign_of_semiplane) ) continue; // (B) // if distance to the axis if larger than pixel diameter, // AND // the semiplane is the GOOD one -> add this pixel if ( (fabs(dist_to_axis) > max_distance) && (SGN(dist_to_axis) == sign_of_semiplane) ) { // here the sum weight = image[i]; j = k+sign_of_semiplane; wsum[j] += weight * dist_to_axis * dist_to_axis; sum[j] += weight; continue; } // (C) // if we reach this point, that means that the center // of our pixel is too close to the axis, and we have // to feed it into the routine to check if the pixel // crosses the axis // ** NOTE ** NOTE ** NOTE ** NOTE ** NOTE ** NOTE ** NOTE // simplified algorithm // assume the pixels are circular, and takes // the fraction of the surface lying on the semiplane // ** NOTE ** NOTE ** NOTE ** NOTE ** NOTE ** NOTE ** NOTE // alpha alpha = 2*asin(sqrt(2*(radius-dist_to_axis)*radius - radius2) / radius); // here the sum // the fraction is the fraction of the area inside the semiplane weight = image[i] * ( (alpha * radius2 / 2.0) / (M_PI * radius2)); j = k+sign_of_semiplane; wsum[j] += weight * dist_to_axis * dist_to_axis; sum[j] += weight; } // foreach pixel pixels } // foreach semiplane } // foreach axis lw.length1 = (sum[0] > 0.) ? sqrt(wsum[0] / sum[0]) : -1; lw.width1 = (sum[1] > 0.) ? sqrt(wsum[1] / sum[1]) : -1; lw.length2 = (sum[2] > 0.) ? sqrt(wsum[2] / sum[2]) : -1; lw.width2 = (sum[3] > 0.) ? sqrt(wsum[3] / sum[3]) : -1; lw.length1 *= plateScale; lw.width1 *= plateScale; lw.length2 *= plateScale; lw.width2 *= plateScale; return &lw; } //!@} //!@subsection Auxiliary functions. //!----------------------------------------------------------- // @name crosspt // // @desc calculate cross point of segments AB and CD // // @var ax Coor. X of point A // @var ay Coor. Y of point A // @var bx Coor. X of point A // @var by Coor. Y of point A // @var cx Coor. X of point A // @var cy Coor. Y of point A // @var dx Coor. X of point A // @var dy Coor. Y of point A // @var *pcrossx Coor. X of cross point // @var *pcrossy Coor. Y of cross point // // @date Mon Mar 8 13:35:54 MET 1999 //------------------------------------------------------------ // @function //!@{ void crosspt( float ax, float ay, float bx, float by, float cx, float cy, float dx, float dy, float * pcrossx, float * pcrossy) { float w, r; // the points A and B, and C and D define two segments (AB and CD) // the coordinates of these points are // A(ax,ay), B(bx,by), C(cx,cy), D(dx,dy) w=(bx-ax)*(dy-cy)-(by-ay)*(dx-cx); r=(ay-cy)*(dx-cx)-(ax-cx)*(dy-cy); *pcrossx = ax + r*(bx-ax)/w; *pcrossy = ay + r*(by-ay)/w; } //!@} //=------------------------------------------------------------ //!@subsection Log of this file. //!@{ // // $Log: not supported by cvs2svn $ // Revision 1.2 1999/10/22 15:01:29 petry // version sent to H.K. and N.M. on Fri Oct 22 1999 // // Revision 1.1.1.1 1999/10/21 16:35:10 petry // first synthesised version // // Revision 1.1 1999/03/08 10:04:06 gonzalez // *** empty log message *** // // Revision 1.4 1999/03/02 09:56:14 gonzalez // *** empty log message *** // // Revision 1.5 1999/03/15 14:59:10 gonzalez // camera-1_1 // //!@} //=EOF