Home > Blockchain >  Convert a Grid of doubles back into a Bitmap
Convert a Grid of doubles back into a Bitmap

Time:08-03

I'm interested in comparing two images using Structural Similarity Index (SSIM) in C#, I've found some code (https://www.lomont.org/software/misc/ssim/SSIM.html) which looks like it'll get me 90% of the way there but I would like to convert the Grid of doubles which results from the SIMM back into a greyscale bitmap so I can highlight the areas of difference, any ideas on how to proceed?

        static Grid ConvertBitmap(Bitmap bmp)                                                                                                       
        {                                                                                                                                       
        return Grid.Op((i, j) => { Color c = bmp.GetPixel(i, j); return 0.3 * c.R   0.59 * c.G   0.11 * c.B; }, new Grid(bmp.Width,bmp.Height));
        }


   class Grid                                                                                                                                  
        {                                                                                                                                       
        double[,] data;                                                                                                                         
        internal int width, height;                                                                                                             
        internal Grid(int w, int h)                                                                                                             
            {                                                                                                                                   
            data = new double[w, h];                                                                                                            
            width = w;                                                                                                                          
            height = h;                                                                                                                         
            }                                                                                                                                   
                                                                                                                                                
        /// <summary>                                                                                                                           
        /// Indexer to read the i,j item                                                                                                        
        /// </summary>                                                                                                                          
        /// <param name="i"></param>                                                                                                            
        /// <param name="j"></param>                                                                                                            
        /// <returns></returns>                                                                                                                 
        internal double this[int i, int j]                                                                                                      
            {                                                                                                                                   
            get { return data[i, j]; }                                                                                                          
            set { data[i, j] = value; }                                                                                                         
            }                                                                                                                                   
                                                                                                                                                
        /// <summary>                                                                                                                           
        /// Get the summed value from the Grid                                                                                                  
        /// </summary>                                                                                                                          
        internal double Total                                                                                                                   
            {                                                                                                                                   
            get                                                                                                                                 
                {                                                                                                                               
                double s = 0;                                                                                                                   
                foreach (var d in data) s  = d;                                                                                                 
                return s;                                                                                                                       
                }                                                                                                                               
            }                                                                                                                                   
                                                                                                                                                
        /// <summary>                                                                                                                           
        /// componentwise addition of Grids                                                                                                     
        /// </summary>                                                                                                                          
        /// <param name="a"></param>                                                                                                            
        /// <param name="b"></param>                                                                                                            
        /// <returns></returns>                                                                                                                 
        static public Grid operator (Grid a, Grid b)                                                                                            
            {                                                                                                                                   
            return Op((i,j)=>a[i,j] b[i,j],new Grid(a.width,a.height));                                                                         
            }                                                                                                                                   
                                                                                                                                                
        /// <summary>                                                                                                                           
        /// componentwise subtraction of Grids                                                                                                  
        /// </summary>                                                                                                                          
        /// <param name="a"></param>                                                                                                            
        /// <param name="b"></param>                                                                                                            
        /// <returns></returns>                                                                                                                 
        static public Grid operator-(Grid a, Grid b)                                                                                            
            {                                                                                                                                   
            return Op((i, j) => a[i, j] - b[i, j], new Grid(a.width, a.height));                                                                
            }                                                                                                                                   
                                                                                                                                                
        /// <summary>                                                                                                                           
        /// componentwise multiplication of Grids                                                                                               
        /// </summary>                                                                                                                          
        /// <param name="a"></param>                                                                                                            
        /// <param name="b"></param>                                                                                                            
        /// <returns></returns>                                                                                                                 
        static public Grid operator*(Grid a, Grid b)                                                                                            
            {                                                                                                                                   
            return Op((i, j) => a[i, j] * b[i, j], new Grid(a.width, a.height));                                                                
            }                                                                                                                                   
                                                                                                                                                
        /// <summary>                                                                                                                           
        /// componentwise division of Grids                                                                                                     
        /// </summary>                                                                                                                          
        /// <param name="a"></param>                                                                                                            
        /// <param name="b"></param>                                                                                                            
        /// <returns></returns>                                                                                                                 
        static public Grid operator/(Grid a, Grid b)                                                                                            
            {                                                                                                                                   
            return Op((i, j) => a[i, j] / b[i, j], new Grid(a.width, a.height));                                                                
            }                                                                                                                                   
                                                                                                                                                
        /// <summary>                                                                                                                           
        /// Generic function maps (i,j) onto the given grid                                                                                     
        /// </summary>                                                                                                                          
        /// <param name="f"></param>                                                                                                            
        /// <param name="a"></param>                                                                                                            
        /// <returns></returns>                                                                                                                 
        static internal Grid Op(Func<int,int,double> f,Grid g)                                                                                  
            {                                                                                                                                   
            int w = g.width, h = g.height;                                                                                                      
            for (int i = 0; i < w;   i)                                                                                                         
                for (int j = 0; j < h;   j)                                                                                                     
                    g[i, j] = f(i,j);                                                                                                           
            return g;                                                                                                                           
            }                                                                                                                                   
                                                                                                                                                
        }

Initial attempt to implement a Grid to bitmap converter, based on my apparently faulty understanding of the help kindly provided, minDoubleValue = -0.42671891773398934, maxDoubleValue = 1 (range should be 0,1), and the produced butmap is black

    static void ConverGrid(Grid grid)
    {
        double maxDoubleValue = grid[0,0];
        double minDoubleValue = grid[0,0];

        for (int i = 0; i < grid.width; i  )
        {
            for (int j = 0; j < grid.height; j  )
            {
                if(grid[i, j] >= maxDoubleValue)
                {
                    maxDoubleValue = grid[i, j];
                }
                else if (grid[i, j] <= minDoubleValue)
                {
                    minDoubleValue = grid[i, j];
                }
            }
        }

        var delta = maxDoubleValue - minDoubleValue;

        Bitmap bmp = new Bitmap(grid.width, grid.height);
        for (int i = 0; i < grid.width; i  )
        {
            for (int j = 0; j < grid.height; j  )
            {

                var scaledValue = (grid[i,j] - minDoubleValue) / delta; // in [0,1] range
                var byteValue = (byte)(scaledValue * byte.MaxValue);
                bmp.SetPixel(i, j, Color.FromArgb(byte.MaxValue, byteValue, byteValue, byteValue));
            }
        }
        bmp.Save("test", ImageFormat.Bmp);

    }

CodePudding user response:

You need to scale your pixels somehow. Typically this would be a linear scaling between min and max. I.e.

var delta = maxDoubleValue - minDoubleValue;
var scaledValue = (doubleValue - minDoubleValue) / delta; // in [0,1] range
var byteValue = (byte)(scaledValue * byte.Max);

Once you have a properly scaled value you can just convert it to a color and use SetPixel to update your bitmap:

bmp.SetPixel(i,j, Color.FromArgb(byte.MaxValue, byteValue, byteValue, byteValue));

If you want better performance you can take a look at how to use pointers to update pixels much faster.

  • Related