Beispiel #1
0
        /// <summary>
        /// Rotates volume along given axis.
        /// </summary>
        /// <param name="volume"></param>
        /// <param name="angles"></param>
        public static void RotateData(ref vtkImageData volume, double[] angles)
        {
            // Rotation along image center
            double[] center = volume.GetExtent().Divide(2);
            // Dimensions of rotated image
            int[] outExtent = volume.GetExtent().Multiply(1.1).Round().ToInt32();

            // Rotation parameters
            var rotate = new vtkTransform();

            rotate.Translate(center[1], center[3], center[5]);
            rotate.RotateX(angles[0]);
            rotate.RotateY(angles[1]);
            rotate.RotateZ(angles[2]); // z angle should be 0
            rotate.Translate(-center[1], -center[3], -center[5]);

            // Perform rotation
            var slice = new vtkImageReslice();

            slice.SetInput(volume);
            slice.SetResliceTransform(rotate);
            slice.SetInterpolationModeToCubic();
            slice.SetOutputSpacing(volume.GetSpacing()[0], volume.GetSpacing()[1], volume.GetSpacing()[2]);
            slice.SetOutputOrigin(volume.GetOrigin()[0], volume.GetOrigin()[1], volume.GetOrigin()[2]);
            slice.SetOutputExtent(outExtent[0], outExtent[1], outExtent[2], outExtent[3], outExtent[4], outExtent[5]);
        }
Beispiel #2
0
        /// <summary>
        /// Function for removing sample edges.
        /// </summary>
        /// <param name="stack"></param>
        /// <param name="side"></param>
        /// <param name="get_center"></param>
        /// <returns></returns>
        public static vtkImageData center_crop(vtkImageData stack, int side = 400, bool get_center = true)
        {
            //Get input dimensions
            int[] dims = stack.GetExtent();

            //Find the center of the sample

            int x1; int x2; int y1; int y2;

            int[] center = find_center(stack, 70, new int[] { 0, (dims[5] - dims[4] + 1) / 3 });//GetCenter(bytedata,80);
            //Compute new volume sides
            y2 = Math.Min(center[0] + (side / 2), dims[1]);
            y1 = Math.Max(y2 - side + 1, dims[0]);
            x2 = Math.Min(center[1] + (side / 2), dims[3]);
            x1 = Math.Max(x2 - side + 1, dims[2]);

            //Create VOI extractor
            vtkExtractVOI cropper = vtkExtractVOI.New();

            cropper.SetVOI(y1, y2, x1, x2, dims[4], dims[5]);
            cropper.SetInput(stack);
            cropper.Update();

            return(cropper.GetOutput());
        }
Beispiel #3
0
        void CreateData(ref vtkImageData data)
        {
            data.SetExtent(-25, 25, -25, 25, 0, 0);
#if VTK_MAJOR_VERSION_5
            data.SetNumberOfScalarComponents(1);
            data.SetScalarTypeToDouble();
#else
            data.AllocateScalars(VTK_DOUBLE, 1);
#endif
            int[] extent = data.GetExtent();

            for (int y = extent[2]; y <= extent[3]; y++)
            {
                for (int x = extent[0]; x <= extent[1]; x++)
                {
                    IntPtr   ptr   = data.GetScalarPointer(x, y, 0);
                    double[] pixel = new double[] { Math.Sqrt(Math.Pow(x, 2.0) + Math.Pow(y, 2.0)) };
                    Marshal.Copy(pixel, 0, ptr, 1);
                }
            }

            vtkXMLImageDataWriter writer = vtkXMLImageDataWriter.New();
            writer.SetFileName(@"c:\vtk\vtkdata-5.8.0\Data\testIsoContours.vti");
#if VTK_MAJOR_VERSION_5
            writer.SetInputConnection(data.GetProducerPort());
#else
            writer.SetInputData(data);
#endif
            writer.Write();
        }
Beispiel #4
0
        /// <summary>
        /// Calculates average columns from 3D volume. Obsolete.
        /// </summary>
        /// <param name="averages"></param>
        /// <param name="steps"></param>
        /// <param name="input"></param>
        /// <param name="n_tiles"></param>
        public static void average_tiles(out double[,,] averages, out int[] steps, vtkImageData input, int n_tiles = 16)
        {
            //Get dimensions
            int[] dims = input.GetExtent();
            int   h    = dims[1] - dims[0] + 1;
            int   w    = dims[3] - dims[2] + 1;
            int   d    = dims[5] - dims[4] + 1;

            //Input to byte array
            byte[] bytedata = DataTypes.vtkToByte(input);

            //Generate tile coordinates
            int N  = (int)Math.Sqrt(n_tiles);
            int wh = h / N;
            int ww = w / N;

            steps = new int[] { wh, ww };

            List <int[]> tiles = new List <int[]>();

            for (int kh = 0; kh < N; kh++)
            {
                for (int kw = 0; kw < N; kw++)
                {
                    int[] tmp = new int[] { kh *wh, (kh + 1) * wh, kw *ww, (kw + 1) * ww };
                    tiles.Add(tmp);
                }
            }

            //Iterate over tiles, and average the grayscale values

            //Empty array for averages
            double[,,] _averages = new double[N, N, d];
            //Number of elements
            N = wh * ww;
            foreach (int[] tile in tiles)
            {
                for (int z = 0; z < d; z++)
                {
                    Parallel.For(tile[0], tile[1], (int y) =>
                    {
                        Parallel.For(tile[2], tile[3], (int x) =>
                        {
                            int pos  = z * (h * w) + x * (h) + y;
                            byte val = bytedata[pos];
                            _averages[y / wh, x / ww, z] += (double)val;
                        });
                    });

                    _averages[(tile[1] - 1) / wh, (tile[3] - 1) / ww, z] /= (double)N;
                }
            }

            averages = _averages;
        }
