/// Applies a Gaussian blur to the rows of an image.
    /// @param channelToBlur A gray-scale channel to be blurred.
    private void ExecuteHorizontalBlur(ref MonochromeBitmap channelToBlur)
    {
        // We will blur each row in parallel.
        int numberOfThreads = channelToBlur.height;

        OnionLogger.globalLog.PushInfoLayer(string.Format("Setting up {0} GrayscaleGaussianBlur threads",
                                                          numberOfThreads));

        // We will keep an active thread count that is atomically decremented when each thread finishes.
        // When this count reaches 0, then we know that all threads have finished and can set "allThreadsDone".
        activeThreadCount = numberOfThreads;
        allThreadsDone    = new ManualResetEvent(false);

        // Initialize thread objects
        GrayscaleGaussianBlurThread[] threads = new GrayscaleGaussianBlurThread[numberOfThreads];
        for (int i = 0; i < numberOfThreads; ++i)
        {
            threads[i] = new GrayscaleGaussianBlurThread(this, i);
        }
        OnionLogger.globalLog.PopInfoLayer();

        OnionLogger.globalLog.PushInfoLayer("Running Gaussian blur");
        for (int i = 0; i < numberOfThreads; ++i)
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(threads[i].BlurRow), channelToBlur);
        }

        if (!allThreadsDone.WaitOne(500))
        {
            string logStr = string.Format("Timed out after 500ms - {0} threads unfinished.",
                                          activeThreadCount);
            OnionLogger.globalLog.LogError(logStr);
        }
        OnionLogger.globalLog.PopInfoLayer();         /* Done with parallel section. */
    }
        private void CreateMonochromeBitmap()
        {
            if (m_originalBitmap == null || m_doNotUpdateMonochrome)
            {
                return;
            }

            using (var scaledImage = m_originalBitmap.Resize(new Size(m_width, m_height)))
            {
                if (m_monochromeBitmap != null)
                {
                    m_monochromeBitmap.Dispose();
                    m_monochromeBitmap = null;
                }

                var mode = (NamedItemContainer <MonochromeConversionMode>)ConversionTypeComboBox.SelectedItem;
                switch (mode.Data)
                {
                case MonochromeConversionMode.ThresholdBased:
                {
                    m_monochromeBitmap = MonochromeBitmap.ConvertTo1Bit(scaledImage, MonochromeConversionMode.ThresholdBased, (int)ThresholdUpDown.Value);
                    break;
                }

                case MonochromeConversionMode.FloydSteinbergDithering:
                {
                    m_monochromeBitmap = MonochromeBitmap.ConvertTo1Bit(scaledImage);
                    break;
                }

                default: throw new ArgumentOutOfRangeException();
                }
            }
        }
Beispiel #3
0
        /// <summary>
        ///     Sets the bounds of the control to the specified location and size.
        /// </summary>
        /// <param name="x">The new <see cref="P:LogiFrame.LCDControl.Left" /> property value of the control.</param>
        /// <param name="y">The new <see cref="P:LogiFrame.LCDControl.Top" /> property value of the control.</param>
        /// <param name="width">The new <see cref="P:LogiFrame.LCDControl.Width" /> property value of the control.</param>
        /// <param name="height">The new <see cref="P:LogiFrame.LCDControl.Height" /> property value of the control.</param>
        /// <param name="preventInvalidation">if set to <c>true</c> invalidation is prevented.</param>
        protected virtual void SetBounds(int x, int y, int width, int height, bool preventInvalidation)
        {
            ThrowIfDisposed();

            if (width < 1)
            {
                width = 1;
            }
            if (height < 1)
            {
                height = 1;
            }
            if (_left == x && _top == y && _width == width && _height == height)
            {
                return;
            }

            _left   = x;
            _top    = y;
            _width  = width;
            _height = height;

            Bitmap = new MonochromeBitmap(Width, Height);

            if (!preventInvalidation)
            {
                Invalidate();
            }
        }
