//Copyright (c) 2011 ashelly.myopenid.com under #include #include #include #define OMP_NUM_THREADS 4 #define Stringify(x) #x #define OMP_FOR(x) _Pragma(Stringify(omp parallel for x)) //Customize for your data Item type typedef int Item; #define ItemLess(a,b) ((a)<(b)) #define ItemMean(a,b) (((a)+(b))/2) typedef struct Mediator_t{ Item* data; // circular queue of values int* pos; // index into `heap` for each value int* heap; // max/median/min heap holding indexes into `data`. int N; // allocated size. int idx; // position in circular queue int ct; // count of items in queue } Mediator; /*--- Helper Functions ---*/ #define minCt(m) (((m)->ct-1)/2) //count of items in minheap #define maxCt(m) (((m)->ct)/2) //count of items in maxheap //returns 1 if heap[i] < heap[j] inline int mmless(Mediator* m, int i, int j){ return ItemLess(m->data[m->heap[i]],m->data[m->heap[j]]); } //swaps items i&j in heap, maintains indexes inline int mmexchange(Mediator* m, int i, int j){ int t = m->heap[i]; m->heap[i] = m->heap[j]; m->heap[j] = t; m->pos[m->heap[i]] = i; m->pos[m->heap[j]] = j; return 1; } //swaps items i&j if i1 && i < minCt(m) && mmless(m, i+1, i)) ++i; if(!mmCmpExch(m,i,i/2)) break; } } //maintains maxheap property for all items below i/2. (negative indexes) void maxSortDown(Mediator* m, int i){ for(; i >= -maxCt(m); i*=2){ if(i<-1 && i > -maxCt(m) && mmless(m, i, i-1)) --i; if(!mmCmpExch(m,i/2,i)) break; } } //maintains minheap property for all items above i, including median //returns true if median changed int minSortUp(Mediator* m, int i){ while (i > 0 && mmCmpExch(m, i, i/2)) i /= 2; return (i == 0); } //maintains maxheap property for all items above i, including median //returns true if median changed int maxSortUp(Mediator* m, int i){ while (i < 0 && mmCmpExch(m, i/2, i)) i /= 2; return (i == 0); } /*--- Public Interface ---*/ //creates new Mediator: to calculate `nItems` running median. //mallocs single block of memory, caller must free. Mediator* MediatorNew(int nItems){ int size = sizeof(Mediator) + nItems*(sizeof(Item)+sizeof(int)*2); Mediator* m = malloc(size); m->data = (Item*)(m + 1); m->pos = (int*) (m->data + nItems); m->heap = m->pos + nItems + (nItems / 2); //points to middle of storage. m->N = nItems; m->ct = m->idx = 0; while (nItems--){ //set up initial heap fill pattern: median,max,min,max,... m->pos[nItems] = ((nItems+1)/2) * ((nItems&1)? -1 : 1); m->heap[m->pos[nItems]] = nItems; } return m; } //Inserts item, maintains median in O(lg nItems) void MediatorInsert(Mediator* m, Item v){ int isNew=(m->ctN); int p = m->pos[m->idx]; Item old = m->data[m->idx]; m->data[m->idx]=v; m->idx = (m->idx+1) % m->N; m->ct+=isNew; if(p>0){ //new item is in minHeap if (!isNew && ItemLess(old,v)) minSortDown(m,p*2); else if (minSortUp(m,p)) maxSortDown(m,-1); }else if (p<0){ //new item is in maxheap if (!isNew && ItemLess(v,old)) maxSortDown(m,p*2); else if (maxSortUp(m,p)) minSortDown(m, 1); }else{ //new item is at median if (maxCt(m)) maxSortDown(m,-1); if (minCt(m)) minSortDown(m, 1); } } //returns median item (or average of 2 when item count is even) Item MediatorMedian(Mediator* m, Item *minval, Item *maxval){ Item v= m->data[m->heap[0]]; if ((m->ct&1) == 0) v = ItemMean(v,m->data[m->heap[-1]]); Item min, max; if(minval){ min = v; int i; for(i = -maxCt(m); i < 0; ++i){ int v = m->data[m->heap[i]]; if(v < min) min = v; } *minval = min; } if(maxval){ max = v; int i; for(i = 0; i <= minCt(m); ++i){ int v = m->data[m->heap[i]]; if(v > max) max = v; } *maxval = v; } return v; } /*--- Test Code ---*/ #include void PrintMaxHeap(Mediator* m){ int i; if(maxCt(m)) printf("Max: %3d",m->data[m->heap[-1]]); for (i=2;i<=maxCt(m);++i){ printf("|%3d ",m->data[m->heap[-i]]); if(++i<=maxCt(m)) printf("%3d",m->data[m->heap[-i]]); } printf("\n"); } void PrintMinHeap(Mediator* m){ int i; if(minCt(m)) printf("Min: %3d",m->data[m->heap[1]]); for (i=2;i<=minCt(m);++i){ printf("|%3d ",m->data[m->heap[i]]); if(++i<=minCt(m)) printf("%3d",m->data[m->heap[i]]); } printf("\n"); } void ShowTree(Mediator* m){ PrintMaxHeap(m); printf("Mid: %3d\n",m->data[m->heap[0]]); PrintMinHeap(m); printf("\n"); } double dtime(){ double t; struct timeval tv; gettimeofday(&tv, NULL); t = tv.tv_sec + ((double)tv.tv_usec)/1e6; return t; } #define SZ (4000) int main(int argc, char* argv[]) { int siz = SZ * SZ; int i, *v = malloc(siz * sizeof(int)), *o = malloc(siz*sizeof(int)), *small = malloc(siz * sizeof(int)), *large = malloc(siz * sizeof(int)); for (i=0; i < siz; ++i){ int s = (rand() & 0xf) + 0xf00, d = rand() & 0xffff; if(d > 0xefff) s+= 0xf000; else if(d < 0xfff) s = 0; v[i] = s; } double t0; void printmas(int *arr){ int x, y, fst = SZ/2-5, lst = SZ/2+4; for(y = fst; y < lst; ++y){ for(x = fst; x < lst; ++x) printf("%5d ", arr[x + y*SZ]); printf("\n"); } } void printels(int hsz){ int fulls = hsz*2+1; printf("median %dx%d for %dx%d image: %g seconds\n", fulls, fulls, SZ, SZ, dtime()-t0); printf("mid 10 values\n"); printf("ori:\n"); printmas(v); printf("\nmed:\n"); printmas(o); printf("\nmin:\n"); printmas(small); printf("\nmax:\n"); printmas(large); printf("\n\n"); } int hs; for(hs = 1; hs < 5; ++hs){ t0 = dtime(); int blksz = hs*2+1, fullsz = blksz * blksz; OMP_FOR(shared(o, v, small, large)) for(int x = hs; x < SZ - hs; ++x){ int xx, yy, xm = x+hs+1, y; Mediator* m = MediatorNew(fullsz); // initial fill for(yy = 0; yy < blksz - 1; ++yy) for(xx = x-hs; xx < xm; ++xx) MediatorInsert(m, v[xx+yy*SZ]); for(y = hs; y < SZ - hs; ++y){ for(xx = x-hs; xx < xm; ++xx) MediatorInsert(m, v[xx+(y+hs)*SZ]); int curpos = x+y*SZ; o[curpos] = MediatorMedian(m, &small[curpos], &large[curpos]); //ShowTree(m); //if(y == 2) return 0; } free(m); } printels(hs); } free(o); free(v); free(small); free(large); }