Beispiel #5
0
        /// <summary>
        /// Removes surface artefacts from the sample.
        /// </summary>
        /// <param name="volume">Sample volume data.</param>
        /// <param name="points">Points for removal line.</param>
        /// <param name="axis">Axis of removal.</param>
        /// <returns>Sample data without artefacts</returns>
        public static vtkImageData remove_artefacts(vtkImageData volume, double[] points, int axis)
        {
            //Get input volume dimensions
            int[] dims = volume.GetExtent();
            int   h    = dims[1] - dims[0] + 1;
            int   w    = dims[3] - dims[2] + 1;
            int   d    = dims[5] - dims[4] + 1;

            Console.WriteLine("Got dims: {0},{1},{2}", h, w, d);
            //Convert volume to byte array
            byte[] bytedata = DataTypes.vtkToByte(volume);
            Console.WriteLine("Got bytedata");
            //Compute slope (k) and zero crossing (b) from given point for a line y=kx+b
            //Compute the slope of the line from points
            double slope = (points[3] - points[1]) / (points[2] - points[0]);
            //Compute zero crossing
            double b = points[3] - slope * points[2] - dims[4];

            Console.WriteLine("Got line equation");
            //Iterate over the data
            Parallel.For(0, h, (int y) =>
            {
                Parallel.For(0, w, (int x) =>
                {
                    //Compute extent for zeroing
                    int zstart = 0;
                    int zstop  = d;
                    if (axis == 0)
                    {
                        zstart = (int)((double)(x + dims[2]) * slope + b);
                        zstart = Math.Max(zstart, 0);
                    }
                    if (axis == 1)
                    {
                        zstart = (int)((double)(y + dims[0]) * slope + b);
                        zstart = Math.Max(zstart, 0);
                    }
                    //Iterate over z-axis
                    for (int z = zstart; z < zstop; z++)
                    {
                        int pos       = z * (h * w) + x * h + y;
                        bytedata[pos] = 0;
                    }
                });
            });
            Console.WriteLine("Zeroed");
            //Convert byte data back to vtkdata
            vtkImageData output = DataTypes.byteToVTK1D(bytedata, dims);

            return(output);
        }
Beispiel #6
0
        /// <summary>
        /// Calculates mean and standard deviation images from volume-of-interest
        /// along third axis (z).
        /// </summary>
        /// <param name="input">Input volume as vtkImageData.</param>
        /// <param name="meanImage">Mean 2D image.</param>
        /// <param name="stdImage">Standard deviation 2D image.</param>
        public static void MeanAndStd(vtkImageData input, out double[,] meanImage, out double[,] stdImage)
        {
            //Get data extent
            int[] ext  = input.GetExtent();
            int[] dims = new int[] { ext[3] - ext[2] + 1, ext[1] - ext[0] + 1, ext[5] - ext[4] + 1 };
            Console.WriteLine("Input shape: {0}, {1}, {2}".Format(dims[0], dims[1], dims[2]));
            // Convert to byte volume
            byte[] bytedata = DataTypes.vtkToByte(input);
            byte[,,] bytevolume = DataTypes.VectorToVolume(bytedata, dims);

            //int[] dims = new int[] { bytedata.GetLength(0), bytedata.GetLength(1), bytedata.GetLength(2) };
            double[,] mean = new double[dims[0], dims[1]];
            double[,] std  = new double[dims[0], dims[1]];

            Parallel.For(0, dims[0], i =>
            {
                Parallel.For(0, dims[1], j =>
                {
                    //double[] temp = new double[dims[2]]; // has to be initialized in the loop
                    double[] temp = new double[0]; // has to be initialized in the loop
                    for (int k = 0; k < dims[2]; k++)
                    {
                        //temp[k] = bytevolume[i, j, k];
                        if (bytevolume[i, j, k] > 0)
                        {
                            temp.Concatenate(bytevolume[i, j, k]);
                        }
                    }
                    if (temp.Length > 0)
                    {
                        mean[i, j] = temp.Average();
                        std[i, j]  =
                            Math.Sqrt(temp
                                      .Subtract(temp.Average())
                                      .Pow(2)
                                      .Sum()
                                      / (temp.Length - 1));
                    }
                    else
                    {
                        mean[i, j] = 0;
                        std[i, j]  = 0;
                    }
                });
            });
            meanImage = mean;
            stdImage  = std;
        }
Beispiel #7
0
        /// <summary>
        /// Calculates orientation of 2D slice. Obsolete.
        /// </summary>
        /// <param name="slice"></param>
        /// <param name="threshold"></param>
        /// <returns></returns>
        public static double find_slice_ori(vtkImageData slice, double threshold = 70.0)
        {
            //Get dimensions
            int[] dims = slice.GetExtent();
            int   h    = dims[1] - dims[0] + 1;
            int   w    = dims[3] - dims[2] + 1;

            //Convert slice to mat
            byte[] bytedata = DataTypes.vtkToByte(slice);


            List <int[]> _idx = new List <int[]>();

            byte[] cont = new byte[h * w];

            //for (int k = 0; k < cont.Length; k++)
            for (int k = 0; k < bytedata.Length; k++)
            {
                int _x = k / h;
                int _y = k % h;
                if ((double)bytedata[k] > threshold)
                {
                    _idx.Add(new int[] { _y, _x });
                    cont[k] = 255;
                }
            }

            Mat im = new Mat(w, h, MatType.CV_8UC1, cont);

            using (var window = new Window("Indices", image: im, flags: WindowMode.AutoSize))
            {
                Cv2.WaitKey();
            }

            //Convert list to double array
            double[][] idx = new double[_idx.Count()][];

            //Iterate over the list and collect indices to the array
            for (int k = 0; k < _idx.Count(); k++)
            {
                int[] _tmp = _idx.ElementAt(k);
                idx[k] = new double[] { _tmp[0], _tmp[1] };
            }

            double theta = find_ori_pca(idx, 0);

            return(theta);
        }