Beispiel #4
0
    /**
     *	Transposes the data in a bitmap.
     *	@param bitmap The bitmap that will be transposed.
     */
    public static void Transpose(ref MonochromeBitmap bitmap)
    {
        OnionLogger.globalLog.PushInfoLayer("Transposing bitmap of length " + (bitmap.height * bitmap.width));
        float[] transposedData = new float[bitmap.channel.Length];
        int     insertionIndex = 0;

        for (int x = 0; x < bitmap.width; ++x)
        {
            for (int y = 0; y < bitmap.height; ++y)
            {
                int pixelIndex = y * bitmap.width + x;
                //OnionLogger.globalLog.LogTrace(string.Format("Moving pixel {0} to {1}", pixelIndex, insertionIndex));
                transposedData[insertionIndex++] = bitmap.channel[pixelIndex];
            }
        }
        // set the new data
        bitmap.channel = transposedData;

        // swap width and height
        int temp = bitmap.height;

        bitmap.height = bitmap.width;
        bitmap.width  = temp;

        OnionLogger.globalLog.PopInfoLayer();
    }
Beispiel #5
0
 /// <summary>
 ///     Initializes a new instance of the <see cref="LCDPaintEventArgs" /> class.
 /// </summary>
 /// <param name="bitmap">The bitmap.</param>
 /// <exception cref="System.ArgumentNullException">Thrown if bitmap is null.</exception>
 public LCDPaintEventArgs(MonochromeBitmap bitmap)
 {
     if (bitmap == null)
     {
         throw new ArgumentNullException(nameof(bitmap));
     }
     Bitmap = bitmap;
 }
Beispiel #6
0
    /**
     *  Extract a MonochromeBitmap from the blue channel of an RGBBitmap.
     *  @param rgbBitmap The RGBBitmap to extract B from.
     *  @return A MonochromeBitmap containing the blue channel.
     */
    public static MonochromeBitmap blueBitmapFromRGBBitmap(ref RGBBitmap rgbBitmap)
    {
        MonochromeBitmap blue = new MonochromeBitmap();

        blue.channel = rgbBitmap.rgb.b;
        blue.height  = rgbBitmap.height;
        blue.width   = rgbBitmap.width;
        return(blue);
    }
Beispiel #7
0
    /**
     *  Extract a MonochromeBitmap from the green channel of an RGBBitmap.
     *  @param rgbBitmap The RGBBitmap to extract G from.
     *  @return A MonochromeBitmap containing the green channel.
     */
    public static MonochromeBitmap greenBitmapFromRGBBitmap(ref RGBBitmap rgbBitmap)
    {
        MonochromeBitmap green = new MonochromeBitmap();

        green.channel = rgbBitmap.rgb.g;
        green.height  = rgbBitmap.height;
        green.width   = rgbBitmap.width;
        return(green);
    }
Beispiel #8
0
    /**
     *  Extract a MonochromeBitmap from the red channel of an RGBBitmap.
     *  @param rgbBitmap The RGBBitmap to extract R from.
     *  @return A MonochromeBitmap containing the red channel.
     */
    public static MonochromeBitmap redBitmapFromRGBBitmap(ref RGBBitmap rgbBitmap)
    {
        MonochromeBitmap red = new MonochromeBitmap();

        red.channel = rgbBitmap.rgb.r;
        red.height  = rgbBitmap.height;
        red.width   = rgbBitmap.width;
        return(red);
    }
    /**
     *  Inverts the values in a single channel, represented as an array of floats
     *  @param state    An object containing a MonochromeBitmap.
     *                  Must be 'object' because of how .NET handles threads.
     */
    public void ThreadedProcessChannel(object state)
    {
        MonochromeBitmap monochromeBitmap = (MonochromeBitmap)state;

        for (int i = 0; i < monochromeBitmap.channel.Length; ++i)
        {
            monochromeBitmap.channel[i] = 1f - monochromeBitmap.channel[i];
        }
        done.Set();
    }
Beispiel #10
0
    /**
     *	Create a deep copy of this monochrome bitmap.
     *	@param original The bitmap to copy.
     *	@return A deep copy of the original.
     */
    public static MonochromeBitmap Copy(ref MonochromeBitmap original)
    {
        MonochromeBitmap copy = new MonochromeBitmap();

        copy.height  = original.height;
        copy.width   = original.width;
        copy.channel = (float[])original.channel.Clone();

        return(copy);
    }
