Exemple #1
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);
        }
Exemple #2
0
 /// <summary>
 /// Extract data as vtkImageData
 /// </summary>
 /// <returns>Converted data as vtkImageData variable.</returns>
 public vtkImageData GetData()
 {
     //Conver byte data to vtkImageData
     vtkdata = DataTypes.byteToVTK(data);
     return(vtkdata);
 }
Exemple #3
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));
        }
Exemple #4
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();
        }
Exemple #5
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);
        }
Exemple #6
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;
        }
        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));
        }
        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));
        }
        /// <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));
        }