Exemplo n.º 1
0
        public CPostScanConvertImage ScanConvert(CPreScanConvertImage preSCImage, UInt32 image_depth, Double xz_sector, Double yz_sector, Double r, bool enable_log_compression, UInt32 LC, Double referenceMaxVoxel)
        {
            UInt32 GSmax = 255; // Max greyscale value
            // LC: Dynamic range to be visualized[dB]
            Double gain = 0;    // Brightness gain[dB]
            // referenceMaxVoxel: if 0.0 use the brightest voxel of the image, else this value

            Double image_upper_limit_N = 1; // Shallow trimming unsupported for now
            Double image_lower_limit_N = Math.Round(r * 2 / probe.c * probe.fs);
            // The pre-scan convert image has a different axis system (TODO change this nonsense):
            // X = radius, Y = azimuth, Z = elevation
            UInt32 original_depth  = preSCImage.GetSizeX();
            UInt32 original_width  = preSCImage.GetSizeY();
            UInt32 original_height = preSCImage.GetSizeZ();

            // We need the width and height to be an odd number, to be symmetric around the central line of sight.
            UInt32 half_image_width  = Convert.ToUInt32(Math.Ceiling(image_depth * Math.Sin(xz_sector / 2)));
            UInt32 image_width       = 2 * half_image_width + 1;  // new X axis
            UInt32 half_image_height = Convert.ToUInt32(Math.Ceiling(image_depth * Math.Sin(yz_sector / 2)));
            UInt32 image_height      = 2 * half_image_height + 1; // new Y axis

            CPostScanConvertImage image = new CPostScanConvertImage(image_width, image_height, image_depth);

            // Since the image's axial resolution may not be based on the full
            // available axial information, scale appropriately
            double samples_per_depth = (image_lower_limit_N - image_upper_limit_N) / original_depth;

            image_upper_limit_N = Math.Round(image_upper_limit_N / samples_per_depth) + 1;
            image_lower_limit_N = Math.Round(image_lower_limit_N / samples_per_depth);

            // Unless log compression is necessary, the scan conversion will operate on the input image.
            CPreScanConvertImage inputImage = preSCImage;

            // Adjust image brightness
            if (enable_log_compression)
            {
                // Here, however, we must introduce a new temporary image.
                inputImage = new CPreScanConvertImage(preSCImage.GetSizeX(), preSCImage.GetSizeY(), preSCImage.GetSizeZ());

                Double im_max;  // Max image amplitude for auto - gain
                if (referenceMaxVoxel == 0.0)
                {
                    im_max = preSCImage.GetMaxValue();
                }
                else
                {
                    im_max = referenceMaxVoxel;
                }
                Double im_adj = im_max * Math.Pow(10, (-gain / 20));

                for (UInt32 k = 0; k < original_depth; k++)
                {
                    for (UInt32 j = 0; j < original_width; j++)
                    {
                        for (UInt32 i = 0; i < original_height; i++)
                        {
                            // log compress the demodulated image with top value at im_adj
                            inputImage.SetPixel(k, j, i, Math.Min(Math.Max(0, GSmax * (1.0 + (20.0 / LC * Math.Log10(Math.Max(1e-12, preSCImage.GetPixel(k, j, i) / im_adj))))), GSmax));
                        }
                    }
                }
            }

            // Low - pass imaging filter cutoff frequency
            // Double fs = probe.fs / samples_per_depth;
            // TODO this comes straight from Matlab
            // Double[] b_lp = {  };
            // Double[] a_lp = {  };
            //for (UInt32 j = 0; j < original_width; j++) // Azimuth lines
            //{
            //    for (UInt32 i = 0; i < original_height; i++) // Elevation lines
            //    {
            //        Double[] image_line = new Double[original_depth];
            //        for (UInt32 k = 0; k < original_depth; k++)
            //            image_line[k] = preSCImage.GetPixel(k, j, i);
            //        Double[] filtered_image_line = new Double[original_depth];
            //        // DemodulateRFImageSimple(probe.f0, fs, image_line, b_lp, a_lp, ref filtered_image_line);
            //        for (UInt32 k = 0; k < original_depth; k++)
            //            preSCImage.SetPixel(k, j, i, filtered_image_line[k]);
            //    }
            //}

            // Color of the region outside the imaging cone. 127 (middle gray) is
            // a good color as the image will be ranging from black to white.
            UInt32 background_level = 127;

            UInt32 old_x = inputImage.GetSizeX();
            UInt32 old_y = inputImage.GetSizeY();
            UInt32 old_z = inputImage.GetSizeZ();

            var watch = System.Diagnostics.Stopwatch.StartNew();

            Debug.WriteLine(string.Format("Scan converting {0} lines", image_depth));

            Double xScaling = ((original_depth + image_upper_limit_N) / image_depth);
            Double yScaling = ((original_width + 1) / xz_sector);
            // If 2D imaging, yz_sector == 0, and zScaling is unused
            Double zScaling = (yz_sector > 0 ? ((original_height + 1) / yz_sector) : 1);

            for (Int32 new_z_index = 0; new_z_index < image_depth; new_z_index++)
            {
                for (Int32 new_y_index = 0; new_y_index < image_height; new_y_index++)
                {
                    for (Int32 new_x_index = 0; new_x_index < image_width; new_x_index++)
                    {
                        Double xIndex = new_x_index - half_image_width;
                        Double yIndex = new_y_index - half_image_height;
                        Double zIndex = new_z_index;

                        Double old_x_location = Math.Sqrt(xIndex * xIndex + yIndex * yIndex + new_z_index * new_z_index) * xScaling;
                        Double old_y_location = ((xz_sector / 2) + Math.Atan(xIndex / Math.Sqrt(yIndex * yIndex + new_z_index * new_z_index))) * yScaling;
                        Double old_z_location = ((yz_sector / 2) + Math.Atan(yIndex / new_z_index)) * zScaling;

                        if (old_x_location >= old_x || old_y_location >= old_y || old_z_location >= old_z || old_x_location < 1 || old_y_location < 1 || old_z_location < 0)
                        {
                            image.SetPixel(Convert.ToUInt32(new_x_index), Convert.ToUInt32(new_y_index), Convert.ToUInt32(new_z_index), background_level);
                        }
                        else
                        {
                            UInt32 old_x_index = Convert.ToUInt32(Math.Floor(old_x_location));
                            UInt32 old_y_index = Convert.ToUInt32(Math.Floor(old_y_location));
                            UInt32 old_z_index = Convert.ToUInt32(Math.Floor(old_z_location));

                            // Get the eight nearest points to(x, y, z) with wrap-around
                            // Normally old_z_index >= 1, but since in the 2D case old_z_index == 0,
                            // adjust the code to tolerate this event (becomes bilinear interpolation)
                            Double c000 = inputImage.GetPixel(old_x_index - 1, old_y_index - 1, (uint)Math.Max(0, (int)old_z_index - 1));
                            Double c100 = inputImage.GetPixel(old_x_index, old_y_index - 1, (uint)Math.Max(0, (int)old_z_index - 1));
                            Double c010 = inputImage.GetPixel(old_x_index - 1, old_y_index, (uint)Math.Max(0, (int)old_z_index - 1));
                            Double c110 = inputImage.GetPixel(old_x_index, old_y_index, (uint)Math.Max(0, (int)old_z_index - 1));

                            Double c001 = inputImage.GetPixel(old_x_index - 1, old_y_index - 1, old_z_index);
                            Double c101 = inputImage.GetPixel(old_x_index, old_y_index - 1, old_z_index);
                            Double c011 = inputImage.GetPixel(old_x_index - 1, old_y_index, old_z_index);
                            Double c111 = inputImage.GetPixel(old_x_index, old_y_index, old_z_index);

                            // Interpolate over them
                            Double InterpVal = trilinearInterpolation(c000, c100, c010, c110, c001, c101, c011, c111, old_x_location - old_x_index, old_y_location - old_y_index, old_z_location - old_z_index);
                            image.SetPixel(Convert.ToUInt32(new_x_index), Convert.ToUInt32(new_y_index), Convert.ToUInt32(new_z_index), InterpVal);
                        }
                    }
                }
            }

            watch.Stop();
            Debug.WriteLine(string.Format("Scan conversion took {0} ms", watch.ElapsedMilliseconds));

            return(image);
        }