Beispiel #8
0
        /// <summary>
        /// Function for scaling sample data. Used in automatic rotation to reduce calculation time in gradient descent.
        /// </summary>
        /// <param name="input">Input volume data</param>
        /// <param name="scale">Scaling factor, e.g. 0.1 = downsampling with factor of 10.</param>
        /// <returns></returns>
        public static vtkImageData rescale_sample(vtkImageData input, double scale)
        {
            //Get sample dimensions
            int[] dims = input.GetExtent();

            vtkImageResample samplery = vtkImageResample.New();

            samplery.SetInput(input);
            samplery.SetOutputSpacing(input.GetSpacing()[0], input.GetSpacing()[1], input.GetSpacing()[2]);
            samplery.SetOutputOrigin(input.GetOrigin()[0], input.GetOrigin()[1], input.GetOrigin()[2]);
            samplery.SetOutputExtent((int)(scale * dims[0]), (int)(scale * dims[1]), dims[2], dims[3], dims[4], dims[5]);
            samplery.SetInterpolationModeToCubic();
            samplery.SetAxisMagnificationFactor(0, scale);
            samplery.Update();

            vtkImageResample samplerx = vtkImageResample.New();

            samplerx.SetInputConnection(samplery.GetOutputPort());
            samplerx.SetOutputSpacing(samplery.GetOutputSpacing()[0], samplery.GetOutputSpacing()[1], samplery.GetOutputSpacing()[2]);
            samplerx.SetOutputOrigin(samplery.GetOutputOrigin()[0], samplery.GetOutputOrigin()[1], samplery.GetOutputOrigin()[2]);
            samplerx.SetOutputExtent((int)(scale * dims[0]), (int)(scale * dims[1]), (int)(scale * dims[2]), (int)(scale * dims[3]), dims[4], dims[5]);
            samplerx.SetInterpolationModeToCubic();
            samplerx.SetAxisMagnificationFactor(1, scale);
            samplerx.Update();

            vtkImageResample samplerz = vtkImageResample.New();

            samplerz.SetInputConnection(samplerx.GetOutputPort());
            samplerz.SetOutputSpacing(samplerx.GetOutputSpacing()[0], samplerx.GetOutputSpacing()[1], samplerx.GetOutputSpacing()[2]);
            samplerz.SetOutputOrigin(samplerx.GetOutputOrigin()[0], samplerx.GetOutputOrigin()[1], samplerx.GetOutputOrigin()[2]);
            samplerz.SetOutputExtent((int)(scale * dims[0]), (int)(scale * dims[1]), (int)(scale * dims[2]),
                                     (int)(scale * dims[3]), (int)(scale * dims[4]), (int)(scale * dims[5]));
            samplerz.SetInterpolationModeToCubic();
            samplerz.SetAxisMagnificationFactor(2, scale);
            samplerz.Update();

            vtkImageData output = vtkImageData.New();

            output.DeepCopy(samplerz.GetOutput());

            samplerz.Dispose();
            samplerx.Dispose();
            samplery.Dispose();

            return(output);
        }
Beispiel #9
0
        /// <summary>
        /// Create scalar copy of vtkImageData.
        /// </summary>
        /// <param name="data">Input data.</param>
        /// <returns>Copied data.</returns>
        public static vtkImageData scalarCopy(vtkImageData data)
        {
            /*DEPRECATED!!*/
            //Get data extent
            int[]        dims    = data.GetExtent();
            vtkImageData newdata = vtkImageData.New();

            newdata.SetExtent(dims[0], dims[1], dims[2], dims[3], dims[4], dims[5]);
            for (int h = dims[0]; h <= dims[1]; h++)
            {
                for (int w = dims[2]; w <= dims[3]; w++)
                {
                    for (int d = dims[4]; d <= dims[5]; d++)
                    {
                        double scalar = data.GetScalarComponentAsDouble(h, w, d, 0);
                        newdata.SetScalarComponentFromDouble(h, w, d, 0, scalar);
                    }
                }
            }
            return(newdata);
        }
Beispiel #10
0
        /// <summary>
        /// Converts 3D vtkImageData to 1D byte array.
        /// </summary>
        /// <param name="vtkdata">Input data.</param>
        /// <returns>Converted 1D array of vtkImageData.</returns>
        public static byte[] vtkToByte(vtkImageData vtkdata)
        {
            //Get vtk data dimensions
            int[] extent = vtkdata.GetExtent();
            int[] dims   = new int[] { extent[1] - extent[0] + 1, extent[3] - extent[2] + 1, extent[5] - extent[4] + 1 };
            //New byte array for conversions
            byte[] bytedata = new byte[dims[0] * dims[1] * dims[2]];
            //pin bytedata to memory
            GCHandle pinnedArray = GCHandle.Alloc(bytedata, GCHandleType.Pinned);
            //Get pointer to pinned array
            IntPtr ptr = pinnedArray.AddrOfPinnedObject();
            //VTK exporter
            vtkImageExport exporter = vtkImageExport.New();

            exporter.SetInput(vtkdata);
            exporter.Update();

            //Export data to byte array
            exporter.Export(ptr);
            //Free pinned array
            pinnedArray.Free();
            //Return byte array
            return(bytedata);
        }
Beispiel #11
0
        /// <summary>
        /// Calculates loss function for gradient descent.
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static double circle_loss(vtkImageData input)
        {
            //Get dimensions
            int[] dims = input.GetExtent();
            int   h    = dims[1] - dims[0] + 1;
            int   w    = dims[3] - dims[2] + 1;
            int   d    = dims[5] - dims[4] + 1;

            //Get non zero indices form projection image
            byte[] bytedata = DataTypes.vtkToByte(input);
            byte[] surf     = new byte[h * w];
            Parallel.For(0, h, (int ky) =>
            {
                Parallel.For(0, w, (int kx) =>
                {
                    for (int kz = d - 1; kz > 0; kz -= 1)
                    {
                        int pos = kz * (h * w) + kx * h + ky;
                        int val = bytedata[pos];
                        if (val > 70.0)
                        {
                            surf[ky * w + kx] = 255;
                            break;
                        }
                    }
                });
            });

            //Get nonzero indices
            Mat surfcv = new Mat(h, w, MatType.CV_8UC1, surf);

            //Find largest blob
            surfcv = Functions.largest_connected_component(surfcv);

            //Indices
            Mat nonzero = surfcv.FindNonZero();

            //Fit circle
            Point2f center; float R;

            nonzero.MinEnclosingCircle(out center, out R);
            //Generate a circle
            byte[] circle = new byte[h * w];
            Parallel.For(0, h, (int ky) =>
            {
                Parallel.For(0, w, (int kx) =>
                {
                    float val = (ky - center.Y) * (ky - center.Y) + (kx - center.X) * (kx - center.X);
                    if (val < R * R)
                    {
                        circle[ky * w + kx] = 255;
                    }
                });
            });

            //Get dice score
            double dice = Functions.dice_score_2d(surf, circle);

            surfcv.Dispose();
            nonzero.Dispose();
            bytedata = null;

            return(1 - dice);
        }
