コード例 #1
0
        /// <summary>
        /// Gets the bar width distribution and calculates narrow bar width over the specified
        /// range of the histogramResult. A histogramResult could have multiple ranges, separated 
        /// by quiet zones.
        /// </summary>
        /// <param name="hist">histogramResult data</param>
        /// <param name="iStart">start coordinate to be considered</param>
        /// <param name="iEnd">end coordinate + 1</param>
        private static void GetBarWidthDistribution(ref histogramResult hist, int iStart, int iEnd)
        {
            HybridDictionary hdLightBars = new HybridDictionary();
            HybridDictionary hdDarkBars = new HybridDictionary();
            bool bDarkBar = (hist.histogram[iStart] <= hist.threshold);
            int iBarStart = 0;
            for (int i = iStart + 1; i < iEnd; i++)
            {
                bool bDark = (hist.histogram[i] <= hist.threshold);
                if (bDark != bDarkBar)
                {
                    int iBarWidth = i - iBarStart;
                    if (bDarkBar)
                    {
                        if (!hdDarkBars.Contains(iBarWidth))
                            hdDarkBars.Add(iBarWidth, 1);
                        else
                            hdDarkBars[iBarWidth] = (int)hdDarkBars[iBarWidth] + 1;
                    }
                    else
                    {
                        if (!hdLightBars.Contains(iBarWidth))
                            hdLightBars.Add(iBarWidth, 1);
                        else
                            hdLightBars[iBarWidth] = (int)hdLightBars[iBarWidth] + 1;
                    }
                    bDarkBar = bDark;
                    iBarStart = i;
                }
            }

            // Now get the most common bar widths
            CalcNarrowBarWidth(hdLightBars, out hist.lightnarrowbarwidth, out hist.lightwiderbarwidth);
            CalcNarrowBarWidth(hdDarkBars, out hist.darknarrowbarwidth, out hist.darkwiderbarwidth);
        }
コード例 #2
0
        /// <summary>
        /// FindBarcodeZones looks for barcode zones in the current band. 
        /// We look for white space that is more than GAPFACTOR * narrowbarwidth
        /// separating two zones. For narrowbarwidth we take the maximum of the 
        /// dark and light narrow bar width.
        /// </summary>
        /// <param name="hist">Data for current image band</param>
        private static void FindBarcodeZones(ref histogramResult hist)
        {
            if (!ValidBars(ref hist))
                hist.zones = null;
            else if (!UseBarcodeZones)
            {
                hist.zones = new BarcodeZone[1];
                hist.zones[0].Start = 0;
                hist.zones[0].End = hist.histogram.Length;
            }
            else
            {
                ArrayList alBarcodeZones = new ArrayList();
                bool bDarkBar = (hist.histogram[0] <= hist.threshold);
                int iBarStart = 0;
                int iZoneStart = -1;
                int iZoneEnd = -1;
                float fQuietZoneWidth = GAPFACTOR * (hist.darknarrowbarwidth + hist.lightnarrowbarwidth) / 2;
                float fMinZoneWidth = fQuietZoneWidth;

                for (int i = 1; i < hist.histogram.Length; i++)
                {
                    bool bDark = (hist.histogram[i] <= hist.threshold);
                    if (bDark != bDarkBar)
                    {
                        int iBarWidth = i - iBarStart;
                        if (!bDarkBar) // This ends a light area
                        {
                            if ((iZoneStart == -1) || (iBarWidth > fQuietZoneWidth))
                            {
                                // the light area can be seen as a quiet zone
                                iZoneEnd = i - (iBarWidth >> 1);

                                // Check if the active zone is big enough to contain a barcode
                                if ((iZoneStart >= 0) && (iZoneEnd > iZoneStart + fMinZoneWidth))
                                {
                                    // record the barcode zone that ended in the detected quiet zone ...
                                    BarcodeZone bz = new BarcodeZone();
                                    bz.Start = iZoneStart;
                                    bz.End = iZoneEnd;
                                    alBarcodeZones.Add(bz);

                                    // .. and start a new barcode zone
                                    iZoneStart = iZoneEnd;
                                }
                                if (iZoneStart == -1)
                                    iZoneStart = iZoneEnd; // first zone starts here
                            }
                        }
                        bDarkBar = bDark;
                        iBarStart = i;
                    }
                }
                if (iZoneStart >= 0)
                {
                    BarcodeZone bz = new BarcodeZone();
                    bz.Start = iZoneStart;
                    bz.End = hist.histogram.Length;
                    alBarcodeZones.Add(bz);
                }
                if (alBarcodeZones.Count > 0)
                    hist.zones = (BarcodeZone[])alBarcodeZones.ToArray(typeof(BarcodeZone));
                else
                    hist.zones = null;
            }
        }
