/*------------------------------------------------------------------------- L o c a l M a x i m u m This is a module for searching a local maximum in a 2D histogram as collected at TRICS. copyright: see copyright.h Mark Koennecke, November 2001 -------------------------------------------------------------------------*/ #include #include #include #include #include "fortify.h" #include "sics.h" #include "lomax.h" #include "lomax.i" #include "HistMem.h" #define WINDOW 0 #define THRESHOLD 1 #define STEEPNESS 2 #define COGWINDOW 3 #define COGCONTOUR 4 extern float nintf(float f); /*-------------------------------------------------------------------*/ static int testBoundaries(int xsize, int ysize, int window, int i, int j) { int half; /* if the window touches the data boundary the result is probably not very useful. Discarding these cases early on also protects us against data array overrun problems. */ half = window/2; if( i - half < 0 || i + half > xsize) return 0; if( j - half < 0 || j + half > ysize) return 0; return 1; } /*-------------------------------------------------------------------*/ static int testSteepness(int *iData, int xsize, int ysize, int i, int j, int window, int steepness) { int testValue, x, y, half; int *iPtr; testValue = iData[j * xsize + i] - steepness; half = window/2; /* test upper row */ iPtr = iData + (j - half) * xsize + i - half; for(x = 0; x < window; x++) { if(iPtr[x] > testValue) return 0; } /* test lower row */ iPtr = iData + (j + half) * xsize + i - half; for(x = 0; x < window; x++) { if(iPtr[x] > testValue) return 0; } /* test columns */ for(y = j - half; y < j + half; y++) { /* left */ if(iData[y*xsize + i - half] > testValue) return 0; /* right */ if(iData[y*xsize + i + half] > testValue) return 0; } return 1; } /*--------------------------------------------------------------------*/ static int testMaximum(int *iData, int xsize, int ysize, int i, int j, int window) { int testValue, x, y, half; int *iPtr; int equalCount = 0; testValue = iData[j * xsize + i]; half = window/2; for(y = j - half; y < j + half; y++) { iPtr = iData + y * xsize + i - half; for(x = 0; x < window; x++) { if(iPtr[x] > testValue) return 0; if(iPtr[x] == testValue) equalCount++; } } /* if(equalCount > 3) { return 0; } */ return 1; } /*--------------------------------------------------------------------*/ int testLocalMaximum(int *iData, int xsize, int ysize, int i, int j, int window, int steepness, int threshold, int *intensity) { if(!testBoundaries(xsize,ysize,window,i,j)) return 0; if(!testMaximum(iData,xsize,ysize,i,j,window)) return 0; if(iData[j * xsize + i] < threshold) return 0; if(!testSteepness(iData,xsize,ysize,i,j,window, steepness)) return 0; *intensity = iData[j * xsize + i]; return 1; } /*-------------------------------------------------------------------*/ int calculateCOG(int *iData, int xsize, int ysize, int *i, int *j, int *intensity,int *nCount, int cogWindow, float contour) { int x, xLow, xMax, y, yLow, yMax; int threshold; float cogTotal, cogX, cogY; int *iPtr; if(!testBoundaries(xsize,ysize,cogWindow,*i,*j)) return 0; /* preparations */ xLow = *i - cogWindow/2; if(xLow < 0) xLow = 0; xMax = *i + cogWindow/2; if(xLow >= xsize) xMax = xsize-1; yLow = *j - cogWindow/2; if(yLow < 0) yLow = 0; yMax = *j + cogWindow/2; if(yLow >= ysize) yMax = ysize-1; threshold = (int)(float)iData[*j * xsize + *i] * contour; /* build the sums */ *nCount = 0; cogTotal = cogY = cogX = .0; for(y = yLow; y < yMax; y++) { iPtr = iData + y *xsize; for(x = xLow; x < xMax; x++) { if(iPtr[x] > threshold) { *nCount++; cogTotal += iPtr[x]; cogY += y * iPtr[x]; cogX += x * iPtr[x]; } } } if(cogTotal <= .0) { return 0; } *i = (int)nintf(cogX/cogTotal); *j = (int)nintf(cogY/cogTotal); *intensity = (int)cogTotal; return 1; } /*-------------------------------------------------------------------*/ void calculateStatistics(int *iData, int xsize, int ysize, float *average, float *maximum) { int i, iLength; int max = -999999999; long sum = 0; iLength = xsize*ysize; for(i = 0; i < iLength; i++) { sum += iData[i]; if(iData[i] > max) max = iData[i]; } *average = (float)sum/(float)iLength; *maximum = (float)max; } /*-------------------------------------------------------------------*/ int wellFormed(int *iData, int xsize, int ysize, int i, int j, int window, float contour, int maxBad) { int testValue, x, y, half; int *iPtr; int badCount = 0; testValue = (int)((float)iData[j * xsize + i]*contour); half = window/2; /* test upper row */ iPtr = iData + (j - half) * xsize + i - half; for(x = 0; x < window; x++) { if(iPtr[x] > testValue) badCount++; } /* test lower row */ iPtr = iData + (j + half) * xsize + i - half; for(x = 0; x < window; x++) { if(iPtr[x] > testValue) badCount++; } /* test columns */ for(y = j - half; y < j + half; y++) { /* left */ if(iData[y*xsize + i - half] > testValue) badCount++; /* right */ if(iData[y*xsize + i + half] > testValue) badCount++; } if(badCount > maxBad) { return 0; } return 1; } /*-------------------------------------------------------------------*/ static int checkHM(pHistMem *pHM, SicsInterp *pSics, SConnection *pCon, char *name, int *iDim) { CommandList *pCom = NULL; char pBueffel[256]; int nDim; pCom = FindCommand(pSics, name); if(!pCom) { sprintf(pBueffel,"ERROR: histogram memory %s not found", name); SCWrite(pCon,pBueffel,eError); return 0; } if(!pCom->pData) { sprintf(pBueffel,"ERROR: histogram memory %s not found", name); SCWrite(pCon,pBueffel,eError); return 0; } *pHM = (pHistMem)pCom->pData; if(!iHasType(*pHM, "HistMem")) { sprintf(pBueffel,"ERROR: %s is no histogram memory!", name); SCWrite(pCon,pBueffel,eError); return 0; } /* we now know that we have a histogram memory, now check Sizes */ GetHistDim(*pHM,iDim,&nDim); if(nDim < 2) { sprintf(pBueffel,"ERROR: %s is not 2 dimensional!", name); SCWrite(pCon,pBueffel,eError); return 0; } return 1; } /*--------------------------------------------------------------------*/ int LoMaxAction(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) { pLoMax self = NULL; char pBueffel[256], pNum[20]; int iRet, i, j, intensity, count, badMax; int iDim[10], nDim; pHistMem pHM = NULL; CommandList *pCom = NULL; Tcl_DString result; int window; int *iData; double dVal; ObPar *ob = NULL; float average, maximum; self = (pLoMax)pData; assert(pCon); assert(pSics); assert(self); /* we need arguments */ if(argc < 2) { sprintf(pBueffel,"ERROR: insufficient number of arguments to %s", argv[0]); SCWrite(pCon,pBueffel,eError); return 0; } /* interpret arguments */ strtolower(argv[1]); if(strcmp(argv[1],"search") == 0) { if(argc < 3) { sprintf(pBueffel,"ERROR: insufficient number of arguments to %s.search", argv[0]); SCWrite(pCon,pBueffel,eError); return 0; } if(!checkHM(&pHM, pSics,pCon, argv[2],iDim)) { return 0; } Tcl_DStringInit(&result); iData = GetHistogramPointer(pHM,pCon); window = (int)ObVal(self->pParam,WINDOW); count = 0; for(i = 0 + window/2; i < iDim[0] - window/2; i++) { for(j = 0 + window/2; j < iDim[1] - window/2; j++) { if(testLocalMaximum(iData,iDim[0], iDim[1], i,j, (int)ObVal(self->pParam,WINDOW), (int)ObVal(self->pParam,STEEPNESS), (int)ObVal(self->pParam,THRESHOLD), &intensity)) { if(count != 0) { Tcl_DStringAppend(&result,"@",strlen("@")); } sprintf(pNum,"%d ", i); Tcl_DStringAppend(&result,pNum,strlen(pNum)); sprintf(pNum,"%d ", j); Tcl_DStringAppend(&result,pNum,strlen(pNum)); sprintf(pNum,"%d", intensity); Tcl_DStringAppend(&result,pNum,strlen(pNum)); count++; } } } SCWrite(pCon,Tcl_DStringValue(&result),eValue); Tcl_DStringFree(&result); return 1; } else if(strcmp(argv[1],"cog") == 0) /* COG calculation */ { if(argc < 5) { sprintf(pBueffel,"ERROR: insufficient number of arguments to %s.cog", argv[0]); SCWrite(pCon,pBueffel,eError); return 0; } if(!checkHM(&pHM, pSics,pCon, argv[2],iDim)) { return 0; } if(Tcl_GetInt(pSics->pTcl,argv[3],&i)!= TCL_OK) { sprintf(pBueffel,"ERROR: expected number, got %s",argv[2]); SCWrite(pCon,pBueffel,eError); return 0; } if(Tcl_GetInt(pSics->pTcl,argv[4],&j)!= TCL_OK) { sprintf(pBueffel,"ERROR: expected number, got %s",argv[2]); SCWrite(pCon,pBueffel,eError); return 0; } Tcl_DStringInit(&result); iData = GetHistogramPointer(pHM,pCon); window = (int)ObVal(self->pParam,COGWINDOW); iRet = calculateCOG(iData,iDim[0], iDim[1], &i, &j, &intensity,&count, window, ObVal(self->pParam,COGCONTOUR)); if(!iRet) { SCWrite(pCon,"ERROR: no intensity in data",eError); return 0; } sprintf(pNum,"%d ", i); Tcl_DStringAppend(&result,pNum,strlen(pNum)); sprintf(pNum,"%d ", j); Tcl_DStringAppend(&result,pNum,strlen(pNum)); sprintf(pNum,"%d ", intensity); Tcl_DStringAppend(&result,pNum,strlen(pNum)); sprintf(pNum,"%d ", count); Tcl_DStringAppend(&result,pNum,strlen(pNum)); SCWrite(pCon,Tcl_DStringValue(&result),eValue); Tcl_DStringFree(&result); return 1; } else if(strcmp(argv[1],"wellformed") == 0) /* test for wellformedness */ { if(argc < 6) { sprintf(pBueffel, "ERROR: insufficient number of arguments to %s.wellformed", argv[0]); SCWrite(pCon,pBueffel,eError); return 0; } if(!checkHM(&pHM, pSics,pCon, argv[2],iDim)) { return 0; } if(Tcl_GetInt(pSics->pTcl,argv[3],&i)!= TCL_OK) { sprintf(pBueffel,"ERROR: expected number, got %s",argv[2]); SCWrite(pCon,pBueffel,eError); return 0; } if(Tcl_GetInt(pSics->pTcl,argv[4],&j)!= TCL_OK) { sprintf(pBueffel,"ERROR: expected number, got %s",argv[2]); SCWrite(pCon,pBueffel,eError); return 0; } if(Tcl_GetInt(pSics->pTcl,argv[5],&badMax)!= TCL_OK) { sprintf(pBueffel,"ERROR: expected number, got %s",argv[2]); SCWrite(pCon,pBueffel,eError); return 0; } iData = GetHistogramPointer(pHM,pCon); window = (int)ObVal(self->pParam,COGWINDOW); iRet = wellFormed(iData,iDim[0], iDim[1], i, j, window, ObVal(self->pParam,COGCONTOUR), badMax); sprintf(pBueffel,"%5d", iRet); SCWrite(pCon,pBueffel,eValue); return 1; } else if(strcmp(argv[1],"stat") == 0) { if(argc < 3) { sprintf(pBueffel,"ERROR: insufficient number of arguments to %s.search", argv[0]); SCWrite(pCon,pBueffel,eError); return 0; } if(!checkHM(&pHM, pSics,pCon, argv[2],iDim)) { return 0; } iData = GetHistogramPointer(pHM,pCon); calculateStatistics(iData,iDim[0],iDim[1],&average,&maximum); sprintf(pBueffel," %f %f", average, maximum); SCWrite(pCon,pBueffel,eValue); return 1; } else { /* we are handling one of the parameter commands */ if(argc > 2) /* set case */ { if(Tcl_GetDouble(pSics->pTcl,argv[2],&dVal) != TCL_OK) { sprintf(pBueffel,"ERROR: expected number, got %s",argv[2]); SCWrite(pCon,pBueffel,eError); return 0; } return ObParSet(self->pParam,argv[0],argv[1],(float)dVal,pCon); } else /* read case */ { ob = ObParFind(self->pParam,argv[1]); if(!ob) { sprintf(pBueffel,"ERROR: parameter %s not found or wrong command", argv[1]); SCWrite(pCon,pBueffel,eError); return 0; } sprintf(pBueffel,"%s.%s = %f",argv[0],argv[1],ob->fVal); SCWrite(pCon,pBueffel,eError); return 1; } } /* not reached */ assert(0); return 0; } /*-------------------------------------------------------------------*/ static void KillLoMax(void *pData) { pLoMax self = (pLoMax)pData; if(!self) return; if(self->pDes) DeleteDescriptor(self->pDes); if(self->pParam) ObParDelete(self->pParam); free(self); } /*-------------------------------------------------------------------*/ int LoMaxFactory(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) { pLoMax pNew = NULL; if(argc < 2) { SCWrite(pCon,"ERROR: Insufficient number of arguments to LoMaxfactory", eError); return 0; } pNew = (pLoMax)malloc(sizeof(LoMax)); if(!pNew) { SCWrite(pCon,"ERROR: out of memory creating local maximum searcher", eError); return 0; } memset(pNew,0,sizeof(LoMax)); /* create Descriptor */ pNew->pDes = CreateDescriptor("Local Maximum Detector"); if(!pNew->pDes) { KillLoMax(pNew); SCWrite(pCon,"ERROR: out of memory creating local maximum searcher", eError); return 0; } /* create and install parameters */ pNew->pParam = ObParCreate(5); if(!pNew->pParam) { KillLoMax(pNew); SCWrite(pCon,"ERROR: out of memory creating local maximum searcher", eError); return 0; } ObParInit(pNew->pParam,WINDOW,"window",10,usUser); ObParInit(pNew->pParam,THRESHOLD,"threshold",30,usUser); ObParInit(pNew->pParam,STEEPNESS,"steepness",5,usUser); ObParInit(pNew->pParam,COGWINDOW,"cogwindow",50,usUser); ObParInit(pNew->pParam,COGCONTOUR,"cogcontour",.2,usUser); return AddCommand(pSics, argv[1], LoMaxAction, KillLoMax, pNew); }