Beispiel #12
0
        /// <summary>
        /// Calculates mean and standard deviation images from volume-of-interest. Obsolete.
        /// </summary>
        /// <param name="output"></param>
        /// <param name="mu"></param>
        /// <param name="std"></param>
        /// <param name="input"></param>
        /// <param name="depth"></param>
        /// <param name="threshold"></param>
        public static void get_voi_mu_std(out vtkImageData output, out double[,] mu, out double[,] std, vtkImageData input, int depth, double threshold = 70.0)
        {
            //Get data extent
            int[] dims = input.GetExtent();
            int   h    = dims[1] - dims[0] + 1;
            int   w    = dims[3] - dims[2] + 1;
            int   d    = dims[5] - dims[4] + 1;

            //Compute strides
            int stridew = 1;
            int strideh = w;
            int strided = h * w;

            byte[] bytedata = DataTypes.vtkToByte(input);
            byte[] voidata  = new byte[bytedata.Length];

            double[,] _mu  = new double[h, w];
            double[,] _std = new double[h, w];

            //Get voi indices
            Parallel.For(24, h - 24, (int y) =>
            {
                Parallel.For(24, w - 24, (int x) =>
                {
                    int start = d - 1;
                    int stop  = 0;
                    //Compute mean
                    for (int z = d - 1; z > 0; z -= 1)
                    {
                        int pos    = z * strided + y * strideh + x * stridew;
                        double val = (double)bytedata[pos];
                        if (val >= threshold)
                        {
                            start = z;
                            stop  = Math.Max(z - depth, 0);
                            //Compute mean and std
                            for (int zz = start; zz > stop; zz -= 1)
                            {
                                int newpos      = zz * strided + y * strideh + x * stridew;
                                double newval   = (double)bytedata[newpos];
                                voidata[newpos] = (byte)newval;
                                _mu[y, x]       = newval / (double)depth;
                            }

                            for (int zz = start; zz > stop; zz -= 1)
                            {
                                int newpos    = zz * strided + y * strideh + x * stridew;
                                double newval = (double)bytedata[newpos];
                                _std[y, x]   += ((double)newval - _mu[y, x]) * ((double)newval - _mu[y, x]);
                            }

                            _std[y, x] = Math.Pow(_std[y, x] / (depth - 1), 0.5);
                            break;
                        }
                    }
                });
            });

            mu     = _mu;
            std    = _std;
            output = vtkImageData.New();
            //Copy voi data to input array
            vtkUnsignedCharArray charArray = vtkUnsignedCharArray.New();
            //Pin byte array
            GCHandle pinnedArray = GCHandle.Alloc(voidata, GCHandleType.Pinned);

            //Set character array input
            charArray.SetArray(pinnedArray.AddrOfPinnedObject(), h * w * d, 1);
            //Set vtkdata properties and connect array
            //Data from char array
            output.GetPointData().SetScalars(charArray);
            //Number of scalars/pixel
            output.SetNumberOfScalarComponents(1);
            //Data extent, 1st and last axis are swapped from the char array
            //Data is converted back to original orientation
            output.SetExtent(dims[0], dims[1], dims[2], dims[3], dims[4], dims[5]);
            //Scalar type
            output.SetScalarTypeToUnsignedChar();
            output.Update();
        }
Beispiel #13
0
        public static vtkImageData SWFPSuppression(vtkImageData BCI, int[] extent, double threshold = 0.7 * 255.0, int min = 0, int max = 650, int step = 4, int ws = 50, double wt = 20.0, double minones = 192.0)
        {
            //Get dimensions
            int[] dims = BCI.GetExtent();
            int   h    = dims[1] - dims[0] + 1;
            int   w    = dims[3] - dims[2] + 1;
            int   d    = dims[5] - dims[4] + 1;

            //Make array of extents
            List <int[]> regions = new List <int[]>();

            for (int k1 = 0; k1 < 4; k1++)
            {
                for (int k2 = 0; k2 < 4; k2++)
                {
                    int   step1 = (extent[1] - extent[0] + 1) / 8;
                    int   step2 = (extent[3] - extent[2] + 1) / 8;
                    int[] _tmp  = new int[] { extent[0] + k1 * step1, extent[0] + (k1 + 1) * step1, extent[2] + k2 * step2, extent[2] + (k2 + 1) * step2 };
                    regions.Add(_tmp);
                    Console.WriteLine("Region:");
                    Console.WriteLine("{0},{1},{2},{3}", _tmp[0], _tmp[1], _tmp[2], _tmp[3]);
                }
            }

            //Get byte data from input samples
            byte[]        BCIByte = DataTypes.vtkToByte(BCI);
            List <byte[]> sums    = new List <byte[]>();

            //Itereate over pixels
            foreach (int[] region in regions)
            {
                byte[] tmp = new byte[max - min];
                for (int k = min; k < max; k += step)
                {
                    int w1 = k; int w2 = w1 + ws;

                    int roisum = 0;

                    Parallel.For(w1, w2, (int kz) =>
                    {
                        Parallel.For(region[0], region[1], (int ky) =>
                        {
                            Parallel.For(region[2], region[3], (int kx) =>
                            {
                                int pos = kz * (h * w) + ky * w + kx;
                                if ((double)BCIByte[pos] > threshold)
                                {
                                    roisum += (int)BCIByte[pos];
                                }
                            });
                        });
                    });

                    //Set sliding window index at k to 1 if enough non-zero pixels were found
                    if (((double)roisum / (minones * minones)) > wt)
                    {
                        tmp[k] = 1;
                    }


                    //Check if there's a drop between consecutive results
                    if (k > min + step && tmp[k] == 0 && tmp[k - step] == 1)
                    {
                        sums.Add(tmp);
                        break;
                    }
                    //Otherswise append the data at the end
                    else
                    {
                        if (k + step >= max)
                        {
                            sums.Add(tmp);
                        }
                    }
                }
            }

            int[] idx = new int[sums.Count];

            //Scan sums vector find last non-zero index
            int c = 0;

            foreach (byte[] sum in sums)
            {
                for (int k = sum.Length - 1; k >= 0; k -= 1)
                {
                    if (sum[k] == 1)
                    {
                        idx[c] = k;
                        c++;
                        break;
                    }
                }
            }

            byte[,,] output = new byte[d, h, w];

            //Set array indices below idx to outputvalues
            c = 0;
            foreach (int[] region in regions)
            {
                int _idx = idx[c];
                Console.WriteLine("Max idx: {0} | Height: {1}", _idx, d);
                int z = 0;
                if (_idx == 0)
                {
                    z = d;
                }
                else
                {
                    z = Math.Min(_idx + 20, d);
                }
                Parallel.For(0, z, (int kz) =>
                {
                    Parallel.For(region[0], region[1], (int ky) =>
                    {
                        Parallel.For(region[2], region[3], (int kx) =>
                        {
                            int pos            = kz * (h * w) + ky * (w) + kx;
                            output[kz, ky, kx] = BCIByte[pos];
                        });
                    });
                });
                c++;
            }

            return(DataTypes.byteToVTK(output));
        }
