在图像文件上大量循环,帧以7 fps左右倾斜,我需要更高

时间:2016-03-17 16:29:24

标签: c# image performance

我目前正在尝试新技术来浏览图像上的每个像素并为每个像素执行一些小的处理。这是我的有效代码:

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;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
namespace ImageProcessingExmp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        Timer timer = new Timer();
        private void Form1_Load(object sender, EventArgs e)
        {
            timer.Tick += ChangeColor;
            timer.Interval = 1;
            timer.Start();
            pictureBox1.Width = this.Width;
            pictureBox1.Height = this.Height;
            pictureBox1.Left = 0;
            pictureBox1.Top = 0;
            this.WindowState = FormWindowState.Maximized;
        }
        int timerinc = 0;
        public void ChangeColor(object sender, EventArgs e)
        {
            if (timerinc>=240)
           {
                timer.Stop();
            }
            timerinc+=10;
            Bitmap bmp = (Bitmap)new Bitmap(this.Width,this.Height);
            Benchmark.Start();
            ///////////////////////////////////////////////////////////////////////////////


            // Get the area to be painted
            Rectangle areaToPaint = new Rectangle();

            BitmapData data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            int stride = data.Stride;
            Random rnd = new Random(DateTime.Now.Millisecond);
            unsafe
            {
                byte* ptr = (byte*)data.Scan0;
                // Check this is not a null area

                    // Go through the draw area and set the pixels as they should be
                    for (int y = 0; y < bmp.Height; y++)
                    {
                        for (int x = 0; x < bmp.Width; x++)
                        {
                            // layer.GetBitmap().SetPixel(x, y, m_colour);
                            byte x2 = Convert.ToByte(x > 255 ? 0 : x);
                            byte y2 = Convert.ToByte(y > 255 ? 0 : y);
                            ptr[(x * 3) + y * stride] = x2;
                            ptr[(x * 3) + y * stride + 1] = y2;
                            ptr[(x * 3) + y * stride + 2] = 255;
                        }
                    }

            }
            bmp.UnlockBits(data);
            /////////////////////////////////////////////////////////////////////////////////
            Benchmark.End();
            double seconds = Benchmark.GetSeconds();
            //MessageBox.Show(seconds.ToString());
            richTextBox1.Text += seconds.ToString()+'\n' ;
            richTextBox2.Text += DateTime.Now.Second.ToString()+'\n';
            pictureBox1.Image=  bmp;
            String[] lines = richTextBox1.Text.Split('\n');
            double avg = 0;
            double sum = 0;
            double num = 0;
            foreach (var line in lines)
            {
                // MessageBox.Show(line);
                double tet = 0;
                Double.TryParse(line, out tet);
                sum += tet;
                num++;
            }
            avg = sum / num;
            label1.Text = "fps = " + (1/avg).ToString();
        }
        public class Benchmark
        {
            private static DateTime startDate = DateTime.MinValue;
            private static DateTime endDate = DateTime.MinValue;

            public static TimeSpan Span { get { return endDate.Subtract(startDate); } }

            public static void Start() { startDate = DateTime.Now; }

            public static void End() { endDate = DateTime.Now; }

            public static double GetSeconds()
            {
                if (endDate == DateTime.MinValue) return 0.0;
                else return Span.TotalSeconds;
            }
        }


    }
}

我需要将FPS提升至90 fps左右。我怎样才能做到这一点?我需要使用C#以外的东西吗?目前的fps约为7。

enter image description here

编辑1 堆栈溢出编辑出我的一些文字..很奇怪...... 这是真正不安全的代码。

unsafe
        {
            byte* ptr = (byte*)data.Scan0;
            // Check this is not a null area

                // Go through the draw area and set the pixels as they should be
                for (int y = 0; y< bmp.Height; y++)
                {
                    for (int x = 0; x < bmp.Width; x++)
                    {
                        // layer.GetBitmap().SetPixel(x, y, m_colour);
                        byte x2 = Convert.ToByte(x > 255 ? 0 : x);
                        byte y2 = Convert.ToByte(y > 255 ? 0 : y);
                        ptr[(x * 3) + y * stride] = x2;
                        ptr[(x * 3) + y * stride + 1] = y2;
                        ptr[(x * 3) + y * stride + 2] = 255;
                    }
                }

        }

编辑2 哇......它又做了......我用(LESSTHAN)替换少于符号

unsafe
        {
            byte* ptr = (byte*)data.Scan0;
            // Check this is not a null area

                // Go through the draw area and set the pixels as they should be
                for (int y = 0; y < bmp.Height; y++)
                {
                    for (int x = 0; x < bmp.Width; x++)
                    {
                        // layer.GetBitmap().SetPixel(x, y, m_colour);
                        byte x2 = Convert.ToByte(x > 255 ? 0 : x);
                        byte y2 = Convert.ToByte(y > 255 ? 0 : y);
                        ptr[(x * 3) + y * stride] = x2;
                        ptr[(x * 3) + y * stride + 1] = y2;
                        ptr[(x * 3) + y * stride + 2] = 255;
                    }
                }                
        }