Beispiel #11
0
        /// <summary>
        ///     Pushes the specified bitmap to the LCD.
        /// </summary>
        /// <param name="bitmap">The bitmap.</param>
        private void Push(MonochromeBitmap bitmap)
        {
            if (bitmap == null)
            {
                throw new ArgumentNullException(nameof(bitmap));
            }

            var render   = new MonochromeBitmap(bitmap, (int)LgLcd.BitmapWidth, (int)LgLcd.BitmapHeight);
            var lgBitmap = new LgLcd.Bitmap160X43X1
            {
                Header = { Format = LgLcd.BitmapFormat160X43X1 },
                Pixels = render.Pixels
            };

            LgLcd.UpdateBitmap(_device, ref lgBitmap, (uint)UpdatePriority);
            OnRendered(new RenderedEventArgs(render));
        }
        /**
         *  Blurs a single row of a bitmap.
         *  @param state    An object containing a MonochromeBitmap.
         *                  Must be 'object' because of how .NET handles threads.
         */
        public void BlurRow(object state)
        {
            MonochromeBitmap blurred = (MonochromeBitmap)state;

            this.original = ColorUtils.Copy(ref blurred);

            // Zero the row we are blurring.
            int startingPixel = rowNumber * blurred.width;
            int finishPixel   = startingPixel + blurred.width;

            for (int i = startingPixel; i < finishPixel; ++i)
            {
                blurred.channel[i] = 0f;
            }

            int numberOfCoefficients = this.coefficients.Length - 1;

            for (int j = 0; j < blurred.width; ++j)
            {
                int targetPixel = rowNumber * blurred.width + j;

                for (int k = 0; k <= numberOfCoefficients; ++k)
                {
                    if (j + k < 0 || j + k >= blurred.width)
                    {
                        continue;
                    }
                    int   sourcePoint   = targetPixel + k;
                    float factor        = coefficients[Mathf.Abs(k)];
                    float weightedValue = factor * original.channel[sourcePoint];
                    blurred.channel[targetPixel] += weightedValue;
                }
            }

            // This thread is considered finished. We atomically decrement, and if the active thread count hits 0 then
            // this thread is the last to finish.
            if (Interlocked.Decrement(ref threadManager.activeThreadCount) <= 0)
            {
                threadManager.allThreadsDone.Set();
            }
        }