Beispiel #14
0
        /// <summary>
        /// Method to calculate sample orientation using gradient descent.
        /// </summary>
        /// <param name="data"></param>
        /// <param name="alpha"></param>
        /// <param name="h"></param>
        /// <param name="n_iter"></param>
        /// <returns></returns>
        public static double[] grad_descent(vtkImageData data, double alpha = 0.5, double h = 5.0, int n_iter = 60)
        {
            //Starting orientation
            double[] ori  = new double[2];
            int[]    dims = data.GetExtent();
            int      y    = dims[1] - dims[0] + 1;
            int      x    = dims[3] - dims[2] + 1;
            int      z    = dims[5] - dims[4] + 1;

            for (int k = 1; k < n_iter + 1; k++)
            {
                //Iintialize gradient
                double[] grads = new double[2];

                //Rotate the sample
                vtkImageData rotated1 = rotate_sample(data, ori[0] + h, 0, 1);
                if (ori[1] != 0)
                {
                    rotated1 = rotate_sample(rotated1, ori[1], 1, 1);
                }

                vtkImageData rotated2 = rotate_sample(data, ori[0] - h, 0, 1);
                if (ori[1] != 0)
                {
                    rotated2 = rotate_sample(rotated2, ori[1], 1, 1);
                }

                //Get losses
                double d1 = circle_loss(rotated1);
                double d2 = circle_loss(rotated2);

                //Compute gradient
                grads[0] = (d1 - d2) / (2 * h);

                //Rotate the sample
                vtkImageData rotated3 = rotate_sample(data, ori[1] + h, 1, 1);
                if (ori[0] != 0)
                {
                    rotated3 = rotate_sample(rotated3, ori[0], 0, 1);
                }

                vtkImageData rotated4 = rotate_sample(data, ori[1] - h, 1, 1);
                if (ori[0] != 0)
                {
                    rotated4 = rotate_sample(rotated4, ori[0], 0, 1);
                }

                //Get losses
                double d3 = circle_loss(rotated3);
                double d4 = circle_loss(rotated4);

                //Compute gradient
                grads[1] = (d3 - d4) / (2 * h);

                //Update the orientation
                ori[0] -= Math.Sign(grads[0]) * alpha;
                ori[1] -= Math.Sign(grads[1]) * alpha;

                if (k % n_iter / 2 == 0)
                {
                    alpha /= 2;
                }

                rotated1.Dispose();
                rotated2.Dispose();
                rotated3.Dispose();
                rotated4.Dispose();
            }

            return(ori);
        }
Beispiel #15
0
        /// <summary>
        /// Otsu thresholding in 3D.
        /// </summary>
        /// <param name="input"></param>
        /// <param name="axis"></param>
        /// <param name="threshold"></param>
        /// <returns></returns>
        public static vtkImageData otsu3D(vtkImageData input, int axis = 0, double threshold = 60.0)
        {
            //Get dimensions
            int[] dims = input.GetExtent();
            int   h    = dims[1] - dims[0] + 1;
            int   w    = dims[3] - dims[2] + 1;
            int   d    = dims[5] - dims[4] + 1;

            //Convert to byte array
            byte[] bytedata = DataTypes.vtkToByte(input);
            byte[] output   = new byte[bytedata.Length];

            //Iterate over axis
            if (axis == 0)
            {
                for (int x = 0; x < w; x++)
                {
                    byte[,] plane = new byte[d, h];
                    Parallel.For(0, h, (int y) =>
                    {
                        Parallel.For(0, d, (int z) =>
                        {
                            int pos     = z * (h * w) + y * w + x;
                            plane[z, y] = bytedata[pos];
                        });
                    });

                    //Convert 2D byte array to opencv Mat
                    Mat image = new Mat(d, h, MatType.CV_8UC1, plane);
                    Mat BW    = image.Threshold(threshold, 255.0, ThresholdTypes.Otsu);

                    IntPtr pointer = BW.Data;
                    byte[] tmp     = new byte[h * d];
                    Marshal.Copy(pointer, tmp, 0, h * d);
                    Parallel.For(0, h, (int y) =>
                    {
                        Parallel.For(0, d, (int z) =>
                        {
                            int tmppos  = z * h + y;
                            int pos     = z * (h * w) + y * w + x;
                            output[pos] = tmp[tmppos];
                        });
                    });
                }
            }
            else
            {
                for (int y = 0; y < h; y++)
                {
                    byte[,] plane = new byte[d, w];
                    Parallel.For(0, w, (int x) =>
                    {
                        Parallel.For(0, d, (int z) =>
                        {
                            int pos     = z * (h * w) + y * w + x;
                            plane[z, x] = bytedata[pos];
                        });
                    });

                    //Convert 2D byte array to opencv Mat
                    Mat image = new Mat(d, w, MatType.CV_8UC1, plane);
                    Mat BW    = image.Threshold(threshold, 255.0, ThresholdTypes.Otsu);

                    IntPtr pointer = BW.Data;
                    byte[] tmp     = new byte[w * d];
                    Marshal.Copy(pointer, tmp, 0, w * d);
                    Parallel.For(0, w, (int x) =>
                    {
                        Parallel.For(0, d, (int z) =>
                        {
                            int tmppos  = z * w + x;
                            int pos     = z * (h * w) + y * w + x;
                            output[pos] = tmp[tmppos];
                        });
                    });
                }
            }

            return(DataTypes.byteToVTK1D(output, dims));
        }
