none
How to replace pixels in a bitmap fast?

    Question

  • I want to replace pixels in Bitmap B with bright green if they are the same color as the same pixel in Bitmap A.

    I am trying to create something like gifcam but that doesn't overwrite files without asking and has higher quality when resizing images (gifcam looks very bad at anything other than 50% most of the time).

    But I don't know how I could do something like gifcam showing which pixels remain the same in the previous frame without taking forever, looping through a Bitmap's pixels takes a while and with 100+ frames of something like 900x900 pixels it might literally take hours. Gifcam manages that in seconds and even with a hundred frames near 1920 x 1080 it never takes more than half a minute.

    If it's not possible in C#, is there a windows dll I can call or something similar?

    I'd assuming replacing pixels to show difference in frames is the only thing that takes a long time, resizing a lot of frames is probably a lot faster?

    • Moved by CoolDadTx Monday, May 8, 2017 1:38 PM Winforms related
    Tuesday, April 25, 2017 8:41 AM

All replies

  • I'd expect there are ways to do that with GDI or GDI+, but I haven't used those in a while. I did something very similar using my company's own product (LEADTOOLS), which you can see here:
    https://www.leadtools.com/support/forum/posts/t12177-

    With 2 small images, the whole thing (without the Load and Save parts) takes less than one millisecond on a normal test PC. If the images are very large, it might take a couple of milliseconds.

    Monday, May 8, 2017 12:55 PM
  • You can see this article  : Fast Image Processing in C#
    Monday, May 8, 2017 1:12 PM
  • Hi,

    use the /unsafe switch in the project-properties and use a BitmapData object and pointers. Thats the fastest you can get in c# -> and it is really fast.

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    
    namespace WindowsFormsApplication1
    {
        public partial class Form1 : Form
        {
            Random _rnd = new Random();
    
            public Form1()
            {
                InitializeComponent();
                Init();
            }
    
            private void Form1_Load(object sender, EventArgs e)
            {
                Bitmap bmp = new Bitmap(this.pictureBox1.ClientSize.Width, this.pictureBox1.ClientSize.Height);
                using (Graphics g = Graphics.FromImage(bmp))
                {
                    g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                    g.Clear(Color.Green);
                    for (int i = 0; i < 4; i++)
                    {
                        using (SolidBrush sb = new SolidBrush(Color.FromArgb(_rnd.Next(256), _rnd.Next(256), _rnd.Next(256), _rnd.Next(256))))
                            g.FillEllipse(sb, new RectangleF(_rnd.Next(bmp.Width / 2), _rnd.Next(bmp.Width / 2), _rnd.Next(bmp.Width / 2), _rnd.Next(bmp.Width / 2)));
                    }
                }
    
                Bitmap bmp2 = (Bitmap)bmp.Clone();
                using (Graphics g = Graphics.FromImage(bmp2))
                {
                    g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
    
                    using (SolidBrush sb = new SolidBrush(Color.FromArgb(_rnd.Next(256), _rnd.Next(256), _rnd.Next(256), _rnd.Next(256))))
                        g.FillEllipse(sb, new RectangleF(_rnd.Next(bmp2.Width / 2), _rnd.Next(bmp2.Width / 2), _rnd.Next(bmp2.Width), _rnd.Next(bmp2.Width)));
                }
    
                this.pictureBox1.Image = bmp;
                this.pictureBox2.Image = bmp2;
    
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                this.pictureBox3.Image = CompareBitmaps((Bitmap)this.pictureBox1.Image, (Bitmap)this.pictureBox2.Image);
                this.pictureBox3.Refresh();
            }
    
            private Image CompareBitmaps(Bitmap image1, Bitmap image2)
            {
                if (image1.Width != image2.Width || image1.Height != image2.Height)
                    throw new Exception("Bitmaps must be of same size.");
    
                System.Drawing.Imaging.BitmapData bmData = null;
                System.Drawing.Imaging.BitmapData bmData2 = null;
    
                Bitmap bmpOUt = new Bitmap(image1.Width, image1.Height);
                System.Drawing.Imaging.BitmapData bmDataOut = null;
    
                try
                {
                    bmData = image1.LockBits(new Rectangle(0, 0, image1.Width, image1.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
                    bmData2 = image2.LockBits(new Rectangle(0, 0, image2.Width, image2.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
                    bmDataOut = bmpOUt.LockBits(new Rectangle(0, 0, bmpOUt.Width, bmpOUt.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
    
                    int stride = bmData.Stride;
                    int nW = image1.Width;
                    int nH = image1.Height;
    
                    unsafe
                    {
                        Parallel.For(0, nH, y =>
                        {
                            byte* p = (byte*)bmData.Scan0;
                            byte* p2 = (byte*)bmData2.Scan0;
                            byte* pOut = (byte*)bmDataOut.Scan0;
    
                            p += y * stride;
                            p2 += y * stride;
                            pOut += y * stride;
    
                            for (int x = 0; x < nW; x++)
                            {
                                if (p[0] != p2[0] || p[1] != p2[1] || p[2] != p2[2] || p[3] != p2[3])
                                {
                                    for (int i = 0; i < 3; i++)
                                    {
                                        pOut[i] = p2[i]; // (byte)Math.Abs(p[i] - p2[i]);    
                                    }
    
                                    pOut[3] = (byte)255;
                                }
    
                                p += 4;
                                p2 += 4;
                                pOut += 4;
                            }
                        });
                    }
    
                    image1.UnlockBits(bmData);
                    image2.UnlockBits(bmData2);
                    bmpOUt.UnlockBits(bmDataOut);
                }
                catch
                {
                    try
                    {
                        image1.UnlockBits(bmData);
                    }
                    catch
                    {
    
                    }
                    try
                    {
                        image2.UnlockBits(bmData2);
                    }
                    catch
                    {
    
                    }
                    try
                    {
                        bmpOUt.UnlockBits(bmDataOut);
                    }
                    catch
                    {
    
                    }
                }
    
                return bmpOUt;
            }
    
            //usually done with the Designer
            private System.Windows.Forms.Button button1;
            private System.Windows.Forms.PictureBox pictureBox1;
            private System.Windows.Forms.PictureBox pictureBox2;
            private System.Windows.Forms.PictureBox pictureBox3;
    
            private void Init()
            {
                this.button1 = new System.Windows.Forms.Button();
                this.pictureBox1 = new System.Windows.Forms.PictureBox();
                this.pictureBox2 = new System.Windows.Forms.PictureBox();
                this.pictureBox3 = new System.Windows.Forms.PictureBox();
                ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
                ((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).BeginInit();
                ((System.ComponentModel.ISupportInitialize)(this.pictureBox3)).BeginInit();
                this.SuspendLayout();
                // 
                // button1
                // 
                this.button1.Location = new System.Drawing.Point(597, 290);
                this.button1.Name = "button1";
                this.button1.Size = new System.Drawing.Size(75, 23);
                this.button1.TabIndex = 0;
                this.button1.Text = "button1";
                this.button1.UseVisualStyleBackColor = true;
                this.button1.Click += new System.EventHandler(this.button1_Click);
                // 
                // pictureBox1
                // 
                this.pictureBox1.Location = new System.Drawing.Point(13, 13);
                this.pictureBox1.Name = "pictureBox1";
                this.pictureBox1.Size = new System.Drawing.Size(276, 260);
                this.pictureBox1.TabIndex = 1;
                this.pictureBox1.TabStop = false;
                // 
                // pictureBox2
                // 
                this.pictureBox2.Location = new System.Drawing.Point(309, 13);
                this.pictureBox2.Name = "pictureBox2";
                this.pictureBox2.Size = new System.Drawing.Size(276, 260);
                this.pictureBox2.TabIndex = 1;
                this.pictureBox2.TabStop = false;
                // 
                // pictureBox3
                // 
                this.pictureBox3.Location = new System.Drawing.Point(597, 13);
                this.pictureBox3.Name = "pictureBox3";
                this.pictureBox3.Size = new System.Drawing.Size(276, 260);
                this.pictureBox3.TabIndex = 1;
                this.pictureBox3.TabStop = false;
                // 
                // Form1
                // 
                this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
                this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
                this.ClientSize = new System.Drawing.Size(890, 322);
                this.Controls.Add(this.pictureBox3);
                this.Controls.Add(this.pictureBox2);
                this.Controls.Add(this.pictureBox1);
                this.Controls.Add(this.button1);
                this.Name = "Form1";
                this.Text = "Form1";
                this.FormClosing += Form1_FormClosing;
                this.Load += new System.EventHandler(this.Form1_Load);
                ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
                ((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).EndInit();
                ((System.ComponentModel.ISupportInitialize)(this.pictureBox3)).EndInit();
                this.ResumeLayout(false);
            }
    
            private void Form1_FormClosing(object sender, FormClosingEventArgs e)
            {
                if (this.pictureBox1.Image != null)
                    this.pictureBox1.Image.Dispose();
                if (this.pictureBox2.Image != null)
                    this.pictureBox2.Image.Dispose();
                if (this.pictureBox3.Image != null)
                    this.pictureBox3.Image.Dispose();
            }
        }
    }
    Regards,


      Thorsten

    Monday, May 8, 2017 10:40 PM