我正在尝试将Matlab MWNumericArray
转换为黑白图片(不是灰度)。最初,我尝试将2D字节数组转换为1D字节数组,然后将其复制到BitmapData对象并在Bitmap中进行转换,但是没有用,因为尝试操作此数据时我必须犯一些错误。
有效的方法是将我从其他答案和在线文档中获得的代码混合在一起。以下是有效的方法和无效的方法。
问题:
是否有一种简单的方法,可以从byte[,]
数组开始,而不使用GetPixel
或Clone
方法,将8bpp位图转换为1bpp,一次或一个字节地复制?允许使用不安全的代码。
我尝试过的方法(有效):
// Most of this code is based on a Jon Skeet's answer.
// resultOut[0] is a 2D 356x356 MWArray
var numArray = (MWNumericArray)resultOut[0];
var data = numArray.ToArray(MWArrayComponent.Real) as byte[,];
var w = data.GetLength(0);
var h = data.GetLength(1);
unsafe
{
fixed (byte* ptr = data)
{
var scan0 = new IntPtr(ptr);
var bpm1 = new Bitmap(
w, h, // image size
w, // scan size
PixelFormat.Format8bppIndexed, scan0);
// works but is grayscale, not B&W
var palette = bpm1.Palette;
palette.Entries[0] = Color.Black;
for (var i = 1; i < 256; i++)
{
palette.Entries[i] = Color.FromArgb((i * 7) % 256, (i * 7) % 256, 255);
}
bpm1.Palette = palette;
bpm1.Save("output.grayscale.png");
// works but with additional helper method call
// based on a Hans Passant answer
var bpm2 = BitmapTo1Bpp(bpm1);
bpm2.Save("output.helper.png");
// works but uses Clone
var bpm3 = bpm1.Clone(new Rectangle(0, 0, bpm1.Width, bpm1.Height), PixelFormat.Format1bppIndexed);
bpm3.Save("output.clone.png");
}
}
我尝试过的方法(没有用):
if (numArray.ToArray(MWArrayComponent.Real) is byte[,] data)
{
// Convert to 1D byte array
var h = data.GetLength(1);
var w = data.GetLength(0);
var byteArray1D = new byte[h * w];
for (var i = 0; i < h; i++)
{
for (var j = 0; j < w; j++)
{
byteArray1D[i + j] = data[i, j];
}
}
// Create Bitmap object
var bmp = new Bitmap(w, h, PixelFormat.Format8bppIndexed);
//// Set palette
// var cp = bmp.Palette;
// for (var i = 0; i < 256; ++i)
// {
// cp.Entries[i] = Color.FromArgb(255, i, i, i);
// }
// bmp.Palette = cp;
var bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height),
ImageLockMode.WriteOnly,
bmp.PixelFormat);
Marshal.Copy(byteArray1D,
0,
bmpData.Scan0,
byteArray1D.Length);
bmp.UnlockBits(bmpData);
// Does not work: graphic object cannot be created from an image that has an indexed pixel format
using (var g = Graphics.FromImage(bmp))
{
g.Clear(Color.White);
}
// Does not work: saves all black image
bmp.Save("output.raw.png");
using (var ms = new MemoryStream())
{
ms.Write(byteArray1D, 0, byteArray1D.Length);
ms.Seek(0, SeekOrigin.Begin); // ms.Position = 0;
// Does not work: parameter is not valid exception
var bm = new Bitmap(ms);
bm.Save("output.ms.png");
// Does not work: parameter is not valid exception
var newImage = Image.FromStream(ms);
newImage.Save("output.fromstream.png");
}
}