Exemplo n.º 2
0
        public Bitmap ScanConvertBitmap(CPreScanConvertImage preSCImage, UInt32 image_depth, Double xz_sector, Double yz_sector, Double r, bool enable_log_compression, Int32 x_cut, Int32 y_cut, Int32 z_cut, UInt32 LC, Double referenceMaxVoxel)
        {
            if ((x_cut < 0 && y_cut < 0 && z_cut < 0) || (x_cut >= 0 && y_cut >= 0) || (x_cut >= 0 && z_cut >= 0) || (y_cut >= 0 && z_cut >= 0))
            {
                throw new System.ArgumentException("Please define one and only one axis on which to provide a cut");
            }

            UInt32 GSmax = 255; // Max greyscale value
            // LC: Dynamic range to be visualized[dB]
            Double gain = 0;    // Brightness gain[dB]
            // referenceMaxVoxel: if 0.0 use the brightest voxel of the image, else this value

            Double image_upper_limit_N = 1; // Shallow trimming unsupported for now
            Double image_lower_limit_N = Math.Round(r * 2 / probe.c * probe.fs);

            // The pre-scan convert image has a different axis system (TODO change this nonsense):
            // X = radius, Y = azimuth, Z = elevation
            UInt32 original_depth  = preSCImage.GetSizeX();
            UInt32 original_width  = preSCImage.GetSizeY();
            UInt32 original_height = preSCImage.GetSizeZ();

            // We need the width and height to be an odd number, to be symmetric around the central line of sight.
            UInt32 half_image_width  = Convert.ToUInt32(Math.Ceiling(image_depth * Math.Sin(xz_sector / 2)));
            UInt32 image_width       = 2 * half_image_width + 1;  // X axis
            UInt32 half_image_height = Convert.ToUInt32(Math.Ceiling(image_depth * Math.Sin(yz_sector / 2)));
            UInt32 image_height      = 2 * half_image_height + 1; // Y axis

            // Since the image's axial resolution may not be based on the full
            // available axial information, scale appropriately
            double samples_per_depth = (image_lower_limit_N - image_upper_limit_N) / original_depth;

            image_upper_limit_N = Math.Round(image_upper_limit_N / samples_per_depth) + 1;
            image_lower_limit_N = Math.Round(image_lower_limit_N / samples_per_depth);

            // Unless log compression is necessary, the scan conversion will operate on the input image.
            CPreScanConvertImage inputImage = preSCImage;

            // Adjust image brightness
            if (enable_log_compression)
            {
                // Here, however, we must introduce a new temporary image.
                inputImage = new CPreScanConvertImage(preSCImage.GetSizeX(), preSCImage.GetSizeY(), preSCImage.GetSizeZ());

                Double im_max;  // Max image amplitude for auto - gain
                if (referenceMaxVoxel == 0.0)
                {
                    im_max = preSCImage.GetMaxValue();
                }
                else
                {
                    im_max = referenceMaxVoxel;
                }
                double im_adj = im_max * Math.Pow(10, (-gain / 20));
                // Safety clause just in case the returned image is all black
                if (im_adj == 0)
                {
                    im_adj = 1;
                }

                for (UInt32 k = 0; k < original_depth; k++)
                {
                    for (UInt32 j = 0; j < original_width; j++)
                    {
                        for (UInt32 i = 0; i < original_height; i++)
                        {
                            // log compress the demodulated image with top value at im_adj
                            inputImage.SetPixel(k, j, i, Math.Min(Math.Max(0, GSmax * (1.0 + (20.0 / LC * Math.Log10(Math.Max(1e-12, preSCImage.GetPixel(k, j, i) / im_adj))))), GSmax));
                        }
                    }
                }
            }

            // Color of the region outside the imaging cone. 127 (middle gray) is
            // a good color as the image will be ranging from black to white.
            UInt32 background_level = 127;

            UInt32 old_x = inputImage.GetSizeX();
            UInt32 old_y = inputImage.GetSizeY();
            UInt32 old_z = inputImage.GetSizeZ();

            Double xScaling = ((original_depth + image_upper_limit_N) / image_depth);
            Double yScaling = ((original_width + 1) / xz_sector);
            // If 2D imaging, yz_sector == 0, and zScaling is unused
            Double zScaling = (yz_sector > 0 ? ((original_height + 1) / yz_sector) : 1);

            Int32 size1 = 0, size2 = 0;
            Int32 min_x, max_x, min_y, max_y, min_z, max_z;

            if (x_cut >= 0)
            {
                if (yz_sector > 0)
                {
                    size1 = Convert.ToInt32(image_height);
                }
                // If 2D imaging, forcefully widen the image canvas into a square (it will just stay black)
                else
                {
                    size1 = Convert.ToInt32(image_width);
                }
                size2 = Convert.ToInt32(image_depth);
                min_x = x_cut;
                max_x = x_cut + 1;
                min_y = 0;
                max_y = Convert.ToInt32(image_height);
                min_z = 0;
                max_z = Convert.ToInt32(image_depth);
            }
            else if (y_cut >= 0)
            {
                size1 = Convert.ToInt32(image_width);
                size2 = Convert.ToInt32(image_depth);
                min_x = 0;
                max_x = Convert.ToInt32(image_width);
                min_y = y_cut;
                max_y = y_cut + 1;
                min_z = 0;
                max_z = Convert.ToInt32(image_depth);
            }
            else // z_cut >= 0
            {
                size1 = Convert.ToInt32(image_width);
                if (yz_sector > 0)
                {
                    size2 = Convert.ToInt32(image_height);
                }
                // If 2D imaging, forcefully widen the image canvas into a square (it will just stay black)
                else
                {
                    size2 = Convert.ToInt32(image_width);
                }
                min_x = 0;
                max_x = Convert.ToInt32(image_width);
                min_y = 0;
                max_y = Convert.ToInt32(image_height);
                min_z = z_cut;
                max_z = z_cut + 1;
            }
            Double [,] scImage = new Double[size1, size2];
            System.Drawing.Bitmap bmp = new Bitmap(size1, size2, System.Drawing.Imaging.PixelFormat.Format24bppRgb);

            for (Int32 new_z_index = min_z; new_z_index < max_z; new_z_index++)
            {
                for (Int32 new_y_index = min_y; new_y_index < max_y; new_y_index++)
                {
                    for (Int32 new_x_index = min_x; new_x_index < max_x; new_x_index++)
                    {
                        Double xIndex = new_x_index - half_image_width;
                        Double yIndex = new_y_index - half_image_height;
                        Double zIndex = new_z_index;

                        Double old_x_location = Math.Sqrt(xIndex * xIndex + yIndex * yIndex + new_z_index * new_z_index) * xScaling;
                        Double old_y_location = ((xz_sector / 2) + Math.Atan(xIndex / Math.Sqrt(yIndex * yIndex + new_z_index * new_z_index))) * yScaling;
                        Double old_z_location = ((yz_sector / 2) + Math.Atan(yIndex / new_z_index)) * zScaling;

                        if (old_x_location >= old_x || old_y_location >= old_y || old_z_location >= old_z || old_x_location < 1 || old_y_location < 1 || old_z_location < 0)
                        {
                            if (x_cut >= 0)
                            {
                                scImage[new_y_index, new_z_index] = background_level;
                            }
                            else if (y_cut >= 0)
                            {
                                scImage[new_x_index, new_z_index] = background_level;
                            }
                            else // z_cut >= 0
                            {
                                scImage[new_x_index, new_y_index] = background_level;
                            }
                        }
                        else
                        {
                            UInt32 old_x_index = Convert.ToUInt32(Math.Floor(old_x_location));
                            UInt32 old_y_index = Convert.ToUInt32(Math.Floor(old_y_location));
                            UInt32 old_z_index = Convert.ToUInt32(Math.Floor(old_z_location));

                            // Get the eight nearest points to(x, y, z) with wrap-around
                            // Normally old_z_index >= 1, but since in the 2D case old_z_index == 0,
                            // adjust the code to tolerate this event (becomes bilinear interpolation)
                            Double c000 = inputImage.GetPixel(old_x_index - 1, old_y_index - 1, (uint)Math.Max(0, (int)old_z_index - 1));
                            Double c100 = inputImage.GetPixel(old_x_index, old_y_index - 1, (uint)Math.Max(0, (int)old_z_index - 1));
                            Double c010 = inputImage.GetPixel(old_x_index - 1, old_y_index, (uint)Math.Max(0, (int)old_z_index - 1));
                            Double c110 = inputImage.GetPixel(old_x_index, old_y_index, (uint)Math.Max(0, (int)old_z_index - 1));

                            Double c001 = inputImage.GetPixel(old_x_index - 1, old_y_index - 1, old_z_index);
                            Double c101 = inputImage.GetPixel(old_x_index, old_y_index - 1, old_z_index);
                            Double c011 = inputImage.GetPixel(old_x_index - 1, old_y_index, old_z_index);
                            Double c111 = inputImage.GetPixel(old_x_index, old_y_index, old_z_index);

                            // Interpolate over them
                            Double InterpVal = trilinearInterpolation(c000, c100, c010, c110, c001, c101, c011, c111, old_x_location - old_x_index, old_y_location - old_y_index, old_z_location - old_z_index);
                            if (x_cut >= 0)
                            {
                                scImage[new_y_index, new_z_index] = InterpVal;
                            }
                            else if (y_cut >= 0)
                            {
                                scImage[new_x_index, new_z_index] = InterpVal;
                            }
                            else // z_cut >= 0
                            {
                                scImage[new_x_index, new_y_index] = InterpVal;
                            }
                        }
                    }
                }
            }

            return(imageSliceToBitmap(scImage));
        }