void colorNorm (COLOR c) /* Normalise colour channels to average of 1 */ { const float avg = colorAvg(c); if (!avg) return; c [0] /= avg; c [1] /= avg; c [2] /= avg; }
void distribPhotonContrib (PhotonMap* pm, unsigned numProc) { EmissionMap emap; char errmsg2 [128], shmFname [PMAP_TMPFNLEN]; unsigned srcIdx, proc; int shmFile, stat, pid; double *srcFlux, /* Emitted flux per light source */ srcDistribTarget; /* Target photon count per source */ PhotonContribCnt *photonCnt; /* Photon emission counter array */ unsigned photonCntSize = sizeof(PhotonContribCnt) * PHOTONCNT_NUMEMIT(nsources); FILE **primaryHeap = NULL; char **primaryHeapFname = NULL; PhotonPrimaryIdx *primaryOfs = NULL; if (!pm) error(USER, "no photon map defined in distribPhotonContrib"); if (!nsources) error(USER, "no light sources in distribPhotonContrib"); if (nsources > MAXMODLIST) error(USER, "too many light sources in distribPhotonContrib"); /* Allocate photon flux per light source; this differs for every * source as all sources contribute the same number of distributed * photons (srcDistribTarget), hence the number of photons emitted per * source does not correlate with its emitted flux. The resulting flux * per photon is therefore adjusted individually for each source. */ if (!(srcFlux = calloc(nsources, sizeof(double)))) error(SYSTEM, "can't allocate source flux in distribPhotonContrib"); /* =================================================================== * INITIALISATION - Set up emission and scattering funcs * =================================================================== */ emap.samples = NULL; emap.src = NULL; emap.maxPartitions = MAXSPART; emap.partitions = (unsigned char*)malloc(emap.maxPartitions >> 1); if (!emap.partitions) error(USER, "can't allocate source partitions in distribPhotonContrib"); /* Initialise contrib photon map */ initPhotonMap(pm, PMAP_TYPE_CONTRIB); initPhotonHeap(pm); initPhotonEmissionFuncs(); initPhotonScatterFuncs(); /* Per-subprocess / per-source target counts */ pm -> distribTarget /= numProc; srcDistribTarget = nsources ? (double)pm -> distribTarget / nsources : 0; if (!pm -> distribTarget) error(INTERNAL, "no photons to distribute in distribPhotonContrib"); /* Get photon ports from modifier list */ getPhotonPorts(photonPortList); /* Get photon sensor modifiers */ getPhotonSensors(photonSensorList); #if NIX /* Set up shared mem for photon counters (zeroed by ftruncate) */ strcpy(shmFname, PMAP_TMPFNAME); shmFile = mkstemp(shmFname); if (shmFile < 0 || ftruncate(shmFile, photonCntSize) < 0) error(SYSTEM, "failed shared mem init in distribPhotonContrib"); photonCnt = mmap(NULL, photonCntSize, PROT_READ | PROT_WRITE, MAP_SHARED, shmFile, 0); if (photonCnt == MAP_FAILED) error(SYSTEM, "failed shared mem mapping in distribPhotonContrib"); #else /* Allocate photon counters statically on Windoze */ if (!(photonCnt = malloc(photonCntSize))) error(SYSTEM, "failed trivial malloc in distribPhotonContrib"); for (srcIdx = 0; srcIdx < PHOTONCNT_NUMEMIT(nsources); srcIdx++) photonCnt [srcIdx] = 0; #endif /* NIX */ if (verbose) { sprintf(errmsg, "\nIntegrating flux from %d sources", nsources); if (photonPorts) { sprintf(errmsg2, " via %d ports", numPhotonPorts); strcat(errmsg, errmsg2); } strcat(errmsg, "\n"); eputs(errmsg); } /* ============================================================= * FLUX INTEGRATION - Get total flux emitted from sources/ports * ============================================================= */ for (srcIdx = 0; srcIdx < nsources; srcIdx++) { unsigned portCnt = 0; srcFlux [srcIdx] = 0; emap.src = source + srcIdx; do { /* Need at least one iteration if no ports! */ emap.port = emap.src -> sflags & SDISTANT ? photonPorts + portCnt : NULL; photonPartition [emap.src -> so -> otype] (&emap); if (verbose) { sprintf(errmsg, "\tIntegrating flux from source %s ", source [srcIdx].so -> oname); if (emap.port) { sprintf(errmsg2, "via port %s ", photonPorts [portCnt].so -> oname); strcat(errmsg, errmsg2); } sprintf(errmsg2, "(%lu partitions)\n", emap.numPartitions); strcat(errmsg, errmsg2); eputs(errmsg); #if NIX fflush(stderr); #endif } for (emap.partitionCnt = 0; emap.partitionCnt < emap.numPartitions; emap.partitionCnt++) { initPhotonEmission(&emap, pdfSamples); srcFlux [srcIdx] += colorAvg(emap.partFlux); } portCnt++; } while (portCnt < numPhotonPorts); if (srcFlux [srcIdx] < FTINY) { sprintf(errmsg, "source %s has zero emission", source [srcIdx].so -> oname); error(WARNING, errmsg); } } /* Allocate & init per-subprocess primary heap files */ primaryHeap = calloc(numProc, sizeof(FILE*)); primaryHeapFname = calloc(numProc, sizeof(char*)); primaryOfs = calloc(numProc, sizeof(PhotonPrimaryIdx)); if (!primaryHeap || !primaryHeapFname || !primaryOfs) error(SYSTEM, "failed primary heap allocation in " "distribPhotonContrib"); for (proc = 0; proc < numProc; proc++) { primaryHeapFname [proc] = malloc(PMAP_TMPFNLEN); if (!primaryHeapFname [proc]) error(SYSTEM, "failed primary heap file allocation in " "distribPhotonContrib"); mktemp(strcpy(primaryHeapFname [proc], PMAP_TMPFNAME)); if (!(primaryHeap [proc] = fopen(primaryHeapFname [proc], "w+b"))) error(SYSTEM, "failed opening primary heap file in " "distribPhotonContrib"); } /* Record start time for progress reports */ repStartTime = time(NULL); if (verbose) { sprintf(errmsg, "\nPhoton distribution @ %d procs\n", numProc); eputs(errmsg); } /* MAIN LOOP */ for (proc = 0; proc < numProc; proc++) { #if NIX if (!(pid = fork())) { /* SUBPROCESS ENTERS HERE; opened and mmapped files inherited */ #else if (1) { /* No subprocess under Windoze */ #endif /* Local photon counters for this subprocess */ unsigned long lastNumPhotons = 0, localNumEmitted = 0; double photonFluxSum = 0; /* Accum. photon flux */ /* Seed RNGs from PID for decorellated photon distribution */ pmapSeed(randSeed + proc, partState); pmapSeed(randSeed + (proc + 1) % numProc, emitState); pmapSeed(randSeed + (proc + 2) % numProc, cntState); pmapSeed(randSeed + (proc + 3) % numProc, mediumState); pmapSeed(randSeed + (proc + 4) % numProc, scatterState); pmapSeed(randSeed + (proc + 5) % numProc, rouletteState); #ifdef PMAP_SIGUSR double partNumEmit; unsigned long partEmitCnt; double srcPhotonFlux, avgPhotonFlux; unsigned portCnt, passCnt, prePassCnt; float srcPreDistrib; double srcNumEmit; /* # to emit from source */ unsigned long srcNumDistrib; /* # stored */ void sigUsrDiags() /* Loop diags via SIGUSR1 */ { sprintf(errmsg, "********************* Proc %d Diags *********************\n" "srcIdx = %d (%s)\nportCnt = %d (%s)\npassCnt = %d\n" "srcFlux = %f\nsrcPhotonFlux = %f\navgPhotonFlux = %f\n" "partNumEmit = %f\npartEmitCnt = %lu\n\n", proc, srcIdx, findmaterial(source [srcIdx].so) -> oname, portCnt, photonPorts [portCnt].so -> oname, passCnt, srcFlux [srcIdx], srcPhotonFlux, avgPhotonFlux, partNumEmit, partEmitCnt); eputs(errmsg); fflush(stderr); } #endif #ifdef PMAP_SIGUSR signal(SIGUSR1, sigUsrDiags); #endif #ifdef DEBUG_PMAP /* Output child process PID after random delay to prevent corrupted * console output due to race condition */ usleep(1e6 * pmapRandom(rouletteState)); fprintf(stderr, "Proc %d: PID = %d " "(waiting 10 sec to attach debugger...)\n", proc, getpid()); /* Allow time for debugger to attach to child process */ sleep(10); #endif /* ============================================================= * 2-PASS PHOTON DISTRIBUTION * Pass 1 (pre): emit fraction of target photon count * Pass 2 (main): based on outcome of pass 1, estimate remaining * number of photons to emit to approximate target * count * ============================================================= */ for (srcIdx = 0; srcIdx < nsources; srcIdx++) { #ifndef PMAP_SIGUSR unsigned portCnt, passCnt = 0, prePassCnt = 0; float srcPreDistrib = preDistrib; double srcNumEmit = 0; /* # to emit from source */ unsigned long srcNumDistrib = pm -> numPhotons; /* # stored */ #else passCnt = prePassCnt = 0; srcPreDistrib = preDistrib; srcNumEmit = 0; /* # to emit from source */ srcNumDistrib = pm -> numPhotons; /* # stored */ #endif if (srcFlux [srcIdx] < FTINY) continue; while (passCnt < 2) { if (!passCnt) { /* INIT PASS 1 */ if (++prePassCnt > maxPreDistrib) { /* Warn if no photons contributed after sufficient * iterations; only output from subprocess 0 to reduce * console clutter */ if (!proc) { sprintf(errmsg, "source %s: too many prepasses, skipped", source [srcIdx].so -> oname); error(WARNING, errmsg); } break; } /* Num to emit is fraction of target count */ srcNumEmit = srcPreDistrib * srcDistribTarget; } else { /* INIT PASS 2 */ #ifndef PMAP_SIGUSR double srcPhotonFlux, avgPhotonFlux; #endif /* Based on the outcome of the predistribution we can now * figure out how many more photons we have to emit from * the current source to meet the target count, * srcDistribTarget. This value is clamped to 0 in case * the target has already been exceeded in pass 1. * srcNumEmit and srcNumDistrib is the number of photons * emitted and distributed (stored) from the current * source in pass 1, respectively. */ srcNumDistrib = pm -> numPhotons - srcNumDistrib; srcNumEmit *= srcNumDistrib ? max(srcDistribTarget/srcNumDistrib, 1) - 1 : 0; if (!srcNumEmit) /* No photons left to distribute in main pass */ break; srcPhotonFlux = srcFlux [srcIdx] / srcNumEmit; avgPhotonFlux = photonFluxSum / (srcIdx + 1); if (avgPhotonFlux > FTINY && srcPhotonFlux / avgPhotonFlux < FTINY) { /* Skip source if its photon flux is grossly below the * running average, indicating negligible contributions * at the expense of excessive distribution time; only * output from subproc 0 to reduce console clutter */ if (!proc) { sprintf(errmsg, "source %s: itsy bitsy photon flux, skipped", source [srcIdx].so -> oname); error(WARNING, errmsg); } srcNumEmit = 0; /* Or just break??? */ } /* Update sum of photon flux per light source */ photonFluxSum += srcPhotonFlux; } portCnt = 0; do { /* Need at least one iteration if no ports! */ emap.src = source + srcIdx; emap.port = emap.src -> sflags & SDISTANT ? photonPorts + portCnt : NULL; photonPartition [emap.src -> so -> otype] (&emap); if (verbose && !proc) { /* Output from subproc 0 only to avoid race condition * on console I/O */ if (!passCnt) sprintf(errmsg, "\tPREPASS %d on source %s ", prePassCnt, source [srcIdx].so -> oname); else sprintf(errmsg, "\tMAIN PASS on source %s ", source [srcIdx].so -> oname); if (emap.port) { sprintf(errmsg2, "via port %s ", photonPorts [portCnt].so -> oname); strcat(errmsg, errmsg2); } sprintf(errmsg2, "(%lu partitions)\n", emap.numPartitions); strcat(errmsg, errmsg2); eputs(errmsg); #if NIX fflush(stderr); #endif } for (emap.partitionCnt = 0; emap.partitionCnt < emap.numPartitions; emap.partitionCnt++) { #ifndef PMAP_SIGUSR double partNumEmit; unsigned long partEmitCnt; #endif /* Get photon origin within current source partishunn * and build emission map */ photonOrigin [emap.src -> so -> otype] (&emap); initPhotonEmission(&emap, pdfSamples); /* Number of photons to emit from ziss partishunn; * scale according to its normalised contribushunn to * the emitted source flux */ partNumEmit = srcNumEmit * colorAvg(emap.partFlux) / srcFlux [srcIdx]; partEmitCnt = (unsigned long)partNumEmit; /* Probabilistically account for fractional photons */ if (pmapRandom(cntState) < partNumEmit - partEmitCnt) partEmitCnt++; /* Update local and shared global emission counter */ photonCnt [PHOTONCNT_NUMEMIT(srcIdx)] += partEmitCnt; localNumEmitted += partEmitCnt; /* Integer counter avoids FP rounding errors during * iteration */ while (partEmitCnt--) { RAY photonRay; /* Emit photon according to PDF (if any), allocate * associated primary ray, and trace through scene * until absorbed/leaked; emitPhoton() sets the * emitting light source index in photonRay */ emitPhoton(&emap, &photonRay); #if 1 if (emap.port) /* !!! PHOTON PORT REJECTION SAMPLING HACK: set * !!! photon port as fake hit object for * !!! primary ray to check for intersection in * !!! tracePhoton() */ photonRay.ro = emap.port -> so; #endif newPhotonPrimary(pm, &photonRay, primaryHeap[proc]); /* Set subprocess index in photonRay for post- * distrib primary index linearisation; this is * propagated with the primary index in photonRay * and set for photon hits by newPhoton() */ PMAP_SETRAYPROC(&photonRay, proc); tracePhoton(&photonRay); } /* Update shared global photon count */ photonCnt [PHOTONCNT_NUMPHOT] += pm -> numPhotons - lastNumPhotons; lastNumPhotons = pm -> numPhotons; #if !NIX /* Synchronous progress report on Windoze */ if (!proc && photonRepTime > 0 && time(NULL) >= repLastTime + photonRepTime) { unsigned s; repComplete = pm -> distribTarget * numProc; repProgress = photonCnt [PHOTONCNT_NUMPHOT]; for (repEmitted = 0, s = 0; s < nsources; s++) repEmitted += photonCnt [PHOTONCNT_NUMEMIT(s)]; pmapDistribReport(); } #endif } portCnt++; } while (portCnt < numPhotonPorts); if (pm -> numPhotons == srcNumDistrib) { /* Double predistrib factor in case no photons were stored * for this source and redo pass 1 */ srcPreDistrib *= 2; } else { /* Now do pass 2 */ passCnt++; } } } /* Flush heap buffa one final time to prevent data corruption */ flushPhotonHeap(pm); /* Flush final photon primary to primary heap file */ newPhotonPrimary(pm, NULL, primaryHeap [proc]); /* Heap files closed automatically on exit fclose(pm -> heap); fclose(primaryHeap [proc]); */ #ifdef DEBUG_PMAP sprintf(errmsg, "Proc %d total %ld photons\n", proc, pm -> numPhotons); eputs(errmsg); fflush(stderr); #endif #ifdef PMAP_SIGUSR signal(SIGUSR1, SIG_DFL); #endif #if NIX /* Terminate subprocess */ exit(0); #endif } else if (pid < 0)
// ###################################################################### Image<PixRGB<byte> > SuperPixelRoadSegmenter::getSuperPixel(Image<PixRGB<byte> > img) { if(!img.initialized()) return Image<PixRGB<byte> >(320,240,ZEROS); // default parameters for the Superpixel segmentation float sigma = .5; uint k = 400; uint minSize = 100; int num_ccs; std::vector<std::vector<Point2D<int> > > groups; Image<int> groupImage = SuperPixelSegment(img,sigma, k, minSize, num_ccs, &groups); Image<PixRGB<byte> > sp_img = SuperPixelDebugImage(groups,img); Image<int> sp_size_img = SuperPixelRegionSizeImage(groups,groupImage); itsRawSuperPixelImg = sp_img; //debugWin(itsRawSuperPixelImg,"itsRawSuperPixelImg"); int w = sp_img.getWidth(); int h = sp_img.getHeight(); // Look for road color, // let's assume it always show up in the middle bottom (h-5,w/2 +- 10) std::vector<PixRGB<byte> > color_map; std::vector<int> color_size_map; std::vector<int> color_map_count; // Pick all road pixel candidates int windowL = -SEARCH_WINDOW_W/2; //-10 int windowR = SEARCH_WINDOW_W/2; // 10 int windowB = SEARCH_WINDOW_BOTTOM; int windowT = SEARCH_WINDOW_H; for(int i = windowL; i<= windowR; i++) { //We are search bottom area as most likely road pixel candidates for(int k = windowB; k <=windowT; k++) { //set our grow window float to the middle of road int middlePoint; if(itsMiddlePoint[k-1]!=0 && itsUseFloatWindow) { middlePoint = itsMiddlePoint[k-1]/4;//1/4 size image //LINFO("Float Window %d midpoint %d",middlePoint,k-1); } else { middlePoint = w/2; //LINFO("Fixed Window %d midpoint",middlePoint); } if(sp_img.coordsOk(middlePoint+i,h-k)) { PixRGB<byte> tmp_color = sp_img.getVal(middlePoint + i,h-k); int regionSize = sp_size_img.getVal(middlePoint+i,h-k); bool notfound = true; // Search color for(int j = 0; j < (int)color_map.size() && notfound ; j++) { if(color_map[j] == tmp_color) { notfound = false; color_map_count[j]++; } } if(notfound) { color_map.push_back(tmp_color); color_map_count.push_back(0); color_size_map.push_back(regionSize); } } } } if(color_map.size() > 1) { //if we found more than one color //Some Option Here: //1.Choose max count color //2.Pick min color difference from previous avg road color pixel //if road color is not available, we pick max pixel color if(itsRoadColor == PixRGB<byte>(0,0,0)) { int max = color_map_count[0]; int max_index = 0; for(int i = 1; i < (int)color_map_count.size() ; i++) { if(max < color_map_count[i]) { max = color_map_count[i]; max_index = i; } } itsRoadColor = color_map[max_index]; //LINFO("Max count color have count %d",max); } else { //Pick min color difference color int min_index = 0; float min = colorDiff(itsRoadColor,color_map[0]);// for(int i = 1; i < (int)color_map_count.size() ; i++) { float cd = colorDiff(itsRoadColor,color_map[i]); int rs = color_size_map[i];//region size //LINFO("Road Region Size %d",rs); if(cd < min && rs > 100) { min = cd; min_index = i; } } itsRoadColorDiff = colorDiff(itsRoadColor,color_map[min_index]); //to prevent jump too much if(itsRoadColorDiff < 50.0) { itsRoadColor = color_map[min_index]; } else { //keep avg color so it will help to solve kid-napping problem PixRGB<byte> avgColor = colorAvg(itsRoadColor,color_map[0],0.8);//first color will have 80% weight itsRoadColor = avgColor; //LINFO("COLOR DIFF1 %f",itsRoadColorDiff); } } } else { //if only one region itsRoadColorDiff = colorDiff(itsRoadColor,color_map[0]); itsRoadColorDiffSub = colorDiffSub(itsRoadColor,color_map[0]); if((itsRoadColorDiff < 50.0 && color_map[0].green() > 150)||itsRoadColor == PixRGB<byte>(0,0,0)) { //for outdoor concrete road //if((itsRoadColorDiff < 90.0 && color_map[0].green()<150)||itsRoadColor == PixRGB<byte>(0,0,0)){//indoor //if((itsRoadColorDiff < 90.0)||itsRoadColor == PixRGB<byte>(0,0,0)){//general, high fail rate itsRoadColor = color_map[0]; //itsUseFloatWindow = false;//FIXXXXXX } else { PixRGB<byte> avgColor = colorAvg(itsRoadColor,color_map[0],0.8);//80% on first one itsRoadColor = avgColor; itsUseFloatWindow = true; //LINFO("COLOR DIFF2 %f,USE float window",itsRoadColorDiff); } //LINFO("Only one color (%d,%d,%d)",itsRoadColor.red(),itsRoadColor.green(),itsRoadColor.blue()); } // use iterator!!!!!! Image<PixRGB<byte> > output(w,h,ZEROS); //image with full red road region Image<PixRGB<byte> > hybrid(w,h,ZEROS); //image with red grid dot road region itsRoadIndexMap = Image<int>(w, h, ZEROS); // inplacePaste(output, sp_img, Point2D<int>(w, 0)); for(int y = 0 ; y < h ; y ++) { int dot = 0; for(int x = 0 ; x < w ; x ++) { PixRGB<byte> c = sp_img.getVal(x,y); //LINFO("Pixel color(%d,%d,%d)road color(%d,%d,%d)",c.red(),c.green(),c.blue(), // itsRoadColor.red(),itsRoadColor.green(),itsRoadColor.blue()); if(c == itsRoadColor) { //Set road color to red byte red = 250+c.red(); if(red > 255) red = 255; //output.setVal(x,y,PixRGB<byte>(red,c.green()/32,c.blue()/32));//this will mess up find red region output.setVal(x,y,PixRGB<byte>(255,0,0)); itsRoadIndexMap.setVal(x,y,255); if(dot % 3 == 0) { hybrid.setVal(x,y,PixRGB<byte>(255,0,0)); } else { hybrid.setVal(x,y,c); } dot ++; } else { //set to it's color output.setVal(x,y,c); hybrid.setVal(x,y,c); itsRoadIndexMap.setVal(x,y,0); // output.setVal(x,y,c); } } } LINFO("hi11"); if(!output.initialized()) return img; LINFO("hi12"); //LINFO("Finish Road Finding"); itsRawRoadSuperPixelImg = hybrid; return output; }