Beispiel #16
0
        /// <summary>
        /// Method to calculate mean and standard deviation images from 3D volume-of-interest along depth-axis.
        /// </summary>
        /// <param name="mean">Resulting mean image.</param>
        /// <param name="sd">Resulting standard deviation image.</param>
        /// <param name="VOI">Input volume-of-interest.</param>
        /// <param name="voi_depth"></param>
        /// <param name="crop_size"></param>
        public static void get_mean_sd(out double[,] mean, out double[,] sd, vtkImageData VOI, int voi_depth = 0, int crop_size = 0)
        {
            //Get input extent
            int[] dims = VOI.GetExtent();

            //Compute dimensions
            int h = dims[1] - dims[0] + 1;
            int w = dims[3] - dims[2] + 1;
            int d = dims[5] - dims[4] + 1;

            //Get byte data from vtkImageData
            byte[] bytedata = DataTypes.vtkToByte(VOI);

            double[,] mu = new double[h - crop_size * 2, w - crop_size * 2];
            byte[,] muim = new byte[h - crop_size * 2, w - crop_size * 2];
            int[,] Ns    = new int[h - crop_size * 2, w - crop_size * 2];

            //Set void depth
            if (voi_depth == 0)
            {
                voi_depth = d;
            }

            //Iterate over data and compute mean image
            for (int y = crop_size; y < h - crop_size; y++)
            {
                for (int x = crop_size; x < w - crop_size; x++)
                {
                    double sum = 0.0;
                    int    N   = 0;
                    for (int z = d - 1; z >= 0; z -= 1)
                    {
                        //Compute position
                        int pos = z * (h * w) + x * h + y;
                        //Get byte value
                        byte val = bytedata[pos];
                        //Add to sum
                        sum += (double)val;
                        //If value is nonzero, increase count
                        if (val > 0)
                        {
                            N += 1;
                        }
                        //If count is equal to VOI depth, break
                        if (N == voi_depth)
                        {
                            break;
                        }
                    }
                    mu[y - crop_size, x - crop_size]   = sum / ((double)N + 1e-9);
                    muim[y - crop_size, x - crop_size] = (byte)mu[y - crop_size, x - crop_size];
                    Ns[y - crop_size, x - crop_size]   = N;
                }
            }

            double[,] sigma = new double[h - crop_size * 2, w - crop_size * 2];
            byte[,] sdim    = new byte[h - crop_size * 2, w - crop_size * 2];

            //Iterate over data and compute sd image
            for (int y = crop_size; y < h - crop_size; y++)
            {
                for (int x = crop_size; x < w - crop_size; x++)
                {
                    double sum = 0.0;
                    int    N   = 0;
                    for (int z = d - 1; z >= 0; z -= 1)
                    {
                        //Compute position
                        int pos = z * (h * w) + x * h + y;
                        //Get byte value
                        byte val = bytedata[pos];
                        //If value is non-zero, subtract from value and square
                        if (val > 0)
                        {
                            double tmp = (double)val - mu[y - crop_size, x - crop_size];
                            sum += tmp * tmp;
                            N   += 1;
                        }
                        //If count is equal to VOI depth, break
                        if (N == voi_depth)
                        {
                            break;
                        }
                    }
                    sigma[y - crop_size, x - crop_size] = Math.Sqrt(sum / ((double)Ns[y - crop_size, x - crop_size] - 1.0 + 1e-9));
                    if (N == 0)
                    {
                        sigma[y - crop_size, x - crop_size] = 0.0;
                    }
                    sdim[y - crop_size, x - crop_size] = (byte)sigma[y - crop_size, x - crop_size];
                }
            }

            //Return mu and sd
            mean = mu;
            sd   = sigma;
        }
Beispiel #17
0
        /// <summary>
        /// Rotates 3D vtk volume around x and y axes.
        /// </summary>
        /// <param name="input"></param>
        /// <param name="angle"></param>
        /// <param name="axis"></param>
        /// <param name="out_extent"></param>
        /// <returns></returns>
        public static vtkImageData rotate_sample(vtkImageData input, double angle, int axis, int out_extent = 0)
        {
            //get input data dimensions
            int[] dims = input.GetExtent();
            //Compute centers
            int[] centers = new int[] { (dims[1] + dims[0]) / 2, (dims[3] + dims[2]) / 2, (dims[5] + dims[4]) / 2 };

            //Set rotation axis
            int[] axes = new int[3];
            axes[axis] = 1;

            int[] new_dims    = new int[] { dims[0], dims[1], dims[2], dims[3], dims[4], dims[5] };
            int[] new_centers = new int[] { centers[0], centers[1], centers[2] };

            //Compute new sample dimensions
            if (axis == 0)
            {
                new_dims[3] = (int)(Math.Cos(Math.Abs(angle / 180) * Math.PI) * new_dims[3] + Math.Sin(Math.Abs(angle / 180) * Math.PI) * new_dims[5]);
                new_dims[5] = (int)(Math.Sin(Math.Abs(angle / 180) * Math.PI) * new_dims[3] + Math.Cos(Math.Abs(angle / 180) * Math.PI) * new_dims[5]);

                new_centers[1] = (Math.Abs(new_dims[3]) + Math.Abs(new_dims[2])) / 2;
                new_centers[2] = (Math.Abs(new_dims[5]) + Math.Abs(new_dims[4])) / 2;
            }
            if (axis == 1)
            {
                new_dims[1] = (int)(Math.Cos(Math.Abs(angle / 180) * Math.PI) * new_dims[1] + Math.Sin(Math.Abs(angle / 180) * Math.PI) * new_dims[5]);
                new_dims[5] = (int)(Math.Sin(Math.Abs(angle / 180) * Math.PI) * new_dims[1] + Math.Cos(Math.Abs(angle / 180) * Math.PI) * new_dims[5]);

                new_centers[0] = (Math.Abs(new_dims[0]) + Math.Abs(new_dims[1])) / 2;
                new_centers[2] = (Math.Abs(new_dims[5]) + Math.Abs(new_dims[4])) / 2;
            }


            //Image transformation
            vtkTransform transform = vtkTransform.New();

            transform.Translate(centers[0], centers[1], centers[2]);
            transform.RotateWXYZ(angle, axes[0], axes[1], axes[2]);
            if (out_extent == 0)
            {
                transform.Translate(-centers[0], -centers[1], -centers[2]);
            }
            else
            {
                transform.Translate(-new_centers[0], -new_centers[1], -new_centers[2]);
            }

            //Console.ReadKey();

            transform.Update();

            //Compute new data extent
            int[] diff = new int[] { new_dims[1] - dims[1], new_dims[3] - dims[3], new_dims[5] - dims[5] };
            new_dims[0] += diff[0] / 2; new_dims[1] -= diff[0] / 2;
            new_dims[2] += diff[1] / 2; new_dims[3] -= diff[1] / 2;
            new_dims[4] += diff[2] / 2; new_dims[5] -= diff[2] / 2;



            //Image reslicing
            vtkImageReslice rotater = vtkImageReslice.New();

            rotater.SetInput(input);
            rotater.SetInformationInput(input);
            rotater.SetResliceTransform(transform);
            rotater.SetInterpolationModeToCubic();
            //rotater.SetInterpolationModeToLinear();
            if (out_extent == 1)
            {
                rotater.SetOutputSpacing(input.GetSpacing()[0], input.GetSpacing()[1], input.GetSpacing()[2]);
                rotater.SetOutputOrigin(input.GetOrigin()[0], input.GetOrigin()[1], input.GetOrigin()[2]);
                rotater.SetOutputExtent(new_dims[0], new_dims[1], new_dims[2], new_dims[3], new_dims[4], new_dims[5]);
            }
            rotater.Update();

            vtkImageData output = vtkImageData.New();

            output.DeepCopy(rotater.GetOutput());

            rotater.Dispose();
            transform.Dispose();

            return(output);
        }