コード例 #3
0
        /// <summary>
        /// Scans for patterns of bars and returns them encoded as strings in the passed
        /// string builder parameters.
        /// </summary>
        /// <param name="hist">Input data containing picture information for the scan line</param>
        /// <param name="sbCode39Pattern">Returns string containing "w" for wide bars and "n" for narrow bars</param>
        /// <param name="sbEANPattern">Returns string with numbers designating relative bar widths compared to 
        /// narrowest bar: "1" to "4" are valid widths that can be present in an EAN barcode</param>
        /// <remarks>In both output strings, "|"-characters will be inserted to indicate gaps 
        /// in the input data.</remarks>
        private static void GetBarPatterns(ref histogramResult hist, out StringBuilder sbCode39Pattern, out StringBuilder sbEANPattern)
        {
            // Initialize return data
            sbCode39Pattern = new StringBuilder();
            sbEANPattern = new StringBuilder();

            if (hist.zones != null) // if barcode zones were found along the scan line
            {
                for (int iZone = 0; iZone < hist.zones.Length; iZone++)
                {
                    // Recalculate bar width distribution if more than one zone is present, it could differ per zone
                    if (hist.zones.Length > 1)
                        GetBarWidthDistribution(ref hist, hist.zones[iZone].Start, hist.zones[iZone].End);

                    // Check the calculated narrow bar widths. If they are very different, the pattern is
                    // unlikely to be a bar code
                    if (ValidBars(ref hist))
                    {
                        // add gap separator to output patterns
                        sbCode39Pattern.Append("|");
                        sbEANPattern.Append("|");

                        // Variables needed to check for
                        int iBarStart = 0;
                        bool bDarkBar = (hist.histogram[0] <= hist.threshold);

                        // Find the narrow and wide bars
                        for (int i = 1; i < hist.histogram.Length; ++i)
                        {
                            bool bDark = (hist.histogram[i] <= hist.threshold);
                            if (bDark != bDarkBar)
                            {
                                int iBarWidth = i - iBarStart;
                                float fNarrowBarWidth = bDarkBar ? hist.darknarrowbarwidth : hist.lightnarrowbarwidth;
                                float fWiderBarWidth = bDarkBar ? hist.darkwiderbarwidth : hist.lightwiderbarwidth;
                                if (IsWideBar(iBarWidth, fNarrowBarWidth, fWiderBarWidth))
                                {
                                    // The bar was wider than the narrow bar width, it's a wide bar or a gap
                                    if (iBarWidth > GAPFACTOR * fNarrowBarWidth)
                                    {
                                        sbCode39Pattern.Append("|");
                                        sbEANPattern.Append("|");
                                    }
                                    else
                                    {
                                        sbCode39Pattern.Append("w");
                                        AppendEAN(sbEANPattern, iBarWidth, fNarrowBarWidth);
                                    }
                                }
                                else
                                {
                                    // The bar is a narrow bar
                                    sbCode39Pattern.Append("n");
                                    AppendEAN(sbEANPattern, iBarWidth, fNarrowBarWidth);
                                }
                                bDarkBar = bDark;
                                iBarStart = i;
                            }
                        }
                    }
                }
            }
        }
コード例 #4
0
 /// <summary>
 /// Checks if dark and light narrow bar widths are in agreement.
 /// </summary>
 /// <param name="hist">barcode data</param>
 /// <returns>true if barcode data is valid</returns>
 private static bool ValidBars(ref histogramResult hist)
 {
     float fCompNarrowBarWidths = hist.lightnarrowbarwidth / hist.darknarrowbarwidth;
     float fCompWiderBarWidths = hist.lightwiderbarwidth / hist.darkwiderbarwidth;
     return ((fCompNarrowBarWidths >= 0.5) && (fCompNarrowBarWidths <= 2.0)
          && (fCompWiderBarWidths >= 0.5) && (fCompWiderBarWidths <= 2.0)
          && (hist.darkwiderbarwidth / hist.darknarrowbarwidth >= 1.5)
          && (hist.lightwiderbarwidth / hist.lightnarrowbarwidth >= 1.5));
 }