编辑3 尝试将格式更改为PixelFormat.Format32bppPArgb。没有工作。明白啦: Click to view image

编辑4 对代码进行了大量更改。这是当前的代码:

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;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
namespace ImageProcessingExmp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        Timer timer = new Timer();
        private void Form1_Load(object sender, EventArgs e)
        {
            timer.Tick += ChangeColor;
            timer.Interval = 1;
            timer.Start();
            pictureBox1.Width = this.Width;
            pictureBox1.Height = this.Height;
            pictureBox1.Left = 0;
            pictureBox1.Top = 0;
            this.WindowState = FormWindowState.Maximized;
            bmp=(Bitmap)new Bitmap(this.Width, this.Height);
        }
        int timerinc = 0;
        int stride;
        Bitmap bmp;
        BitmapData data;
        public void ChangeColor(object sender, EventArgs e)
        {

            timerinc+=10;
            Benchmark.Start();
            ///////////////////////////////////////////////////////////////////////////////



           data=   bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
             stride = data.Stride;
            unsafe
            {
                byte* ptr = (byte*)data.Scan0;
                // Check this is not a null area

                // Go through the draw area and set the pixels as they should be
                for (int y = 0; y < bmp.Height; y++)
                {
                    int yTimeStride = y * stride;
                    byte y2 = (byte)(y > 255 ? 0 : y);

                    for (int x = 0; x < bmp.Width; x++)
                    {
                        int addressToAssign = (x * 3) + yTimeStride;
                        byte x2 = (byte)(x > 255 ? 0 : x);
                        ptr[addressToAssign] = x2;
                        ptr[addressToAssign + 1] = y2;
                        ptr[addressToAssign + 2] = x2;
                    }
                }

            }
            bmp.UnlockBits(data);
            /////////////////////////////////////////////////////////////////////////////////
            Benchmark.End();
            double seconds = Benchmark.GetSeconds();
            //MessageBox.Show(seconds.ToString());
            richTextBox1.Text += seconds.ToString()+'\n' ;
            richTextBox2.Text += DateTime.Now.Second.ToString()+'\n';
            pictureBox1.Image=  bmp;
            String[] lines = richTextBox1.Text.Split('\n');
            double avg = 0;
            double sum = 0;
            double num = 0;
            foreach (var line in lines)
            {
                // MessageBox.Show(line);
                double tet = 0;
                Double.TryParse(line, out tet);
                sum += tet;
                num++;
            }
            avg = sum / num;
            label1.Text = "fps = " + (1/avg).ToString();
            tst1.Add(1/avg*20);
            if (timerinc >= 500)
            {
                timer.Stop();
                Bitmap bmp2 = new Bitmap(pictureBox2.Width,pictureBox2.Height);


                data = bmp2.LockBits(new Rectangle(0, 0, bmp2.Width, bmp2.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                stride = data.Stride;
                unsafe
                {
                    byte* ptr = (byte*)data.Scan0;
                    // Check this is not a null area

                    // Go through the draw area and set the pixels as they should be
                    for (int x = 0; x < tst1.Count; x++)
                    {
                        for (int y = 0; y < (int)tst1[x]; y++)
                        {
                            //MessageBox.Show(x.ToString());
                            if (y<bmp2.Height)
                            {
                                ptr[(x * 3) + (int)y * stride] = 255;//b
                                ptr[(x * 3) + (int)y * stride + 1] =0;//g
                                ptr[(x * 3) + (int)y * stride + 2] = 255;//r
                            }
                        }
                    }
                }
                bmp2.UnlockBits(data);
                pictureBox2.Image = bmp2;
            }
        }
        public List<double> tst1 = new List<double>();
        public class Benchmark
        {
            private static DateTime startDate = DateTime.MinValue;
            private static DateTime endDate = DateTime.MinValue;

            public static TimeSpan Span { get { return endDate.Subtract(startDate); } }

            public static void Start() { startDate = DateTime.Now; }

            public static void End() { endDate = DateTime.Now; }

            public static double GetSeconds()
            {
                if (endDate == DateTime.MinValue) return 0.0;
                else return Span.TotalSeconds;
            }
        }


    }
}

不幸的是,这只能让我获得5 fps。我开始相信在位图上绘画然后将它放到屏幕上并不是快速渲染游戏的方法。有人知道另一种方式吗?

1 个答案:

答案 0 :(得分:0)

考虑您正在进行基准测试的代码:

  • rnd没用(错误的复制/粘贴?)
  • 你做的太多了,考虑使用:

代码:

for (int y = 0; y < bmp.Height; y++)
{
    int yTimeStride = y * stride;
    byte y2 = Convert.ToByte(y > 255 ? 0 : y);

    for (int x = 0; x < bmp.Width; x++)
    {
        int addressToAssign = (x * 3) + yTimeStride;
        byte x2 = Convert.ToByte(x > 255 ? 0 : x);
        ptr[addressToAssign] = x2;
        ptr[addressToAssign + 1] = y2;
        ptr[addressToAssign + 2] = 255;
    }
}

这会减少yHeight*Width*3Height的乘法,并将x乘以3减少。