Beispiel #18
0
        public static vtkImageData OCVFPSuppression(vtkImageData BCI, vtkImageData sample, int axis = 0, double BC_threshold = 0.7 * 255.0, double sample_threshold = 80)
        {
            //Get dimensions
            int[] dims = BCI.GetExtent();

            //Get byte data from input samples
            byte[] BCIByte    = DataTypes.vtkToByte(BCI);
            byte[] SampleByte = DataTypes.vtkToByte(sample);

            //Output byte array
            byte[,,] OutByte = new byte[(dims[1] - dims[0] + 1), (dims[3] - dims[2] + 1), (dims[5] - dims[4] + 1)];

            //Loop parameters
            int start = 0; int stop = 0; int h = 0; int w = 0; int strideh = 0; int stridew = 0; int pos = 0;

            if (axis == 0)
            {
                start   = dims[0];
                stop    = dims[1] + 1;
                h       = dims[5] + 1;
                w       = dims[3] + 1;
                strideh = (dims[1] + 1) * (dims[3] + 1);
                stridew = 1;
            }
            if (axis == 1)
            {
                start   = dims[2];
                stop    = dims[3] + 1;
                h       = dims[5] + 1;
                w       = dims[1] + 1;
                strideh = (dims[1] + 1) * (dims[3] + 1);
                stridew = (dims[3] + 1);
            }
            if (axis == 2)
            {
                start   = dims[4];
                stop    = dims[5] + 1;
                h       = dims[1] + 1;
                w       = dims[3] + 1;
                strideh = dims[3] + 1;
                stridew = 1;
            }

            //Iterate over samples in parallel
            Parallel.For(start, stop, (int k) =>
            {
                //Get slices to OpenCV matrices
                Mat BCMat         = new Mat(h, w, MatType.CV_8UC1);
                var BCIndexer     = BCMat.GetGenericIndexer <Vec2b>();
                Mat SampleMat     = new Mat(h, w, MatType.CV_8UC1);
                var SampleIndexer = SampleMat.GetGenericIndexer <Vec2b>();

                //Iterate over indices
                Parallel.For(0, h, (int kh) =>
                {
                    Parallel.For(0, w, (int kw) =>
                    {
                        //Current slice index
                        if (axis == 0)
                        {
                            pos = k * (dims[1] + 1);
                        }
                        ;
                        if (axis == 1)
                        {
                            pos = k;
                        }
                        ;
                        if (axis == 2)
                        {
                            pos = k * (dims[1] + 1) * (dims[3] + 1);
                        }
                        ;

                        //Current index
                        int cur = pos + kh * strideh + kw * stridew;

                        //Get values
                        Vec2b bcval = BCIndexer[kh, kw];
                        bcval.Item0 = BCIByte[cur];
                        bcval.Item1 = BCIByte[cur];

                        Vec2b sampleval = SampleIndexer[kh, kw];
                        sampleval.Item0 = SampleByte[cur];
                        sampleval.Item1 = SampleByte[cur];

                        //Update matrices
                        BCIndexer[kh, kw]     = bcval;
                        SampleIndexer[kh, kw] = sampleval;
                    });
                });

                if (k == 500)
                {
                    using (var window = new Window("BCMat", image: BCMat, flags: WindowMode.AutoSize))
                    {
                        Cv2.WaitKey();
                    }

                    using (var window = new Window("Sample", image: SampleMat, flags: WindowMode.AutoSize))
                    {
                        Cv2.WaitKey();
                    }
                }



                //Get binary masks
                Mat BCBW     = BCMat.Threshold(BC_threshold, 255.0, ThresholdTypes.Binary);
                Mat SampleBW = SampleMat.Threshold(sample_threshold, 255.0, ThresholdTypes.Binary);

                if (k == 500)
                {
                    using (var window = new Window("BCMat", image: BCBW, flags: WindowMode.AutoSize))
                    {
                        Cv2.WaitKey();
                    }

                    using (var window = new Window("Sample", image: SampleBW, flags: WindowMode.AutoSize))
                    {
                        Cv2.WaitKey();
                    }
                }

                //Subtract BCI mask from sample mask
                Mat D = SampleBW - BCBW;
                if (k == 500)
                {
                    using (var window = new Window("D", image: D, flags: WindowMode.AutoSize))
                    {
                        Cv2.WaitKey();
                    }
                }
                //Closing

                //Generate structuring element
                InputArray element = InputArray.Create(new Mat(1, 50, MatType.CV_8UC1));

                D = D.Dilate(element);
                D = D.Erode(element);

                if (k == 500)
                {
                    using (var window = new Window("D", image: D, flags: WindowMode.AutoSize))
                    {
                        Cv2.WaitKey();
                    }
                }

                //Subtract closed mask from BCI mask
                BCBW = BCBW - D;

                if (k == 500)
                {
                    using (var window = new Window("Cleaned BC", image: BCBW, flags: WindowMode.AutoSize))
                    {
                        Cv2.WaitKey();
                    }
                }

                //Dilate
                BCBW = BCBW.Dilate(element);

                if (k == 500)
                {
                    using (var window = new Window("Dilated BC", image: BCBW, flags: WindowMode.AutoSize))
                    {
                        Cv2.WaitKey();
                    }
                }

                //Multiply BCI matrix with the mask
                BCMat     = BCMat.Mul(BCBW);
                BCIndexer = BCMat.GetGenericIndexer <Vec2b>();

                if (k == 500)
                {
                    using (var window = new Window("Dilated BC", image: BCBW, flags: WindowMode.AutoSize))
                    {
                        Cv2.WaitKey();
                    }
                }

                //Return the elements to output byte array
                Parallel.For(0, h, (int kh) =>
                {
                    Parallel.For(0, w, (int kw) =>
                    {
                        //Get value
                        Vec2b bcval = BCIndexer[kh, kw];

                        //Update outputarray
                        if (axis == 0 && bcval.Item0 > BC_threshold)
                        {
                            OutByte[kh, k, kw] = 255;
                        }
                        ;
                        if (axis == 1 && bcval.Item0 > BC_threshold)
                        {
                            OutByte[kh, kw, k] = 255;
                        }
                        ;
                        if (axis == 2 && bcval.Item0 > BC_threshold)
                        {
                            OutByte[k, kh, kw] = 255;
                        }
                        ;
                    });
                });
            });

            //Convert outputarray to VTK data
            return(DataTypes.byteToVTK(OutByte));
        }
