public void RemoveNeighbor(ManifoldPoint adj) { if (this.neighbors != null) { this.neighbors.Remove(adj); } }
public void AddNeighbor(ManifoldPoint adj) { if (this.neighbors == null) { this.neighbors = new List <ManifoldPoint>(); } if (!this.neighbors.Contains(adj)) { this.neighbors.Add(adj); } }
public int CompareTo(PriorityQueueElement other) { ManifoldPoint rec = other as ManifoldPoint; if (this.distance < rec.distance) { return(-1); } if (this.distance > rec.distance) { return(1); } return(0); }
private void InitAppearanceManifold() { int w = this.labImage.Width, h = this.labImage.Height; this.manifoldPoints = new ManifoldPoint[w, h]; this.leastWeatheredPoints = new List <ManifoldPoint>(); this.mostWeatheredPoints = new List <ManifoldPoint>(); this.nonWeatheredPoints = new List <ManifoldPoint>(); this.kdTree = new KDTree <ManifoldPoint>(3); // create manifold points for (int i = 0; i < w; ++i) { for (int j = 0; j < h; ++j) { Lab lab = this.labImage[j, i]; ManifoldPoint mp = new ManifoldPoint(i * h + j, new Vector3d(lab.X, lab.Y, lab.Z) ); this.manifoldPoints[i, j] = mp; switch (this.userMask[i, j]) { case 1: // least weathered -- left mouse button this.leastWeatheredPoints.Add(mp); break; case 2: // least weathered -- left mouse button this.mostWeatheredPoints.Add(mp); break; case 3: // unused pointes (e.g., shadows, etc) this.nonWeatheredPoints.Add(mp); break; } // fill tree kdTree.Add(mp, mp.Pos.x, mp.Pos.y, mp.Pos.z); } } }
private double[] ComputeDistanceFrom(ManifoldPoint rec) { int w = this.labImage.Width, h = this.labImage.Height; int n = w * h; PriorityQueue queue = new PriorityQueue(n); rec.Distance = 0; // initialize seed foreach (ManifoldPoint p in this.manifoldPoints) { queue.Insert(p); } while (queue.IsEmpty() == false) { ManifoldPoint u = queue.DeleteMin() as ManifoldPoint; foreach (ManifoldPoint v in u.Neighbors) { double dis = (u.Pos - v.Pos).Length(); if (dis < v.Distance) { v.Parent = u; v.Distance = dis; if (!queue.IsEmpty()) { queue.Update(v); } } } } double[] distance = new double[n]; for (int i = 0; i < n; i++) { distance[i] = this.manifoldPoints[i / h, i % h].Distance; } return(distance); }
private void ComputeShadingComponent() { // find the least- and most- bright pixel in Ic channels // to determine the window radious r(x,y) = p*e(-q*Il(x,y)), so that // r(brightiest pixel) = 1, r(darkest pixel) = 20; double brightiest_Il = double.MinValue; double darkest_Il = double.MaxValue; foreach (ManifoldPoint mp in this.manifoldPoints) { if (mp.Il > brightiest_Il) { brightiest_Il = mp.Il; } if (mp.Il < darkest_Il) { darkest_Il = mp.Il; } } double q = Math.Log(20.0) / (brightiest_Il - darkest_Il); double p = Math.Exp(q * brightiest_Il); // now compute the hist_xy for each pixel // first fill the pixels into buckets w.r.t. ab channels List <ManifoldPoint>[,] ab_buckets = new List <ManifoldPoint> [255, 255]; for (int i = 0; i < 255; ++i) { for (int j = 0; j < 255; ++j) { ab_buckets[i, j] = new List <ManifoldPoint>(); } } foreach (ManifoldPoint mp in this.manifoldPoints) { int I = (int)mp.Pos.y + 128; int J = (int)mp.Pos.z + 128; ab_buckets[I, J].Add(mp); } int w = this.labImage.Width, h = this.labImage.Height; double[, ][] pixel_pdfs = new double[w, h][]; // for each pixel, initialize a pdf double[, ][] new_pixel_pdfs = new double[w, h][]; // for each pixel, initialize a new pdf Random rand = new Random(); int K = 500; int numbins = 100; double[] x_val = new double[numbins]; for (int i = 0; i < numbins; ++i) // the x values for pdfs { x_val[i] = (double)(i + 0.5) / numbins; } // copy weathering degree foreach (ManifoldPoint mp in this.manifoldPoints) { mp.OldWeatheringDegree = mp.WeatheringDegree; } // iteration int itr = 0, maxitr = 5; do { foreach (ManifoldPoint mp in this.manifoldPoints) { int r = (int)(p * Math.Exp(-q * mp.Il)); // get all manifold points within the radius r List <ManifoldPoint> ab_points = new List <ManifoldPoint>(); for (int i = -r; i < r; ++i) { for (int j = -r; j < r; ++j) { int I = (int)mp.Pos.y + 128 + i; int J = (int)mp.Pos.z + 128 + j; if (I >= 0 && I < 255 && J >= 0 && J < 255) { ab_points.AddRange(ab_buckets[I, J]); } } } // now radom sample K points -- might be repeated double[] pdf = new double[numbins]; int ncount = ab_points.Count; if (ncount > 0) { List <ManifoldPoint> hist_points = new List <ManifoldPoint>(); for (int i = 0; i < K; ++i) { hist_points.Add(ab_points[rand.Next(ncount)]); } // build the histogram -- pdf // divid the weathering degree into 100 uniform bins double step = 1.0 / numbins; foreach (ManifoldPoint pp in hist_points) { int bin_index = (int)(pp.WeatheringDegree / step) % numbins; pdf[bin_index] += 1.0 / (hist_points.Count); // normalization } } pixel_pdfs[mp.Index / h, mp.Index % h] = pdf; } // convolve the pixel weathering degrees int windowsize = 2; for (int i = 0; i < w; ++i) { for (int j = 0; j < h; ++j) { double[] pdf1 = pixel_pdfs[i, j]; double[] res = pdf1.Clone() as double[]; for (int k = -windowsize; k < windowsize; ++k) { int I = i + k, J = j + k; if (I >= 0 && I < w && J >= 0 && J < h) { double[] pdf2 = pixel_pdfs[I, J]; for (int l = 0; l < pdf1.Length; ++l) { res[l] *= pdf2[l]; } } } this.NormalizeData(res); new_pixel_pdfs[i, j] = res; } } // assign back the weathering degree for (int i = 0; i < w; ++i) { for (int j = 0; j < h; ++j) { double[] pdf1 = pixel_pdfs[i, j]; double[] pdf2 = new_pixel_pdfs[i, j]; double mean1, var1, mean2, var2; this.ComputeMeanAndVariance(pdf1, x_val, out mean1, out var1); this.ComputeMeanAndVariance(pdf2, x_val, out mean2, out var2); if (var1 < var2) // confidence increase { this.manifoldPoints[i, j].WeatheringDegree = mean2; } } } }while (itr++ < maxitr); // now update the weathering (reflectance) component & compute the shading component List <ManifoldPoint>[] w_buckets = this.PackPointsIntoBins(1000); double[,] wl = new double[w, h]; // compute the new weathering component for (int i = 0; i < w; ++i) { for (int j = 0; j < h; ++j) { ManifoldPoint curr_point = this.manifoldPoints[i, j]; double wd = curr_point.WeatheringDegree; int btk_idx = (int)(wd / 1e-3); List <ManifoldPoint> mp_list = new List <ManifoldPoint>(); foreach (ManifoldPoint mp in w_buckets[btk_idx]) // get all points with weather defree = wd { if (Math.Abs(mp.OldWeatheringDegree - wd) < 1e-5) { mp_list.Add(mp); } } double mincrama = double.MaxValue; // get the one point with cloest ab value foreach (ManifoldPoint mp in mp_list) { double dy = (curr_point.Pos.y - mp.Pos.y); double dz = (curr_point.Pos.z - mp.Pos.z); double dd = dy * dy + dz * dz; if (dd < mincrama) { mincrama = dd; wl[i, j] = mp.Wl; // assign the weathering component } } } } // compute the shading component for (int i = 0; i < w; ++i) { for (int j = 0; j < h; ++j) { ManifoldPoint curr_point = this.manifoldPoints[i, j]; double _wl = wl[i, j]; if (_wl > 0) { curr_point.Sl = curr_point.Il / wl[i, j]; } else { curr_point.Sl = curr_point.Il / curr_point.Wl; } } } }
private void ConvexilizePoints() { // dilate and make convex the least- and most- weathered points // compute distances from src/tar points to all other points double[][] src_dist = new double[this.leastWeatheredPoints.Count][]; double[][] tar_dist = new double[this.mostWeatheredPoints.Count][]; int I = 0; this.leastWeatheredPoints.ForEach(p => src_dist[I++] = this.ComputeDistanceFrom(p)); I = 0; this.mostWeatheredPoints.ForEach(p => tar_dist[I++] = this.ComputeDistanceFrom(p)); // find the minmum distance between points in source and targets double geoV02V1 = double.MaxValue; foreach (ManifoldPoint mp in this.leastWeatheredPoints) { foreach (double[] dist in tar_dist) { double d = dist[mp.Index]; if (d < geoV02V1) { geoV02V1 = d; } } } geoV02V1 *= 0.9; // dilate the source (least weathered points) foreach (ManifoldPoint mp in this.manifoldPoints) { if (this.leastWeatheredPoints.Contains(mp)) { continue; } double geovvo = double.MaxValue; foreach (double[] dist in tar_dist) { double d = dist[mp.Index]; if (d < geovvo) { geovvo = d; } } if (geovvo > geoV02V1) { this.leastWeatheredPoints.Add(mp); } } // dilate the target (most weathered points) foreach (ManifoldPoint mp in this.manifoldPoints) { if (this.mostWeatheredPoints.Contains(mp)) { continue; } double geovvo = double.MaxValue; foreach (double[] dist in src_dist) { double d = dist[mp.Index]; if (d < geovvo) { geovvo = d; } } if (geovvo > geoV02V1) { this.mostWeatheredPoints.Add(mp); } } // convexilize List <ManifoldPoint> res_points = new List <ManifoldPoint>(); foreach (ManifoldPoint mp in this.leastWeatheredPoints) { this.ComputeDistanceFrom(mp); foreach (ManifoldPoint mp2 in this.leastWeatheredPoints) { ManifoldPoint tmp = mp2; while (tmp.Parent != null) { res_points.Add(tmp.Parent); tmp = tmp.Parent; } } } foreach (ManifoldPoint mp in res_points) { if (!this.leastWeatheredPoints.Contains(mp)) { this.leastWeatheredPoints.Add(mp); } } // the most-weathered points part res_points.Clear(); foreach (ManifoldPoint mp in this.mostWeatheredPoints) { this.ComputeDistanceFrom(mp); foreach (ManifoldPoint mp2 in this.mostWeatheredPoints) { ManifoldPoint tmp = mp2; while (tmp.Parent != null) { res_points.Add(tmp.Parent); tmp = tmp.Parent; } } } foreach (ManifoldPoint mp in res_points) { if (!this.mostWeatheredPoints.Contains(mp)) { this.mostWeatheredPoints.Add(mp); } } }
public void Weathering(double t) // t -> time { // divid into bins by weathering degrees -- for fast query List <ManifoldPoint>[] w_buckets = this.PackPointsIntoBins(1000); double intv = 1.0 / 1000; // by editing t, we edit the weathering degree (0,1) is deweathering, (1,infinity) is weathering int w = this.labImage.Width, h = this.labImage.Height; double[,] new_wl = new double[w, h]; for (int i = 0; i < w; ++i) { for (int j = 0; j < h; ++j) { ManifoldPoint pt = this.manifoldPoints[i, j]; // compute the new weathering degree d' double ds = pt.WeatheringDegree; double dt = 1 - Math.Exp(-pt.Kw * t); List <ManifoldPoint> srcpoints = this.FindPointsWithDegree(w_buckets[(int)(ds / intv)], ds); List <ManifoldPoint> tarpoints = this.FindPointsWithDegree(w_buckets[(int)(dt / intv)], dt); // compute src and tar geometric center Vector3d srcvc = new Vector3d(); foreach (ManifoldPoint mp in srcpoints) { srcvc += mp.Pos; } srcvc *= (1.0 / srcpoints.Count); Vector3d tarvc = new Vector3d(); foreach (ManifoldPoint mp in tarpoints) { tarvc += mp.Pos; } tarvc *= (1.0 / tarpoints.Count); // find points closest to geometric centers ManifoldPoint svc = null, tvc = null; double mindist = double.MaxValue; foreach (ManifoldPoint mp in srcpoints) { double d = (mp.Pos - srcvc).Length(); if (d < mindist) { mindist = d; svc = mp; } } mindist = double.MaxValue; foreach (ManifoldPoint mp in tarpoints) { double d = (mp.Pos - tarvc).Length(); if (d < mindist) { mindist = d; tvc = mp; } } int I = svc.Index / h, J = svc.Index % h; double RadSv1 = double.MinValue; foreach (ManifoldPoint mp in srcpoints) { double d = this.manifoldGeodesic[I, J][mp.Index]; if (d > RadSv1) { RadSv1 = d; } } double RbrVs1 = this.manifoldGeodesic[I, J][pt.Index] / RadSv1; // see paper - the distance between svc and the src point // find the target point with degree d and assign the weathering component I = tvc.Index / h; J = tvc.Index % h; double RadTa1 = double.MinValue; double[] geo = this.manifoldGeodesic[I, J]; foreach (ManifoldPoint mp in tarpoints) { double d = geo[mp.Index]; if (d > RadTa1) { RadTa1 = d; } } // find the target point with degree d and assign the weathering component mindist = double.MaxValue; ManifoldPoint target = null; foreach (ManifoldPoint mp in tarpoints) { double Rbrv = geo[mp.Index] / RadTa1; double geosv = this.manifoldGeodesic[i, j][mp.Index]; double d = geosv * (Rbrv - RbrVs1); if (d < mindist) { mindist = d; target = mp; } } // apply the effect (combine with shading component) this.labImage[i, j] = new Lab(target.Wl * pt.Sl, target.Pos.y, target.Pos.z); } } }