Page 1 of 1

IntensityPoint in IntensityGridSeries

Posted: Tue Mar 25, 2014 1:29 pm
by juergen
Hi,
I get images from a ccd camera with a resolution of 1280x1024 pixels.
The data I get is a standard RGB format. I store them as an RGB coded integer format (ARGB).

For displaying the data I use IntensityPoints with IntensityGridSeries in a ViewXY.
It looks good, but I only get about 2-4 images/second.
If I use just Intensity data(heatmap) and Update them by SetValuesData(...) I get about 10 frames/second which is ok.

Are the color values calculated by a shader inside the graphics-card?
If yes, is it a problem to implement a shader with RGB values instead of intensity values to get it faster?

Best,
Jürgen

Re: IntensityPoint in IntensityGridSeries

Posted: Tue Mar 25, 2014 1:59 pm
by ArctionPasi
When you present it with Fill=Paletted, the colors get decoded in the GPU shader.

Are you now looking for an option to show your data more quickly by using the source point colors (Fill = FromSurfacePoints) without the ValueRangePalette encoding the colors?

Re: IntensityPoint in IntensityGridSeries

Posted: Tue Mar 25, 2014 2:05 pm
by juergen
That's exactly what I'm looking for.

Re: IntensityPoint in IntensityGridSeries

Posted: Wed Mar 26, 2014 9:40 am
by ArctionPasi
I believe you are using it with PixelRendering = true, right?

The overhead comes from converting the integer ARGB to Color and in data update stage converting that Color back to 32-bit ARGB. The conversions in WPF are way heavier than in Winforms.

So we'd need to add an equivalent to SetValuesData method, say SetColorsData, that would accept a jagged array of type int[][]. It would work a lot faster. Even faster than SetValuesData. Adding this feature as fully functional feature will be several days of work to us, and we are already busy with v.6 development schedule, so I have to propose we'll implement this during next 6 months.

Re: IntensityPoint in IntensityGridSeries

Posted: Wed Mar 26, 2014 10:28 am
by juergen
I had a look in the source and isn't it possible to add a PixelShader to calculate the color from the integer value instead of the Palette values?
If you say "yes" I can try it on my own and write you the result.

I forgot:
In this case I don't need PixelRendering - it doesn't matter if it's used or not.
It's just the speed that is important.

Re: IntensityPoint in IntensityGridSeries

Posted: Wed Mar 26, 2014 10:52 am
by ArctionPasi
I don't see reason to make it in the shader side...

If using PixelRendering = true, it uses a texture, which takes bitmap bytes in (like your ARGB data). It's then in correct color already, and using a PixelShader only slows it down.

If using PixelRendering = false, vertices are used. Each vertex needs already 32-bit ARGB integer as color.

So you you may want to investigate how to input your array in these.

Re: IntensityPoint in IntensityGridSeries

Posted: Thu Sep 25, 2014 3:54 pm
by quarz
That would be great!
Besides ARGB, it would be useful to have formats RGB, Grayscale 8 bit and Grayscale 16 bit, to avoid unnecessary copying
ArctionPasi wrote: So we'd need to add an equivalent to SetValuesData method, say SetColorsData, that would accept a jagged array of type int[][]. It would work a lot faster. Even faster than SetValuesData. Adding this feature as fully functional feature will be several days of work to us, and we are already busy with v.6 development schedule, so I have to propose we'll implement this during next 6 months.

Re: IntensityPoint in IntensityGridSeries

Posted: Fri Sep 26, 2014 8:46 am
by quarz
When do you plan to do this feature?

Re: IntensityPoint in IntensityGridSeries

Posted: Sat Sep 27, 2014 10:22 pm
by ArctionPasi
This is now done and will be included in 6.2 next week.

EDIT: but we are not going to implement grayscale. Convert the grayscale to ARGB (int) on your side.

Re: IntensityPoint in IntensityGridSeries

Posted: Tue Sep 30, 2014 10:08 am
by quarz
I tried to use SetColorsData, but did not notice the speed increase. On the contrary, "SetColorsData" is in 2 times slower than the "SetValuesData".
Could you check my sources, maybe i did not properly use this feature

