/// <summary> /// Returns the maximal absolute distance between the components of /// the two matrices. /// </summary> public static __ftype__ DistanceMax(__nmtype__ a, __nmtype__ b) { return(Fun.Max( /*# n.ForEach(i => { */ Fun.Max( /*# m.ForEach(j => { */ Fun.Abs(b.M__i____j__ - a.M__i____j__) /*# * }, comma); */) /*# }, comma); */)); }
/// <summary> /// Uses the 2 random series (seriesIndex, seriesIndex+1) /// </summary> public static V3d Spherical( IRandomSeries rnds, int seriesIndex) { double phi = Constant.PiTimesTwo * rnds.UniformDouble(seriesIndex); double z = 1.0 - 2.0 * rnds.UniformDouble(seriesIndex + 1); double r = Fun.Max(1.0 - z * z, 0.0).Sqrt(); return(new V3d(r * phi.Cos(), r * phi.Sin(), z)); }
/// <summary> /// Stitches the images provided in the 2D array into one large image according to the position in the array. /// The array is treated as column-major. Therefore, the array /// {{1, 2, 3}} /// {{4, 5, 6}} /// produces the image /// 1 2 3 /// 4 6 7 /// Null-items are allowed an result in black spot at the corresponding position. /// The color format of all images must be equal and have byte format. /// </summary> /// <param name="images">The 2D image array that should be stitched.</param> /// <returns>Stitched image</returns> public static PixImage <T> Stitch <T>(this PixImage <T>[][] images) { if (images.IsEmptyOrNull()) { return(null); } // Find largest extensions var numRows = images.Length; var numColumns = images.Max(img => img.Length); // Find largest X Y var sizesX = new int[numColumns].SetByIndex(c => images.Max(ic => (ic[c] == null) ? 0 : ic[c].Size.X)); var sizesY = images.Map(img => img.Max(img2 => (img2 == null) ? 0 : img2.Size.Y)); var width = sizesX.Sum(); var height = sizesY.Sum(); // The first image in the array, used to determine the color format var fst = images.First(img => img.Length > 0).First(img => img != null); if (fst == null) { Report.Line("Empty image array!"); return(null); } // Assure that the color format fits if (images.TrueForAny(imgs => imgs.Where(i => i != null).TrueForAny(img => img.Format != fst.Format))) { Report.Line("Color format not matching!"); return(null); } // Allocate new image var target = new PixImage <T>(fst.Format, new V2i(width, height)); for (int r = 0, y = 0; r < numRows; r++) { for (int c = 0, x = 0; c < Fun.Max(numColumns, images[r].Length); c++) { var source = images[r][c]; if (source != null) { target.Set(x, y, source); } x += sizesX[c]; } y += sizesY[r]; } return(target); }
/// <summary> /// UnDistortion of pixel coordinates. /// </summary> public V2d UndistortPixel(V2d p2, V2i imageSize) { var maxSize = Fun.Max(imageSize.X, imageSize.Y); var y = (p2.Y - PrincipalPoint.Y * imageSize.Y) / (FocalLength.Y * maxSize); var x = (p2.X - PrincipalPoint.X * imageSize.X - Skew * maxSize * y) / (FocalLength.X * maxSize); ComputeUndistortionParamsForCameraPoint(x, y, out double rd, out double tx, out double ty); double xd = x * rd + tx; double yd = y * rd + ty; return(new V2d( FocalLength.X * maxSize * xd + Skew * maxSize * yd + PrincipalPoint.X * imageSize.X, FocalLength.Y * maxSize * yd + PrincipalPoint.Y * imageSize.Y)); }
/// <summary> /// Supplied normal MUST be normalized, uses the 2 random series /// (seriesIndex, seriesIndex+1). /// </summary> public static V3d Lambertian( V3d normal, IRandomSeries rnds, int seriesIndex) { V3d vec; double squareLen; do { double phi = Constant.PiTimesTwo * rnds.UniformDouble(seriesIndex); double z = 1.0 - 2.0 * rnds.UniformDouble(seriesIndex + 1); double r = Fun.Max(1.0 - z * z, 0.0).Sqrt(); vec = new V3d(r * phi.Cos(), r * phi.Sin(), z) + normal; squareLen = vec.LengthSquared; }while (squareLen < 0.000001); vec *= 1.0 / squareLen.Sqrt(); return(vec); }
/// <summary> /// Project a point from camera space into image space according to the intrinsic camera parameters. /// This documents the camera model. /// </summary> public V2d ProjectToImage(V3d p, V2d imageSize) { // projection double x = p.X / p.Z; double y = p.Y / p.Z; // undo distortion here ComputeUndistortionParamsForCameraPoint(x, y, out double rd, out double tx, out double ty); // undistorted point: double xd = x * rd + tx; double yd = y * rd + ty; double maxSize = Fun.Max(imageSize.X, imageSize.Y); // point in image: return(new V2d( FocalLength.X * maxSize * xd + Skew * maxSize * yd + PrincipalPoint.X * imageSize.X, FocalLength.Y * maxSize * yd + PrincipalPoint.Y * imageSize.Y)); }
/// <summary> /// Compute the Delaunay triangluation of the supplied points. Note that /// the supplied point array must be by 3 larger than the actual number of /// points. /// </summary> private static void Triangulate2d(V2d[] pa, out Triangle1i[] ta, out int triangleCount) { int vc = pa.Length - 4; int tcMax = 2 * vc + 2; // sharp upper bound with no degenerates int ecMax = 6 * vc - 3; // sharp bound: last step replaces all tris ta = new Triangle1i[tcMax]; var ra = new double[tcMax]; var ca = new V2d[tcMax]; var ea = new Line1i[ecMax]; // -------------------------------------- set up the supertriangle ta[0] = new Triangle1i(vc, vc + 2, vc + 1); ra[0] = -1.0; ta[1] = new Triangle1i(vc, vc + 3, vc + 2); ra[1] = -1.0; int tc = 2, cc = 0; // triangle count, complete count // ------------- superquad vertices at the end of vertex array var box = new Box2d(pa.Take(vc)).EnlargedBy(0.1); V2d center = box.Center, size = box.Size; pa[vc + 0] = box.Min; pa[vc + 1] = new V2d(box.Min.X, box.Max.Y); pa[vc + 2] = box.Max; pa[vc + 3] = new V2d(box.Max.X, box.Min.Y); // ------------------------------ include the points one at a time for (int i = 0; i < vc; i++) { V2d p = pa[i]; int ec = 0; /* * if the point lies inside the circumcircle then the triangle * is removed and its edges are added to the edge array */ for (int ti = cc; ti < tc; ti++) { var tr = ta[ti]; double r2 = ra[ti]; if (r2 < 0.0) { Triangle2d.ComputeCircumCircleSquared( pa[tr.I0], pa[tr.I1], pa[tr.I2], out center, out r2); ra[ti] = r2; ca[ti] = center; } else { center = ca[ti]; } // ---------------- include this if points are sorted by X if (center.X < p.X && (p.X - center.X).Square() > r2) { Fun.Swap(ref ta[ti], ref ta[cc]); ra[ti] = ra[cc]; ca[ti] = ca[cc]; ++cc; continue; } if (Vec.DistanceSquared(p, center) <= r2) { int nec = ec + 3; if (nec >= ecMax) { ecMax = Fun.Max(nec, (int)(1.1 * (double)ecMax)); Array.Resize(ref ea, ecMax); } ea[ec] = tr.Line01; ea[ec + 1] = tr.Line12; ea[ec + 2] = tr.Line20; --tc; ec = nec; ta[ti] = ta[tc]; ra[ti] = ra[tc]; ca[ti] = ca[tc]; --ti; } } // ---------------------------------------- tag multiple edges for (int ei = 0; ei < ec - 1; ei++) { for (int ej = ei + 1; ej < ec; ej++) { if (ea[ei].I0 == ea[ej].I1 && ea[ei].I1 == ea[ej].I0) { ea[ei] = Line1i.Invalid; ea[ej] = Line1i.Invalid; } } } // ------------------ form new triangles for the current point for (int ei = 0; ei < ec; ei++) { var e = ea[ei]; if (e.I0 < 0 || e.I1 < 0) { continue; // skip tagged edges } if (tc >= tcMax) // necessary for degenerate cases { tcMax = Fun.Max(tcMax + 1, (int)(1.1 * (double)tcMax)); Array.Resize(ref ta, tcMax); Array.Resize(ref ra, tcMax); Array.Resize(ref ca, tcMax); } ta[tc] = new Triangle1i(e.I0, e.I1, i); ra[tc++] = -1.0; } } // ------------------ remove triangles with supertriangle vertices for (int ti = 0; ti < tc; ti++) { if (ta[ti].I0 >= vc || ta[ti].I1 >= vc || ta[ti].I2 >= vc) { ta[ti--] = ta[--tc]; } } triangleCount = tc; }