コード例 #5
0
        /// <summary>
        /// Vertical histogram of an image
        /// </summary>
        /// <param name="bmp">Bitmap</param>
        /// <param name="start">Start coordinate of band to be scanned</param>
        /// <param name="end">End coordinate of band to be scanned</param>
        /// <param name="direction">
        /// ScanDirection.Vertical: start and end denote y-coordinates.
        /// ScanDirection.Horizontal: start and end denote x-coordinates.
        /// </param>
        /// <returns>histogramResult, containing average brightness values across the scan line</returns>
        private static histogramResult verticalHistogram(Bitmap bmp, int start, int end, ScanDirection direction)
        {
            // convert the pixel format of the bitmap to something that we can handle
            PixelFormat pf = CheckSupportedPixelFormat(bmp.PixelFormat);
            BitmapData bmData;
            int xMax, yMax;

            if (direction == ScanDirection.Horizontal)
            {
                bmData = bmp.LockBits(new Rectangle(start, 0, end - start, bmp.Height), ImageLockMode.ReadOnly, pf);
                xMax = bmData.Height;
                yMax = end - start;
            }
            else
            {
                bmData = bmp.LockBits(new Rectangle(0, start, bmp.Width, end - start), ImageLockMode.ReadOnly, pf);
                xMax = bmp.Width;
                yMax = bmData.Height;
            }

            // Create the return value
            byte[] histResult = new byte[xMax + 2]; // add 2 to simulate light-colored background pixels at sart and end of scanline
            ushort[] vertSum = new ushort[xMax];

            unsafe
            {
                byte* p = (byte*)(void*)bmData.Scan0;
                int stride = bmData.Stride;    // stride is offset between horizontal lines in p

                for (int y = 0; y < yMax; ++y)
                {
                    // Add up all the pixel values vertically
                    for (int x = 0; x < xMax; ++x)
                    {
                        if (direction == ScanDirection.Horizontal)
                            vertSum[x] += getpixelbrightness(p, pf, stride, y, x);
                        else
                            vertSum[x] += getpixelbrightness(p, pf, stride, x, y);
                    }
                }
            }
            bmp.UnlockBits(bmData);

            // Now get the average of the row by dividing the pixel by num pixels
            int iDivider = end - start;
            if (pf != PixelFormat.Format1bppIndexed)
                iDivider *= 3;

            byte maxValue = byte.MinValue; // Start the max value at zero
            byte minValue = byte.MaxValue; // Start the min value at the absolute maximum

            for (int i = 1; i <= xMax; i++) // note: intentionally skips first pixel in histResult
            {
                histResult[i] = (byte)(vertSum[i - 1] / iDivider);
                //Save the max value for later
                if (histResult[i] > maxValue) maxValue = histResult[i];
                // Save the min value for later
                if (histResult[i] < minValue) minValue = histResult[i];
            }

            // Set first and last pixel to "white", i.e., maximum intensity
            histResult[0] = maxValue;
            histResult[xMax + 1] = maxValue;

            histogramResult retVal = new histogramResult();
            retVal.histogram = histResult;
            retVal.max = maxValue;
            retVal.min = minValue;

            // Now we have the brightness distribution along the scan band, try to find the distribution of bar widths.
            retVal.threshold = (byte)(minValue + ((maxValue - minValue) >> 1));
            GetBarWidthDistribution(ref retVal, 0, retVal.histogram.Length);

            // Now that we know the narrow bar width, lets look for barcode zones.
            // The image could have more than one barcode in the same band, with
            // different bar widths.
            FindBarcodeZones(ref retVal);
            return retVal;
        }