Beispiel #19
0
        /// <summary>
        /// Calculates center of volume data along z-axis.
        /// </summary>
        /// <param name="stack"></param>
        /// <param name="threshold"></param>
        /// <param name="zrange"></param>
        /// <returns></returns>
        public static int[] find_center(vtkImageData stack, double threshold = 70.0, int[] zrange = null)
        {
            //Get byte data
            byte[] bytedata = DataTypes.vtkToByte(stack);

            //Get data dimensions
            int[] dims = stack.GetExtent();
            int   h    = dims[1] - dims[0] + 1;
            int   w    = dims[3] - dims[2] + 1;
            int   d    = dims[5] - dims[4] + 1;
            //Get strides
            int stride_d = h * w;
            int stride_h = 1;
            int stride_w = h;

            //Empty array for binary mask
            byte[,] BW = new byte[h, w];

            //z range
            int zstart = 0; int zstop = 0;

            if (zrange == null)
            {
                zstart = 0;
                zstop  = d;
            }
            else
            {
                zstart = zrange[0];
                zstop  = zrange[1];
            }

            Parallel.For(0, h, (int y) =>
            {
                Parallel.For(0, w, (int x) =>
                {
                    for (int z = zstart; z < zstop; z++)
                    {
                        int pos  = (z * stride_d) + (x * stride_w) + (y * stride_h);
                        byte val = bytedata[pos];
                        if (val > threshold)
                        {
                            BW[y, x] = 255;
                        }
                    }
                });
            });

            Mat sumim = new Mat(h, w, MatType.CV_8UC1, BW);

            //Get largest binary object
            sumim = Functions.largest_connected_component(sumim);

            int x1; int x2; int y1; int y2;

            Functions.get_bbox(out x1, out x2, out y1, out y2, sumim);

            //Compute center
            int[] center = new int[2];
            center[0] = (y2 + y1) / 2 + dims[0];
            center[1] = (x2 + x1) / 2 + dims[2];

            return(center);
        }
Beispiel #20
0
        /// <summary>
        /// Scans the input mask slice by slice and selects the largest binary component of each slice.
        /// Return cleaned mask as vtkImageData
        /// </summary>
        /// <param name="input"></param>
        /// <param name="extent"></param>
        /// <param name="threshold"></param>
        /// <param name="axes"></param>
        /// <returns></returns>
        public static vtkImageData FalsePositiveSuppresion(vtkImageData input, int[] extent, double threshold, int axis, double scale = 1.0)
        {
            //Slice extractor
            vtkExtractVOI slicer = vtkExtractVOI.New();
            //Permuter
            vtkImagePermute permuter = vtkImagePermute.New();
            //List of outputs
            List <byte[, , ]> outputs = new List <byte[, , ]>();
            //List of output orientations
            List <int[]> orientations = new List <int[]>();

            //vtkImageData size
            int[] full_extent = input.GetExtent();

            //Set range for slices
            int start = 0, stop = 0;

            int[] size      = new int[2];
            int[] outextent = new int[4];
            if (axis == 0)
            {
                start     = extent[0];
                stop      = extent[1];
                size      = new int[] { extent[3] - extent[2] + 1, extent[5] - extent[4] + 1 };
                outextent = new int[] { extent[2], extent[3] + 1, extent[4], extent[5] + 1 };
            }
            if (axis == 1)
            {
                start     = extent[2];
                stop      = extent[3];
                size      = new int[] { extent[1] - extent[0] + 1, extent[5] - extent[4] + 1 };
                outextent = new int[] { extent[0], extent[1] + 1, extent[4], extent[5] + 1 };
            }
            if (axis == 2)
            {
                start     = extent[4];
                stop      = extent[5];
                size      = new int[] { extent[1] - extent[0] + 1, extent[3] - extent[2] + 1 };
                outextent = new int[] { extent[0], extent[1] + 1, extent[2], extent[3] + 1 };
            }

            //Temporary array for output
            byte[,,] output = new byte[full_extent[1] + 1, full_extent[3] + 1, full_extent[5] + 1];
            int[] outsize = new int[] { size[0], size[1], stop - start + 1 };
            //Loop over current axis
            for (int k = start; k < stop; k++)
            {
                byte[] bytedata = new byte[size[0] * size[1]];
                //Select slice
                if (axis == 0)
                {
                    slicer.Dispose();
                    slicer = vtkExtractVOI.New();
                    slicer.SetInput(input);
                    slicer.SetVOI(k, k, extent[2], extent[3], extent[4], extent[5]);
                    slicer.Update();
                    permuter.Dispose();
                    permuter = vtkImagePermute.New();
                    permuter.SetInput(slicer.GetOutput());
                    permuter.SetFilteredAxes(1, 2, 0);
                    permuter.Update();
                }
                if (axis == 1)
                {
                    slicer.Dispose();
                    slicer = vtkExtractVOI.New();
                    slicer.SetInput(input);
                    slicer.SetVOI(extent[0], extent[1], k, k, extent[4], extent[5]);
                    slicer.Update();
                    permuter.Dispose();
                    permuter = vtkImagePermute.New();
                    permuter.SetInput(slicer.GetOutput());
                    permuter.SetFilteredAxes(0, 2, 1);
                    permuter.Update();
                }
                if (axis == 2)
                {
                    slicer.Dispose();
                    slicer = vtkExtractVOI.New();
                    slicer.SetInput(input);
                    slicer.SetVOI(extent[0], extent[1], extent[2], extent[3], k, k);
                    slicer.Update();
                    permuter.Dispose();
                    permuter = vtkImagePermute.New();
                    permuter.SetInput(slicer.GetOutput());
                    permuter.SetFilteredAxes(0, 1, 2);
                    permuter.Update();
                }
                //Convert data to byte
                bytedata = DataTypes.vtkToByte(permuter.GetOutput());
                slicer.Dispose();
                permuter.Dispose();
                //convert data to Mat
                Mat image = new Mat(size[1], size[0], MatType.CV_8UC1, bytedata);
                //Get largest binary object
                Mat bw = Processing.LargestBWObject(image, 0.7 * 255.0);
                //Set slice to byte array
                if (bw.Sum().Val0 > 0)
                {
                    output = DataTypes.setByteSlice(output, bw, outextent, axis, k);
                }
            }

            return(DataTypes.byteToVTK(output));
        }