Beispiel #13
0
        /// <summary>
        ///     Called after the control has been added to another container.
        /// </summary>
        protected virtual void InitLayout()
        {
            if (_isLayoutInit)
            {
                Invalidate();
                return;
            }

            _isLayoutInit = true;

            if (_width == 0 || _height == 0)
            {
                SetBounds(0, 0, 1, 1);
            }
            else
            {
                Bitmap = new MonochromeBitmap(Width, Height);
            }

            Invalidate();
        }
    /**
     *	Applies gaussian blur effect to a grayscale bitmap.
     *  @param colorBitmap the image to be processed.
     */
    public void ProcessBitmap(ref ColorBitmap colorBitmap)
    {
        OnionLogger.globalLog.PushInfoLayer("Performing GrayscaleGaussianBlur on bitmap.");

        RGBBitmap rgbBitmap = new RGBBitmap();

        ColorUtils.colorBitmapToRGBBitmap(ref colorBitmap, ref rgbBitmap);

        /* Since we are assuming the image is grayscale, we can apply the blur to just one
         * channel. We arbitrarily choose the red channel.
         */
        MonochromeBitmap blurR = ColorUtils.redBitmapFromRGBBitmap(ref rgbBitmap);

        // temporarily hard-coded
        int numberOfCoefficients = 5;

        this.coefficients = ApproximateGaussianCoefficients(numberOfCoefficients);

        OnionLogger.globalLog.PushInfoLayer("Blurring rows");
        ExecuteHorizontalBlur(ref blurR);
        ColorUtils.Transpose(ref blurR);         /* transpose to set up for blurring columns */
        OnionLogger.globalLog.PopInfoLayer();

        // Since we transposed the image, we can re-use the horizontal blur operation to blur the columns.
        OnionLogger.globalLog.PushInfoLayer("Blurring columns");
        ExecuteHorizontalBlur(ref blurR);
        ColorUtils.Transpose(ref blurR);         /* reset the image to original orientation */
        OnionLogger.globalLog.PopInfoLayer();

        // Since we assumed that we are using a grayscale image, the Blue and Green channels can be copied from
        // the red channel.
        rgbBitmap.rgb.r = blurR.channel;
        rgbBitmap.rgb.b = blurR.channel;
        rgbBitmap.rgb.g = blurR.channel;

        ColorUtils.RGBBitmapToColorBitmap(ref rgbBitmap, ref colorBitmap);

        OnionLogger.globalLog.PopInfoLayer();
    }
    /**
     *	Invert the colors of a bitmap.
     *
     *  @param colorBitmap The ColorBitmap to invert.
     */
    public void ProcessBitmap(ref ColorBitmap colorBitmap)
    {
        OnionLogger.globalLog.PushInfoLayer("Inverting bitmap");
        RGBBitmap rgbBitmap = new RGBBitmap();

        ColorUtils.colorBitmapToRGBBitmap(ref colorBitmap, ref rgbBitmap);

        MonochromeBitmap invertedr = ColorUtils.redBitmapFromRGBBitmap(ref rgbBitmap);
        MonochromeBitmap invertedg = ColorUtils.greenBitmapFromRGBBitmap(ref rgbBitmap);
        MonochromeBitmap invertedb = ColorUtils.blueBitmapFromRGBBitmap(ref rgbBitmap);

        // We'll run a thread for each color channel.
        int numberOfThreads = 3;

        ManualResetEvent[]  threadsDone = new ManualResetEvent[numberOfThreads];
        ColorInvertThread[] threads     = new ColorInvertThread[numberOfThreads];
        for (int i = 0; i < numberOfThreads; ++i)
        {
            threadsDone[i] = new ManualResetEvent(false);
            threads[i]     = new ColorInvertThread(threadsDone[i]);
        }

        ThreadPool.QueueUserWorkItem(new WaitCallback(threads[0].ThreadedProcessChannel), invertedr);
        ThreadPool.QueueUserWorkItem(new WaitCallback(threads[1].ThreadedProcessChannel), invertedg);
        ThreadPool.QueueUserWorkItem(new WaitCallback(threads[2].ThreadedProcessChannel), invertedb);

        WaitHandle.WaitAll(threadsDone);
        // Done with parallel section.

        rgbBitmap.rgb.r = invertedr.channel;
        rgbBitmap.rgb.g = invertedg.channel;
        rgbBitmap.rgb.b = invertedb.channel;

        ColorUtils.RGBBitmapToColorBitmap(ref rgbBitmap, ref colorBitmap);
        OnionLogger.globalLog.PopInfoLayer();
    }
        private void ExportBitmapMenuItem_Click(object sender, EventArgs e)
        {
            if (SelectedImageMetadata.Count == 0)
            {
                return;
            }

            string directoryPath;

            using (var fb = new FolderBrowserDialog())
            {
                if (fb.ShowDialog() != DialogResult.OK)
                {
                    return;
                }
                directoryPath = fb.SelectedPath;
            }

            var exportData = SelectedImageMetadata.Select(x => new { Metadata = x, ImageData = m_firmware.ReadImage(x) });

            foreach (var data in exportData)
            {
                try
                {
                    using (var image = MonochromeBitmap.Create1BitBitmapFromRaw(data.ImageData))
                    {
                        var fileName = Path.Combine(directoryPath, "0x" + data.Metadata.Index.ToString("X2") + Consts.BitmapFileExtensionWoAsterisk);
                        image.Save(fileName, ImageFormat.Bmp);
                    }
                }
                catch
                {
                    // Ignore
                }
            }
        }
Beispiel #17
0
 /// <summary>
 ///     Initializes a new instance of the <see cref="RenderedEventArgs" /> class.
 /// </summary>
 /// <param name="bitmap">The bitmap.</param>
 public RenderedEventArgs(MonochromeBitmap bitmap)
 {
     Bitmap = bitmap;
 }