コード例 #6
0
        /// <summary>
        /// Vertical histogram of an image
        /// </summary>
        /// <param name="bmp">the bitmap to be processed</param>
        /// <param name="showDiagnostics">if true, draws an overlay on the image</param>
        /// <param name="diagnosticsColor">the color of the overlay</param>
        /// <returns>a histogramResult representing the vertical histogram</returns>
        private static histogramResult verticalHistogram(Bitmap bmp, bool showDiagnostics, Color diagnosticsColor)
        {
            // Create the return value
            float[] histResult = new float[bmp.Width];

            float[] vertSum = new float[bmp.Width];
            // Start the max value at zero
            float maxValue = 0;
            // Start the min value at the absolute maximum
            float minValue = 255;

            // GDI+ still lies to us - the return format is BGR, NOT RGB.
            BitmapData bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

            int stride = bmData.Stride;
            System.IntPtr Scan0 = bmData.Scan0;

            unsafe
            {

                byte* p = (byte*)(void*)Scan0;

                int nOffset = stride - bmp.Width * 3;
                int nWidth = bmp.Width * 3;

                for (int y = 0; y < bmp.Height; ++y)
                {
                    for (int x = 0; x < bmp.Width; ++x)
                    {
                        // Add up all the pixel values vertically (average the R,G,B channels)
                        vertSum[x] += ((p[0] + (p + 1)[0] + (p + 2)[0]) / 3);

                        p += 3;
                    }
                    p += nOffset;
                }
            }

            bmp.UnlockBits(bmData);

            // Now get the average of the row by dividing the pixel by num pixels
            for (int i = 0; i < bmp.Width; i++)
            {
                histResult[i] = (vertSum[i] / (bmp.Height));
                //Save the max value for later
                if (histResult[i] > maxValue) maxValue = histResult[i];
                // Save the min value for later
                if (histResult[i] < minValue) minValue = histResult[i];
            }

            // Use GDI+ to draw a lines up the image showing each lines average
            if (showDiagnostics)
            {
                // Set the alpha of the overlay to half transparency
                int alpha = (int)255 / 2;
                Pen p = new Pen(Color.FromArgb(alpha, diagnosticsColor));

                //Get the graphics to draw on
                Graphics g;
                g = Graphics.FromImage(bmp);
                for (int i = 0; i < bmp.Width; ++i)
                {
                    // Normalize the drawn histogram to the height of the image
                    int drawLength = (int)(histResult[i] * (bmp.Height / maxValue));
                    g.DrawLine(p, i, bmp.Height, i, (bmp.Height - (int)drawLength));
                }
                p.Dispose();
                g.Dispose();
            }
            histogramResult retVal = new histogramResult();
            retVal.histogram = histResult;
            retVal.max = maxValue;
            retVal.min = minValue;
            return retVal;
        }
コード例 #7
0
    public static string ReadCode39(Bitmap bmp, bool showDiagnostics, Color diagnosticsColor)
    {
        // To find a horizontal barcode, find the vertical histogram to find individual barcodes,
        // then get the vertical histogram to decode each
        histogramResult vertHist = verticalHistogram(bmp, showDiagnostics, diagnosticsColor);


        // Set the threshold for determining dark/light bars to half way between the histograms min/max
        float threshold = vertHist.min + ((vertHist.max - vertHist.min) / 2);

        // Variables needed to check for
        string patternString   = null;
        int    nBarStart       = -1;
        int    nNarrowBarWidth = -1;
        bool   bDarkBar        = false;

        // Find the narrow and wide bars
        for (int i = 0; i < vertHist.histogram.Length; ++i)
        {
            // First find the narrow bar width
            if (nNarrowBarWidth < 0)
            {
                if (nBarStart < 0)
                {
                    // The code doesn't start until we see a dark bar
                    if (vertHist.histogram[i] <= threshold)
                    {
                        // We detected a dark bar, save it's start position
                        nBarStart = i;
                    }
                }
                else
                {
                    if (vertHist.histogram[i] > threshold)
                    {
                        // We detected the end of first the dark bar, save the narrow bar width and
                        // start the rest of the barcode
                        nNarrowBarWidth = i - nBarStart + 1;
                        patternString  += "n";
                        nBarStart       = i;
                        bDarkBar        = false;
                    }
                }
            }
            else
            {
                if (bDarkBar)
                {
                    // We're on a dark bar, detect when the bar becomes light again
                    if (vertHist.histogram[i] > threshold)
                    {
                        if ((i - nBarStart) > (nNarrowBarWidth))
                        {
                            // The light bar was wider than the narrow bar width, it's a wide bar
                            patternString += "w";
                            nBarStart      = i;
                        }
                        else
                        {
                            // The light bar is a narrow bar
                            patternString += "n";
                            nBarStart      = i;
                        }
                        bDarkBar = false;
                    }
                }
                else
                {
                    // We're on a light bar, detect when the bar becomes dark
                    if (vertHist.histogram[i] <= threshold)
                    {
                        if ((i - nBarStart) > (nNarrowBarWidth))
                        {
                            // The dark bar was wider than the narrow bar width, it's a wide bar
                            patternString += "w";
                            nBarStart      = i;
                        }
                        else
                        {
                            // The dark bar is a narrow bar
                            patternString += "n";
                            nBarStart      = i;
                        }
                        bDarkBar = true;
                    }
                }
            }
        }

        // We now have a barcode in terms of narrow & wide bars... Parse it!
        string dataString = "";

        // Each pattern within code 39 is nine bars with one white bar between each pattern
        for (int i = 0; i < patternString.Length - 1; i += 10)
        {
            // Create an array of charachters to hold the pattern to be tested
            char[] pattern = new char[9];
            // Stuff the pattern with data from the pattern string
            patternString.CopyTo(i, pattern, 0, 9);

            dataString += parsePattern(new string(pattern));
        }

        return(dataString);
    }
