public MaskedImage TransfromImageForwards(IImage image, bool preserveSize = false) { MaskedImage undistorted; var influences = FindInfluenceMatrix(image.RowCount, image.ColumnCount); Matrix<double>[] matrices = new Matrix<double>[image.ChannelsCount]; if(preserveSize) { // New image is in old one's coords undistorted = new MaskedImage(image.Clone()); for(int i = 0; i < image.ChannelsCount; ++i) { matrices[i] = new DenseMatrix(image.RowCount, image.ColumnCount); undistorted.SetMatrix(matrices[i], i); } // Bound processing to smaller of images in each dimesions int minX = Math.Max(0, _finalTopLeft.X); int maxX = Math.Min(image.ColumnCount, _finalSize.X + _finalTopLeft.X); int minY = Math.Max(0, _finalTopLeft.Y); int maxY = Math.Min(image.RowCount, _finalSize.Y + _finalTopLeft.Y); for(int x = minX; x < maxX; ++x) { for(int y = minY; y < maxY; ++y) { double influenceTotal = 0.0; double[] val = new double[image.ChannelsCount]; foreach(var inf in influences[y - _finalTopLeft.Y, x - _finalTopLeft.X]) // Move Pu to influence matrix coords { for(int i = 0; i < image.ChannelsCount; ++i) val[i] += image[inf.Yd, inf.Xd, i] * inf.Influence; influenceTotal += inf.Influence; } if(influenceTotal > 0.25) { for(int i = 0; i < image.ChannelsCount; ++i) matrices[i].At(y, x, val[i] / influenceTotal); undistorted.SetMaskAt(y, x, true); } else { undistorted.SetMaskAt(y, x, false); } } } } else { // New image is in same coords as influence matrix for(int i = 0; i < image.ChannelsCount; ++i) matrices[i] = new DenseMatrix(_finalSize.Y, _finalSize.X); IImage img = image.Clone(); for(int i = 0; i < image.ChannelsCount; ++i) img.SetMatrix(matrices[i], i); undistorted = new MaskedImage(image.Clone()); for(int x = 0; x < _finalSize.X; ++x) { for(int y = 0; y < _finalSize.Y; ++y) { double influenceTotal = 0.0; double[] val = new double[image.ChannelsCount]; foreach(var inf in influences[y, x]) { for(int i = 0; i < image.ChannelsCount; ++i) val[i] += image[inf.Yd, inf.Xd, i] * inf.Influence; influenceTotal += inf.Influence; } if(influenceTotal > 0.5) { for(int i = 0; i < image.ChannelsCount; ++i) matrices[i].At(y, x, val[i] / influenceTotal); undistorted.SetMaskAt(y, x, true); } else { undistorted.SetMaskAt(y, x, false); } } } } return undistorted; }
public MaskedImage TransfromImageBackwards(IImage image, bool preserveSize = false) { MaskedImage undistorted; FindTransformedImageSize(image.RowCount, image.ColumnCount); Matrix<double>[] matrices = new Matrix<double>[image.ChannelsCount]; if(preserveSize) { undistorted = new MaskedImage(image.Clone()); for(int i = 0; i < image.ChannelsCount; ++i) { matrices[i] = new DenseMatrix(image.RowCount, image.ColumnCount); undistorted.SetMatrix(matrices[i], i); } } else { IImage img = image.Clone(); for(int i = 0; i < image.ChannelsCount; ++i) { matrices[i] = new DenseMatrix(_finalSize.Y, _finalSize.X); img.SetMatrix(matrices[i], i); } undistorted = new MaskedImage(image.Clone()); } int R = InterpolationRadius; int R21 = R * 2 + 1; for(int x = 0; x < matrices[0].ColumnCount; ++x) { for(int y = 0; y < matrices[0].RowCount; ++y) { // Cast point from new image to old one Vector2 oldCoords = Transformation.TransformPointBackwards(new Vector2(x: x, y: y)); Vector2 aa = Transformation.TransformPointForwards(oldCoords); IntVector2 oldPixel = new IntVector2(oldCoords); // Check if point is in old image range or points to undefined point if(oldCoords.X < 0 || oldCoords.X > image.ColumnCount || oldCoords.Y < 0 || oldCoords.Y > image.RowCount || image.HaveValueAt(oldPixel.Y, oldPixel.X) == false) { // Point out of range, so set to black for(int i = 0; i < image.ChannelsCount; ++i) { matrices[i].At(y, x, 0.0); undistorted.SetMaskAt(y, x, false); } } else { // Interpolate value from patch in old image double[,] influence = new double[R21, R21]; double totalInf = 0; // For each pixel in neighbourhood find its distance and influence of Pu on it for(int dx = -R; dx <= R; ++dx) { for(int dy = -R; dy <= R; ++dy) { double distance = _computeDistance(oldCoords, oldPixel.X + dx, oldPixel.Y + dy); influence[dx + R, dy + R] = 1.0 / distance; totalInf += influence[dx + R, dy + R]; } } double infScale = 1.0 / totalInf; // Scale influence, so that its sum over all pixels in radius is 1 double[] val = new double[image.ChannelsCount]; for(int dx = -R; dx <= R; ++dx) { for(int dy = -R; dy <= R; ++dy) { double inf = influence[dx + R, dy + R] * infScale; // Store color for new point considering influence from neighbours int ix = Math.Max(0, Math.Min(image.ColumnCount - 1, oldPixel.X + dx)); int iy = Math.Max(0, Math.Min(image.RowCount - 1, oldPixel.Y + dy)); for(int i = 0; i < image.ChannelsCount; ++i) { val[i] += image[iy, ix, i] * inf; } } } for(int i = 0; i < image.ChannelsCount; ++i) { matrices[i].At(y, x, val[i]); } } } } return undistorted; }