Flash Light Effect Windows Forms Edited I am having performence issues with image processing task (flash light effect). I used c#, and used couple references (LockBits Method, Extension). The program has bad frame rates.

Edited the code, improvments were made but still doesn't match up to my expectations.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ImagePro
{
    public partial class Form1 : Form
    {
        Bitmap Dog;
        Rectangle rect;

        public Form1()
        {
            InitializeComponent();
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            Dog = new Bitmap(@"D:\Programs\VS 2013\Projectss\ImageProcessing\ImageProcessing\dog.jpg");
            rect = new Rectangle(0, 0, Dog.Width, Dog.Height);
            this.Width = Dog.Width;
            this.Height = Dog.Height;
            timer1.Interval = 100;
            timer1.Start();
            this.DoubleBuffered = true;
        }

        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            Bitmap tempImg = new Bitmap(Dog);
            BitmapData imgRawData = tempImg.LockBits(rect, ImageLockMode.ReadWrite, tempImg.PixelFormat);
            IntPtr arrStart = imgRawData.Scan0;

            int size = imgRawData.Stride * tempImg.Height;
            byte[] rgbValues = new byte[size];

            System.Runtime.InteropServices.Marshal.Copy(arrStart, rgbValues, 0, size);
            var absPos = PointToClient(Cursor.Position);
            for (int x = 0; x &lt; tempImg.Width; x++)
            {
                for (int y = 0; y &lt; tempImg.Height; y++)
                {
                    double distence = GetDistance(absPos.X, absPos.Y, x, y); //Distence from pixel to cursor
                    int pixelIndex = x * 4 + y * imgRawData.Stride;

                        for (int i = 0; i &lt; 3; i++)
                        {
                            if (distence &gt; rgbValues[pixelIndex + i])
                            {
                                rgbValues[pixelIndex + i] = 0; //Sets pixel to black
                            }
                            else
                            {
                                rgbValues[pixelIndex + i] -= (byte)distence; //Reduce pixel brightness                                                         
                            }
                        }
                        //rgbValues[pixelIndex];          //blue
                        //rgbValues[pixelIndex + 1];     //green
                        //rgbValues[pixelIndex + 2];    //red
                        //rgbValues[pixelIndex + 3];   // alpha
                }
            }
            System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, arrStart, size);
            tempImg.UnlockBits(imgRawData);
            e.Graphics.DrawImage(tempImg,0,0);
        }
        private static double GetDistance(double x1, double y1, double x2, double y2)
        {
            return Math.Sqrt(Math.Pow((x2 - x1), 2) + Math.Pow((y2 - y1), 2));
        }
        private void timer1_Tick(object sender, EventArgs e)
        {
            this.Invalidate();
        }
    }
}
I don't know much about C#, so this answer will focus solely on generic stuff. Performance problems in image processing applications usually happen inside loops over all pixels. I'm focusing on this section of the code:

for (int x = 0; x &lt; tempImg.Width; x++)
{
    for (int y = 0; y &lt; tempImg.Height; y++)
    {
        double distence = GetDistance(absPos.X, absPos.Y, x, y); //Distence from pixel to cursor
        int pixelIndex = x * 4 + y * imgRawData.Stride;

            for (int i = 0; i &lt; 3; i++)
            {
                if (distence &gt; rgbValues[pixelIndex + i])
                {
                    rgbValues[pixelIndex + i] = 0; //Sets pixel to black
                }
                else
                {
                    rgbValues[pixelIndex + i] -= (byte)distence; //Reduce pixel brightness                                                         
                }
            }
    }
}


You loop over all pixels, but only do something for those pixels close to absPos. The maximum distance over which your filter will have effect is 255, assuming that rgbValues is an 8-bit unsigned integer. Outside of that range, you always set pixels to 0.
Thus, you can loop over only those pixels within that range: x goes from max(absPos.X - 255, 0) to min(absPos.X + 255, tempImg.Width - 1), and similarly for the y-coordinate (maybe this is Math.Max and Math.Min in C#?). Outside of that range simply fill with zeros.

Next, GetDistance computes the square root, which is quite expensive. It is a lot cheaper to compute the square of a value. We also know that if a &lt; b, then a*a &lt; b*b. So instead write a function GetSquareDistance, which returns Math.Pow((x2 - x1), 2) + Math.Pow((y2 - y1), 2), and compare the square distance to the square of the pixel's value. By not computing the square root, all operations can be done as integers, which might or might not be faster.

This function GetSquareDistance can actually be further improved by computing Math.Pow((y2 - y1), 2) once outside the loop over x, then adding only the square of the x-difference inside the loop.

Finally, the innermost if statement also duplicates work. I presume that a good optimizing compiler will correct this, but in principle distence &gt; rgbValues[pixelIndex + i] computes the difference and compares to 0, then inside the loop you again compute the same difference. Using a max function would improve this conditional statement:

int diff = (int)rgbValues[pixelIndex + i] - (int)distence;
rgbValues[pixelIndex + i] = (byte)max(diff, 0); // again, maybe Math.Max?


(using int in case integer subtraction is faster than floating-point subtraction.)



Another issue I've just noticed: You loop over y in the inner loop, and over x in the outer loop. If you reverse these two loops, then the array will be accessed in storage order (pixelIndex = x * 4 + y * imgRawData.Stride will increase monotonically). With this access pattern, the cache will be used optimally, and the code should be quite a bit faster.

The code would look like this (not tested, sorry for any typo):

int firstX = max(absPos.X - 255, 0); // max and min could be Math.Max and Math.Min?
int lastX = min(absPos.X + 255, tempImg.Width - 1) + 1;
int firstY = max(absPos.Y - 255, 0);
int lastY = min(absPos.Y + 255, tempImg.Height - 1) + 1;
int pixelIndex = 0;
for (int y = 0; y &lt; firstY; y++)
{
    SetRowToZero(rgbValues + pixelIndex, tempImg.Width); // This function iterates over a line of the image and sets it to 0
    pixelIndex += imgRawData.Stride;
}
for (int y = firstY; y &lt; lastY; y++)
{
    int yDistance2 = absPos.Y - y;
    yDistance2 = yDistance2 * yDistance2;

    SetRowToZero(rgbValues + pixelIndex, firstX); // Here the function sets the first set of pixels in the line to 0

    int index = pixelIndex + firstX * 4;
    for (int x = firstX; x &lt; lastX; x++)
    {
        int xDistance2 = absPos.X - x;
        xDistance2 = xDistance2 * xDistance2;
        int distance2 = xDistance2 + yDistance2;
        for (int i = 0; i &lt; 3; i++)
        {
            int value2 = rgbValues[index + i];
            value2 = value2 * value2 - distance2;
            if (value2 &lt;= 0)
            {
                rgbValues[index + i] = 0; // Sets pixel to black
            }
            else
            {
                rgbValues[index + i] = (byte)Math.Sqrt(value2); // Reduce pixel brightness                                                         
            }
        }
        index += 4;
    }

    SetRowToZero(rgbValues + index, tempImg.Width - lastX); // Here the function sets the last set of pixels in the line to 0

    pixelIndex += imgRawData.Stride;
}
for (int y = lastY; y &lt; tempImg.Height; y++)
{
    SetRowToZero(rgbValues + pixelIndex, tempImg.Width);
    pixelIndex += imgRawData.Stride;
}




Additional comments:


Typo: "distence" should be "distance"
Don't leave commented-out code in your source files. They tend to be confusing. If you do, at least add a clear bit of comment text to indicate why the code is commented out.