コード例 #8
0
    /// <summary>
    /// Vertical histogram of an image
    /// </summary>
    /// <param name="bmp">the bitmap to be processed</param>
    /// <param name="showDiagnostics">if true, draws an overlay on the image</param>
    /// <param name="diagnosticsColor">the color of the overlay</param>
    /// <returns>a histogramResult representing the vertical histogram</returns>
    private static histogramResult verticalHistogram(Bitmap bmp, bool showDiagnostics, Color diagnosticsColor)
    {
        // Create the return value
        float[] histResult = new float[bmp.Width];

        float[] vertSum = new float[bmp.Width];
        // Start the max value at zero
        float maxValue = 0;
        // Start the min value at the absolute maximum
        float minValue = 255;

        // GDI+ still lies to us - the return format is BGR, NOT RGB.
        BitmapData bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

        int stride = bmData.Stride;

        System.IntPtr Scan0 = bmData.Scan0;

        unsafe
        {
            byte *p = (byte *)(void *)Scan0;

            int nOffset = stride - bmp.Width * 3;
            int nWidth  = bmp.Width * 3;

            for (int y = 0; y < bmp.Height; ++y)
            {
                for (int x = 0; x < bmp.Width; ++x)
                {
                    // Add up all the pixel values vertically (average the R,G,B channels)
                    vertSum[x] += ((p[0] + (p + 1)[0] + (p + 2)[0]) / 3);

                    p += 3;
                }
                p += nOffset;
            }
        }

        bmp.UnlockBits(bmData);

        // Now get the average of the row by dividing the pixel by num pixels
        for (int i = 0; i < bmp.Width; i++)
        {
            histResult[i] = (vertSum[i] / (bmp.Height));
            //Save the max value for later
            if (histResult[i] > maxValue)
            {
                maxValue = histResult[i];
            }
            // Save the min value for later
            if (histResult[i] < minValue)
            {
                minValue = histResult[i];
            }
        }

        // Use GDI+ to draw a lines up the image showing each lines average
        if (showDiagnostics)
        {
            // Set the alpha of the overlay to half transparency
            int alpha = (int)255 / 2;
            Pen p     = new Pen(Color.FromArgb(alpha, diagnosticsColor));

            //Get the graphics to draw on
            Graphics g;
            g = Graphics.FromImage(bmp);
            for (int i = 0; i < bmp.Width; ++i)
            {
                // Normalize the drawn histogram to the height of the image
                int drawLength = (int)(histResult[i] * (bmp.Height / maxValue));
                g.DrawLine(p, i, bmp.Height, i, (bmp.Height - (int)drawLength));
            }
            p.Dispose();
            g.Dispose();
        }
        histogramResult retVal = new histogramResult();

        retVal.histogram = histResult;
        retVal.max       = maxValue;
        retVal.min       = minValue;
        return(retVal);
    }
