private static void notifyProgessListenerIfNeeded(RasterBindingProgress progress, int startProgressPercent, int endProgressPercent, ref double completed, ref double previousPercent, int sourceWidth) { if (progress == null) { return; } completed += ((double)endProgressPercent - (double)startProgressPercent) / sourceWidth; if (Math.Truncate(completed) > previousPercent) { progress((int)Math.Truncate(completed + startProgressPercent)); previousPercent = Math.Truncate(completed); } }
/// <summary> /// Performs a rubbersheeting transformation of raster. /// </summary> /// <param name="source">A System.Drawing.Bitmap instance containing the source image</param> /// <param name="sourceControlPoints">Control points of source</param> /// <param name="destinationControlPoints">Control points on the map</param> /// <param name="rectangle">A bounding rectangle defining a bouns of transformed raster</param> /// <param name="progress">Defines a method which is called to notify a subscriber about completion state.</param> /// <returns>A System.Drawing.Bitmap instance containing the transformed image</returns> public static Bitmap BindRaster(Bitmap source, Point[] sourceControlPoints, ICoordinate[] destinationControlPoints, out BoundingRectangle rectangle, RasterBindingProgress progress) { #if DEMO throw new NotImplementedException("This method is not implemented in demo version."); #else if (source == null) throw new ArgumentNullException("source"); if (sourceControlPoints.Length != destinationControlPoints.Length) throw new ArgumentException("Number of control points of raster and map should be the same."); if (sourceControlPoints.Length < 3) throw new ArgumentException("Number of control points should not be less than 3"); if (!checkControlPoints(source.Width, source.Height, sourceControlPoints)) throw new ArgumentException("At least one source control point is outside raster", "sourceControlPoints"); ICoordinate[,] warpTransformResult = new ICoordinate[source.Width, source.Height]; PointF[,] affinneTransformResult = new PointF[source.Width, source.Height]; // вычисляем результат аффинного преобразования примененного к координатам точек исходного растра calculateAffinneTransform(source.Width, source.Height, affinneTransformResult, sourceControlPoints, destinationControlPoints, progress); ICoordinate[] shifts = new ICoordinate[destinationControlPoints.Length]; for (int i = 0; i < shifts.Length; i++) { PointF p = affinneTransformResult[sourceControlPoints[i].X, sourceControlPoints[i].Y]; shifts[i] = PlanimetryEnvironment.NewCoordinate(destinationControlPoints[i].X - p.X, destinationControlPoints[i].Y - p.Y); } // вычисляем новые координаты точек исходного растра, полученные в результате "коробления" calculateRubberSheetTransform(source.Width, source.Height, affinneTransformResult, warpTransformResult, destinationControlPoints, shifts, progress); // вычисляем ограничивающий прямоугольник преобразованного растра rectangle = new BoundingRectangle(); for (int i = 0; i < source.Width; i++) for (int j = 0; j < source.Height; j++) { if (!double.IsNaN(warpTransformResult[i, j].X) && !double.IsNaN(warpTransformResult[i, j].Y)) rectangle.Join(warpTransformResult[i, j]); } return calcDestRaster(source, rectangle, warpTransformResult, progress); #endif }
private static Bitmap calcDestRaster(Bitmap source, BoundingRectangle rectangle, ICoordinate[,] warpTransformResult, RasterBindingProgress progress) { byte[,] fillCount = new byte[source.Width, source.Height]; Int16[,] r = new Int16[source.Width, source.Height]; Int16[,] g = new Int16[source.Width, source.Height]; Int16[,] b = new Int16[source.Width, source.Height]; for (int i = 0; i < source.Width; i++) for (int j = 0; j < source.Height; j++) { fillCount[i, j] = 0; r[i, j] = 0; g[i, j] = 0; b[i, j] = 0; } Bitmap result = new Bitmap(source.Width, source.Height); int startProgressPercent = 70; int endProgressPercent = 80; double completed = 0; double previousPercent = 0; for (int i = 0; i < source.Width; i++) { for (int j = 0; j < source.Height; j++) { int x = getDestRasterX(source.Width, warpTransformResult[i, j], rectangle); int y = getDestRasterY(source.Height, warpTransformResult[i, j], rectangle); if (!double.IsNaN(warpTransformResult[i, j].X) && !double.IsNaN(warpTransformResult[i, j].Y) && x >= 0 && y >= 0) { fillCount[x, y]++; Color c = source.GetPixel(i, j); r[x, y] += c.R; g[x, y] += c.G; b[x, y] += c.B; } } notifyProgessListenerIfNeeded(progress, startProgressPercent, endProgressPercent, ref completed, ref previousPercent, source.Width); } startProgressPercent = 80; endProgressPercent = 90; completed = 0; for (int i = 0; i < source.Width; i++) { for (int j = 0; j < source.Height; j++) { int fc = fillCount[i, j]; if (fc > 0) { result.SetPixel(i, j, Color.FromArgb(r[i, j] / fc, g[i, j] / fc, b[i, j] / fc)); } else result.SetPixel(i, j, Color.Transparent); } notifyProgessListenerIfNeeded(progress, startProgressPercent, endProgressPercent, ref completed, ref previousPercent, source.Width); } startProgressPercent = 90; endProgressPercent = 100; completed = 0; for (int i = 0; i < source.Width; i++) { for (int j = 0; j < source.Height; j++) if (fillCount[i, j] == 0) fillPixel(i, j, result, fillCount, result.Width, result.Height); notifyProgessListenerIfNeeded(progress, startProgressPercent, endProgressPercent, ref completed, ref previousPercent, source.Width); } return result; }
private static void notifyProgessListenerIfNeeded(RasterBindingProgress progress, int startProgressPercent, int endProgressPercent, ref double completed, ref double previousPercent, int sourceWidth) { if (progress == null) return; completed += ((double)endProgressPercent - (double)startProgressPercent) / sourceWidth; if (Math.Truncate(completed) > previousPercent) { progress((int)Math.Truncate(completed + startProgressPercent)); previousPercent = Math.Truncate(completed); } }
private static void calculateAffinneTransform(int width, int height, PointF[,] affinneTransformResult, Point[] sourceNodes, ICoordinate[] destNodes, RasterBindingProgress progress) { int[] r = RasterAlgorithms.calculateOptimalAffineTransformPoints(sourceNodes, destNodes); PointF p01 = new PointF(sourceNodes[r[0]].X, sourceNodes[r[0]].Y); PointF p02 = new PointF(sourceNodes[r[1]].X, sourceNodes[r[1]].Y); PointF p03 = new PointF(sourceNodes[r[2]].X, sourceNodes[r[2]].Y); PointF p11 = new PointF((float)destNodes[r[0]].X, (float)destNodes[r[0]].Y); PointF p12 = new PointF((float)destNodes[r[1]].X, (float)destNodes[r[1]].Y); PointF p13 = new PointF((float)destNodes[r[2]].X, (float)destNodes[r[2]].Y); int startProgressPercent = 0; int endProgressPercent = 30; double completed = 0; double previousPercent = 0; Matrix m = getAffineTransformMatrix(p01, p02, p03, p11, p12, p13); for (int i = 0; i < width; i++) { PointF[] pts = new PointF[height]; for (int j = 0; j < height; j++) pts[j] = new PointF(i, j); m.TransformPoints(pts); for (int j = 0; j < height; j++) affinneTransformResult[i, j] = pts[j]; if (progress != null) { completed += ((double)endProgressPercent - (double)startProgressPercent) / width; if (Math.Truncate(completed) > previousPercent) { progress((int)Math.Truncate(completed + startProgressPercent)); previousPercent = Math.Truncate(completed); } } } }
private static void calculateRubberSheetTransform(int width, int height, PointF[,] source, ICoordinate[,] result, ICoordinate[] sourceNodes, ICoordinate[] destNodesShifts, RasterBindingProgress progress) { double[] w = new double[sourceNodes.Length]; double[] distances = new double[sourceNodes.Length]; int startProgressPercent = 30; int endProgressPercent = 70; double completed = 0; double previousPercent = 0; for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { // проверяем попали ли мы в узел интерполяции bool isNode = false; for (int k = 0; k < sourceNodes.Length; k++) { if (sourceNodes[k].X == source[i, j].X && sourceNodes[k].Y == source[i, j].Y) { // попали result[i, j] = PlanimetryEnvironment.NewCoordinate(destNodesShifts[k].X + source[i, j].X, destNodesShifts[k].Y + source[i, j].Y); isNode = true; } } if (isNode) continue; // расчет расстояний до узлов double maxDistance = 0; for (int t = 0; t < sourceNodes.Length; t++) { ICoordinate p = PlanimetryEnvironment.NewCoordinate(sourceNodes[t].X, sourceNodes[t].Y); distances[t] = PlanimetryAlgorithms.Distance(p, PlanimetryEnvironment.NewCoordinate(source[i, j].X, source[i, j].Y)); if (maxDistance < distances[t]) maxDistance = distances[t]; } // расчет знаменателей весов узловых точек double sum = 0; for (int k = 0; k < sourceNodes.Length; k++) { double temp = (maxDistance - distances[k]) / (maxDistance * distances[k]); sum += Math.Pow(temp, 2); } // расчет весов узловых точек for (int k = 0; k < sourceNodes.Length; k++) { double temp = (maxDistance - distances[k]) / (maxDistance * distances[k]); w[k] = Math.Pow(temp, 2) / sum; } // расчет значений новых координат result[i, j] = PlanimetryEnvironment.NewCoordinate(source[i, j].X, source[i, j].Y); for (int k = 0; k < sourceNodes.Length; k++) { result[i, j].X += w[k] * destNodesShifts[k].X; result[i, j].Y += w[k] * destNodesShifts[k].Y; } } notifyProgessListenerIfNeeded(progress, startProgressPercent, endProgressPercent, ref completed, ref previousPercent, width); } }
/// <summary> /// Performs a rubbersheeting transformation of raster. /// </summary> /// <param name="source">A System.Drawing.Bitmap instance containing the source image</param> /// <param name="sourceControlPoints">Control points of source</param> /// <param name="destinationControlPoints">Control points on the map</param> /// <param name="rectangle">A bounding rectangle defining a bouns of transformed raster</param> /// <param name="progress">Defines a method which is called to notify a subscriber about completion state.</param> /// <returns>A System.Drawing.Bitmap instance containing the transformed image</returns> public static Bitmap BindRaster(Bitmap source, Point[] sourceControlPoints, ICoordinate[] destinationControlPoints, out BoundingRectangle rectangle, RasterBindingProgress progress) { #if DEMO throw new NotImplementedException("This method is not implemented in demo version."); #else if (source == null) { throw new ArgumentNullException("source"); } if (sourceControlPoints.Length != destinationControlPoints.Length) { throw new ArgumentException("Number of control points of raster and map should be the same."); } if (sourceControlPoints.Length < 3) { throw new ArgumentException("Number of control points should not be less than 3"); } if (!checkControlPoints(source.Width, source.Height, sourceControlPoints)) { throw new ArgumentException("At least one source control point is outside raster", "sourceControlPoints"); } ICoordinate[,] warpTransformResult = new ICoordinate[source.Width, source.Height]; PointF[,] affinneTransformResult = new PointF[source.Width, source.Height]; // вычисляем результат аффинного преобразования примененного к координатам точек исходного растра calculateAffinneTransform(source.Width, source.Height, affinneTransformResult, sourceControlPoints, destinationControlPoints, progress); ICoordinate[] shifts = new ICoordinate[destinationControlPoints.Length]; for (int i = 0; i < shifts.Length; i++) { PointF p = affinneTransformResult[sourceControlPoints[i].X, sourceControlPoints[i].Y]; shifts[i] = PlanimetryEnvironment.NewCoordinate(destinationControlPoints[i].X - p.X, destinationControlPoints[i].Y - p.Y); } // вычисляем новые координаты точек исходного растра, полученные в результате "коробления" calculateRubberSheetTransform(source.Width, source.Height, affinneTransformResult, warpTransformResult, destinationControlPoints, shifts, progress); // вычисляем ограничивающий прямоугольник преобразованного растра rectangle = new BoundingRectangle(); for (int i = 0; i < source.Width; i++) { for (int j = 0; j < source.Height; j++) { if (!double.IsNaN(warpTransformResult[i, j].X) && !double.IsNaN(warpTransformResult[i, j].Y)) { rectangle.Join(warpTransformResult[i, j]); } } } return(calcDestRaster(source, rectangle, warpTransformResult, progress)); #endif }
private static Bitmap calcDestRaster(Bitmap source, BoundingRectangle rectangle, ICoordinate[,] warpTransformResult, RasterBindingProgress progress) { byte[,] fillCount = new byte[source.Width, source.Height]; Int16[,] r = new Int16[source.Width, source.Height]; Int16[,] g = new Int16[source.Width, source.Height]; Int16[,] b = new Int16[source.Width, source.Height]; for (int i = 0; i < source.Width; i++) { for (int j = 0; j < source.Height; j++) { fillCount[i, j] = 0; r[i, j] = 0; g[i, j] = 0; b[i, j] = 0; } } Bitmap result = new Bitmap(source.Width, source.Height); int startProgressPercent = 70; int endProgressPercent = 80; double completed = 0; double previousPercent = 0; for (int i = 0; i < source.Width; i++) { for (int j = 0; j < source.Height; j++) { int x = getDestRasterX(source.Width, warpTransformResult[i, j], rectangle); int y = getDestRasterY(source.Height, warpTransformResult[i, j], rectangle); if (!double.IsNaN(warpTransformResult[i, j].X) && !double.IsNaN(warpTransformResult[i, j].Y) && x >= 0 && y >= 0) { fillCount[x, y]++; Color c = source.GetPixel(i, j); r[x, y] += c.R; g[x, y] += c.G; b[x, y] += c.B; } } notifyProgessListenerIfNeeded(progress, startProgressPercent, endProgressPercent, ref completed, ref previousPercent, source.Width); } startProgressPercent = 80; endProgressPercent = 90; completed = 0; for (int i = 0; i < source.Width; i++) { for (int j = 0; j < source.Height; j++) { int fc = fillCount[i, j]; if (fc > 0) { result.SetPixel(i, j, Color.FromArgb(r[i, j] / fc, g[i, j] / fc, b[i, j] / fc)); } else { result.SetPixel(i, j, Color.Transparent); } } notifyProgessListenerIfNeeded(progress, startProgressPercent, endProgressPercent, ref completed, ref previousPercent, source.Width); } startProgressPercent = 90; endProgressPercent = 100; completed = 0; for (int i = 0; i < source.Width; i++) { for (int j = 0; j < source.Height; j++) { if (fillCount[i, j] == 0) { fillPixel(i, j, result, fillCount, result.Width, result.Height); } } notifyProgessListenerIfNeeded(progress, startProgressPercent, endProgressPercent, ref completed, ref previousPercent, source.Width); } return(result); }
private static void calculateAffinneTransform(int width, int height, PointF[,] affinneTransformResult, Point[] sourceNodes, ICoordinate[] destNodes, RasterBindingProgress progress) { int[] r = RasterAlgorithms.calculateOptimalAffineTransformPoints(sourceNodes, destNodes); PointF p01 = new PointF(sourceNodes[r[0]].X, sourceNodes[r[0]].Y); PointF p02 = new PointF(sourceNodes[r[1]].X, sourceNodes[r[1]].Y); PointF p03 = new PointF(sourceNodes[r[2]].X, sourceNodes[r[2]].Y); PointF p11 = new PointF((float)destNodes[r[0]].X, (float)destNodes[r[0]].Y); PointF p12 = new PointF((float)destNodes[r[1]].X, (float)destNodes[r[1]].Y); PointF p13 = new PointF((float)destNodes[r[2]].X, (float)destNodes[r[2]].Y); int startProgressPercent = 0; int endProgressPercent = 30; double completed = 0; double previousPercent = 0; Matrix m = getAffineTransformMatrix(p01, p02, p03, p11, p12, p13); for (int i = 0; i < width; i++) { PointF[] pts = new PointF[height]; for (int j = 0; j < height; j++) { pts[j] = new PointF(i, j); } m.TransformPoints(pts); for (int j = 0; j < height; j++) { affinneTransformResult[i, j] = pts[j]; } if (progress != null) { completed += ((double)endProgressPercent - (double)startProgressPercent) / width; if (Math.Truncate(completed) > previousPercent) { progress((int)Math.Truncate(completed + startProgressPercent)); previousPercent = Math.Truncate(completed); } } } }
private static void calculateRubberSheetTransform(int width, int height, PointF[,] source, ICoordinate[,] result, ICoordinate[] sourceNodes, ICoordinate[] destNodesShifts, RasterBindingProgress progress) { double[] w = new double[sourceNodes.Length]; double[] distances = new double[sourceNodes.Length]; int startProgressPercent = 30; int endProgressPercent = 70; double completed = 0; double previousPercent = 0; for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { // проверяем попали ли мы в узел интерполяции bool isNode = false; for (int k = 0; k < sourceNodes.Length; k++) { if (sourceNodes[k].X == source[i, j].X && sourceNodes[k].Y == source[i, j].Y) { // попали result[i, j] = PlanimetryEnvironment.NewCoordinate(destNodesShifts[k].X + source[i, j].X, destNodesShifts[k].Y + source[i, j].Y); isNode = true; } } if (isNode) { continue; } // расчет расстояний до узлов double maxDistance = 0; for (int t = 0; t < sourceNodes.Length; t++) { ICoordinate p = PlanimetryEnvironment.NewCoordinate(sourceNodes[t].X, sourceNodes[t].Y); distances[t] = PlanimetryAlgorithms.Distance(p, PlanimetryEnvironment.NewCoordinate(source[i, j].X, source[i, j].Y)); if (maxDistance < distances[t]) { maxDistance = distances[t]; } } // расчет знаменателей весов узловых точек double sum = 0; for (int k = 0; k < sourceNodes.Length; k++) { double temp = (maxDistance - distances[k]) / (maxDistance * distances[k]); sum += Math.Pow(temp, 2); } // расчет весов узловых точек for (int k = 0; k < sourceNodes.Length; k++) { double temp = (maxDistance - distances[k]) / (maxDistance * distances[k]); w[k] = Math.Pow(temp, 2) / sum; } // расчет значений новых координат result[i, j] = PlanimetryEnvironment.NewCoordinate(source[i, j].X, source[i, j].Y); for (int k = 0; k < sourceNodes.Length; k++) { result[i, j].X += w[k] * destNodesShifts[k].X; result[i, j].Y += w[k] * destNodesShifts[k].Y; } } notifyProgessListenerIfNeeded(progress, startProgressPercent, endProgressPercent, ref completed, ref previousPercent, width); } }