0

I am trying to apply brightness/contrast on a image using track bar, since applying on image taking long time. When track bar is scrolled, it's not smooth, it's getting lagged on my form. Here is my code,is this right method for separating out worker thread from UI (there is no improvement in user experience though)?

    private void bright_tbr_ValueChanged(object sender, EventArgs e)
    {
        brightness = bright_tbr.Value;
        contrast = contrast_tbr.Value;
        toolTip1.SetToolTip(bright_tbr, brightness.ToString());
        Thread thread = new Thread(new ThreadStart(applyBandC));
        thread.IsBackground = true;
        thread.Start();

    }
     private void applyBandC()
    {
        this.Invoke((MethodInvoker)delegate()
                {
                    lock (this)
                    {
                        create_pixmap(brightness, contrast, 0, 0, 255, 255);
                        Bitmap bmp1 = new Bitmap(bmp);
                        BitmapData data1 = bmp1.LockBits(new Rectangle(0, 0,                                                bmp1.Width, bmp1.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                        MapLUT(bmp1.Height, bmp1.Width, data1.Scan0);
                        bmp1.UnlockBits(data1);
                        pictureBox2.Image = bmp1;
                    }
                }
    );

    }

3 Answers 3

2

Your solution doesn't improve the user experience because your entire "multithreaded" code is wrapped in this.Invoke! The purpose of Invoke is to execute a delegate on the UI thread. Move all your processing code except for the pictureBox2.Image = bmp1; part out of the delegate passed to this.Invoke and it should work properly.

Sign up to request clarification or add additional context in comments.

7 Comments

Just wanted to clarify what minitech said. The thread should get a bitmap to process and then return it and the UI should update the screen. Even this might be too slow, so maybe you should show a small version and preview the changes in the small window first.
@minitech:thanx for reply,still lag is there in trackbar movement and sometimes i get this exception: Object is currently in use elsewhere.
@Sisya: You still need a lock, and you should wait until the TrackBar has stopped moving until you apply the change, ideally.
@minitech:is there a way to check trackbar has stopped moving?
@Sisya: MouseUp, but if there was no MouseDown event before it use ValueChanged for accessibility. So basically, in MouseDown set a flag, in ValueChanged change image if !flag, and in MouseUp change image if flag.
|
1

As minitech said, when working in a invoke block, you are still blocking the UI. You have to prepare the bitmap in the background and assign it in the foreground. You also have to make sure that only one prepare task is running simultaniously and you dont want update requests batching up when you are waiting for another updateTask. TPL helps you in this, see the following example code:

    private Task _runningTask;

    // only call this method from the UI!
    private void UpdateBitmap()
    {
        int brightness = bright_tbr.Value; 
        int contrast = contrast_tbr.Value;
        // only when not yet running
        if (_runningTask == null)
        {
            var ui = TaskScheduler.FromCurrentSynchronizationContext();

            _runningTask = Task.Factory.StartNew<Bitmap>(() =>
            {
                // prepare
                create_pixmap(brightness, contrast, 0, 0, 255, 255);
                Bitmap bmp1 = new Bitmap(bmp);
                BitmapData data1 = bmp1.LockBits(new Rectangle(0, 0, bmp1.Width, bmp1.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                MapLUT(bmp1.Height, bmp1.Width, data1.Scan0);
                bmp1.UnlockBits(data1);
                return bmp1;
            }).ContinueWith(x =>
            {
                // assign
                pictureBox2.Image = x.Result;

                int newBrightness = bright_tbr.Value;
                int newContrast = contrast_tbr.Value;

                // If the value has changed in the meantime, update again
                if (newBrightness != brightness || newContrast != contrast)
                {
                    UpdateBitmap();
                }
                else
                {
                    _runningTask = null;
                }
            }, CancellationToken.None, TaskContinuationOptions.None, ui);
        }
    }

1 Comment

:i cant find TaskScheduler in .net 3.5?
0

Is this a web app or windows application(more specifically WPF). If its a WPF based application, then you can use Dispatcher class, for performing non-UI based tasks, which will be executed on a separate thread and once the processing is over, the result will be pushed back to the main UI thread. For more on Dispatcher : http://weblogs.asp.net/pawanmishra/archive/2010/06/06/understanding-dispatcher-in-wpf.aspx

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.