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.