// Moments vector : [m00, m01, m10, m11, m02, m20, m12, m21, m03, m30] Vector<double> ComputeMomentVectorForPatch(IntVector2 centerPixel, IImage image) { Vector<double> moments = new DenseVector(10); // M00 = total_intensity // Mpq = sum{x,y}( x^p*y^q*I(x,y) ) for(int dx = -WindowRadius; dx <= WindowRadius; ++dx) { for(int dy = -_ybounds[dx + WindowRadius]; dy <= _ybounds[dx + WindowRadius]; ++dy) { if(image.HaveValueAt(centerPixel.Y + dy, centerPixel.X + dx)) { double val = image[centerPixel.Y + dy, centerPixel.X + dx]; moments[m00] += val; moments[m01] += dy * val; moments[m10] += dx * val; moments[m11] += dx * dy * val; moments[m02] += dy * dy * val; moments[m20] += dx * dx * val; moments[m12] += dx * dy * dy * val; moments[m21] += dx * dx * dy * val; moments[m03] += dy * dy * dy * val; moments[m30] += dx * dx * dx * val; } } } return moments; }
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; }