Re: IntensityPoint in IntensityGridSeries

Posted: Tue Sep 30, 2014 2:00 pm
by ArctionPasi
- You don't need to use SetValuesData, only setColorsData, and after updating, call InvalidateColorsOnly.
- Set Fill property only in initialization stage, not every time you update the chart.
- Take SizeX and SizeY out of the loop, otherwise it causes and expensive DependencyProperty call for every cell.
- After these, rnd.Next becomes a bottleneck. You may want to use Parallel.For loop for updating.


Use this code:

Code: Select all

 public partial class MainWindow : Window
    {
        IntensityGridSeries chartData = null;

        public MainWindow()
        {
            InitializeComponent();

            chart1.BeginUpdate();

            chart1.ActiveView = ActiveView.ViewXY;
            chart1.ViewXY.XAxes[0].ValueType = AxisValueType.Number;
            chart1.ViewXY.YAxes[0].ValueType = AxisValueType.Number;
            chart1.ViewXY.XAxes[0].SetRange(0, 1088);
            chart1.ViewXY.YAxes[0].SetRange(0, 1024);
            chart1.ViewXY.LegendBox.Visible = false;

            chartData = new IntensityGridSeries(chart1.ViewXY, chart1.ViewXY.XAxes[0], chart1.ViewXY.YAxes[0]);
            chartData.SetSize(1088, 1024);
            chartData.SetRangesXY(0, 1088, 0, 1024);            
            chartData.MouseInteraction = false;
            chartData.Optimization = IntensitySeriesOptimization.DynamicValuesData;
            chartData.ShowNodes = false;
            chartData.PixelRendering = true;
            chartData.Fill = IntensityFillStyle.FromSurfacePoints; //PT

            chart1.ViewXY.IntensityGridSeries.Add(chartData);

            int iSizeY =  chartData.SizeY;
            int iSizeX = chartData.SizeX; 

            // Set geometry; NOT NEEDED.
            
            //for (int i = 0; i <iSizeY; i++)
            //{
            //    for (int j = 0; j < iSizeY; j++)
            //    {
            //        chartData.Data[j, i].X = i;
            //        chartData.Data[j, i].Y = j;
            //    }
            //}

            pixels = new int[iSizeY][];

            for (int i = 0; i < iSizeY; i++)
            {
                pixels[i] = new int[iSizeX];
            }

            chart1.EndUpdate();


            chartData.SetColorsData(pixels, IntensityGridValuesDataOrder.RowsColumns);  

            System.Windows.Threading.DispatcherTimer ttm = new System.Windows.Threading.DispatcherTimer();
            //ttm.Interval = new TimeSpan(0, 0, 0, 0, 500);
            ttm.Interval = new TimeSpan(0, 0, 0, 0, 1);
            ttm.Tick += new EventHandler(Update);
            ttm.Start();
        }

      
        int[][] pixels = null;

        void Update(object sender, EventArgs e)
        {
            Random rnd = new Random();

            st.Restart();
            int iSizeY = chartData.SizeY;
            int iSizeX = chartData.SizeX; 
            
            // Fill with random data
            int iRandomColor = 255 << 24 | (rnd.Next() % 255) << 16 | (rnd.Next() % 255) << 8 | (rnd.Next() % 255);
            for (int i = 0; i < iSizeY; i++)
            {
                for (int j = 0; j < iSizeX; j++)
                {
                    //rnd.Next becomes the bottleneck. 

                    //pixels[i][j] = 255 << 24 | (rnd.Next() % 255) << 16 | (rnd.Next() % 255) << 8 | (rnd.Next() % 255); 
                    pixels[i][j] = iRandomColor;
                }
            }

            st.Stop();

            // doesn't matter
            wnd.Title = "";// "Prepare data: " + st.ElapsedMilliseconds.ToString() + " ms. ";

            
            st.Restart();

            chart1.BeginUpdate();

            
            chartData.InvalidateColorsOnly(); 
            
            chart1.EndUpdate();

            st.Stop();

            wnd.Title += "Redraw: " + st.ElapsedMilliseconds.ToString() + " ms";
        }

        Stopwatch st = new Stopwatch();
    }


and it's solid 60 FPS refresh rate.