コード例 #9
0
    /// <summary>
    /// Vertical histogram of an image
    /// </summary>
    /// <param name="bmp">the bitmap to be processed</param>
    /// <param name="showDiagnostics">if true, draws an overlay on the image</param>
    /// <param name="diagnosticsColor">the color of the overlay</param>
    /// <returns>a histogramResult representing the vertical histogram</returns>
    private static histogramResult verticalHistogram(Bitmap bmp, int startheight, int endheight)
    {
        // Create the return value
        float[] histResult = new float[bmp.Width];

        float[] vertSum = new float[bmp.Width];
        // Start the max value at zero
        float maxValue = 0;
        // Start the min value at the absolute maximum
        float minValue = 255;

        // GDI+ still lies to us - the return format is BGR, NOT RGB.
        BitmapData bmData = bmp.LockBits(new Rectangle(0, startheight, bmp.Width, endheight - startheight), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);



        int stride = bmData.Stride;

        System.IntPtr Scan0 = bmData.Scan0;

        unsafe
        {
            byte *p = (byte *)(void *)Scan0;

            int nOffset = stride - bmp.Width * 3;
            int nWidth  = bmp.Width * 3;

            for (int y = startheight; y < endheight; ++y)
            {
                for (int x = 0; x < bmp.Width; ++x)
                {
                    // Add up all the pixel values vertically (average the R,G,B channels)
                    vertSum[x] += ((p[0] + (p + 1)[0] + (p + 2)[0]) / 3);

                    p += 3;
                }
                p += nOffset;
            }
        }

        bmp.UnlockBits(bmData);

        // Now get the average of the row by dividing the pixel by num pixels
        for (int i = 0; i < bmp.Width; i++)
        {
            histResult[i] = (vertSum[i] / (endheight - startheight));
            //Save the max value for later
            if (histResult[i] > maxValue)
            {
                maxValue = histResult[i];
            }
            // Save the min value for later
            if (histResult[i] < minValue)
            {
                minValue = histResult[i];
            }
        }

        histogramResult retVal = new histogramResult();

        retVal.histogram = histResult;
        retVal.max       = maxValue;
        retVal.min       = minValue;
        return(retVal);
    }
コード例 #10
0
    /// <summary>
    /// Vertical histogram of an image
    /// </summary>
    /// <param name="bmp">the bitmap to be processed</param>
    /// <param name="showDiagnostics">if true, draws an overlay on the image</param>
    /// <param name="diagnosticsColor">the color of the overlay</param>
    /// <returns>a histogramResult representing the vertical histogram</returns>
    private static histogramResult verticalHistogram(Bitmap bmp, int startheight, int endheight)
    {
        // Create the return value
            float[] histResult = new float[bmp.Width];

            float[] vertSum = new float[bmp.Width];
            // Start the max value at zero
            float maxValue = 0;
            // Start the min value at the absolute maximum
            float minValue = 255;

            // GDI+ still lies to us - the return format is BGR, NOT RGB.
            BitmapData bmData = bmp.LockBits(new Rectangle(0, startheight, bmp.Width, endheight - startheight), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

            int stride = bmData.Stride;
            System.IntPtr Scan0 = bmData.Scan0;

            unsafe
            {

                byte * p = (byte *)(void *)Scan0;

                int nOffset = stride - bmp.Width*3;
                int nWidth = bmp.Width * 3;

                for(int y=startheight;y<endheight;++y)
                {
                    for(int x=0; x < bmp.Width; ++x )
                    {
                        // Add up all the pixel values vertically (average the R,G,B channels)
                        vertSum[x] += ((p[0] + (p+1)[0] + (p+2)[0])/3);

                        p+=3;
                    }
                    p += nOffset;
                }
            }

            bmp.UnlockBits(bmData);

            // Now get the average of the row by dividing the pixel by num pixels
            for(int i=0; i<bmp.Width; i++)
            {
                histResult[i] = (vertSum[i] / (endheight - startheight));
                //Save the max value for later
                if (histResult[i] > maxValue) maxValue = histResult[i];
                // Save the min value for later
                if (histResult[i] < minValue) minValue = histResult[i];
            }

            histogramResult retVal = new histogramResult();
            retVal.histogram = histResult;
            retVal.max = maxValue;
            retVal.min = minValue;
            return retVal;
    }