将 HImage 转换为 byte[],就像 File.ReadAllBytes() 对 .png 文件所做的那样。

huangapple go评论54阅读模式
英文:

Convert HImage to byte[] as File.ReadAllBytes() does with .png

问题

HalconDotNet.HOperatorSet.ReadImage(out HObject image, srcPath);
//...
//(graphic stuff)
//...
HalconDotNet.HOperatorSet.WriteImage(imagePart, "png", 0, tmpImgPath); // skip these steps
Image = File.ReadAllBytes(path)                                        // skip these steps

这段代码被执行了成千上万次。最后两步只是为了在Halcon和.NET之间有一个兼容性步骤,因为我不知道如何将它们结合起来。

我需要一种将HImage(HObject)转换为byte[]的方法,就像WriteImage() + File.ReadAllBytes(path)所做的那样。最后一部分很重要,因为这段代码生成了用于图像分类模型的输入数据。

由于模型是用从磁盘加载的数据训练的,使用File.ReadAllBytes(path),我假设在使用模型时需要以相同的方式准备数据。当我使用File.ReadAllBytes()读取一个100x100的彩色PNG图像(单色)时,我不会得到100x100x3字节,而是342字节,所以我假设数据仍然是压缩的,进一步假设在使用模型时需要确保类似的数据。

这个问题与这个问题有一些重叠,但我需要一个byte[]而不是位图,而且就是无法让它工作。

英文:
HalconDotNet.HOperatorSet.ReadImage(out HObject image, srcPath);
//...
//(graphic stuff)
//...
HalconDotNet.HOperatorSet.WriteImage(imagePart, "png", 0, tmpImgPath); // skip these steps
Image = File.ReadAllBytes(path)                                        // skip these steps

This piece of code is executed thousands of times. The last two steps are just there to have a compatibility step in between Halcon and .NET as I dont know how to combine them.

What I need is a way to convert a HImage(HObject) to a byte[], the same way WriteImage() + File.ReadAllBytes(path) would do. This last bit is important as this piece of code generates inputs for image classification models.

As the models are trained with data loaded from disk with File.ReadAllBytes(path) I'm assuming I need to prepare the data in the same way when using the model. When I read a 100x100 color PNG (solid color) with File.ReadAllBytes() I don't get 100x100x3 bytes, but 342, so I'm assuming the data is still compressed, and further assuming that I need to guarantee similar data when using the model.

This question has some overlap with this one but I need a byte[] instead of bitmap and just can't get it to work.

答案1

得分: 1

以下是代码的翻译部分:

另一种方法是将hImage转换为位图,然后将此位图序列化为字节数组。

以下是将hImage转换为System.Drawing.Bitmap的函数

public static Bitmap HImageToBitmap(HImage ho_Image) {
    int iWidth, iHeight, iNumChannels;
    IntPtr ip_R, ip_G, ip_B, ip_Gray;
    String sType;
    // 空返回对象
    Bitmap bitmap = null;
    try {
        //
        // 请注意,像素数据在System.Drawing.Bitmap中以不同的方式存储
        // a) Stride:
        // stride是宽度,四舍五入为4的倍数(填充)
        // 数据数组的大小 HALCON: 高度*宽度,Bitmap: 高度*stride
        // 比较:https://msdn.microsoft.com/en-us/library/zy1a2d14%28v=vs.110%29.aspx
        // b) RGB数据
        // HALCON: 三个数组,Bitmap: 一个数组(交替红/绿/蓝)
        iNumChannels = ho_Image.CountChannels();
        if (iNumChannels != 1 && iNumChannels != 3)
            throw new Exception("将HImage转换为Bitmap失败。HImage的通道数为:" +
                iNumChannels + "。仅适用于具有1个或3个通道的图像的转换规则");
        if (iNumChannels == 1) {
            //
            // 1) 获取图像指针
            ip_Gray = ho_Image.GetImagePointer1(out sType, out iWidth, out iHeight);
            //
            // 2) 计算Stride
            int iPadding = (4 - (iWidth % 4)) % 4;
            int iStride = iWidth + iPadding;
            //
            // 3) 创建一个新的灰度位图对象,分配所需的(托管)内存
            bitmap = new Bitmap(iWidth, iHeight, PixelFormat.Format8bppIndexed);
            // 高性能的注意事项:如果填充=0,图像可以通过引用复制。
            // 但是,然后位图的有效性依赖于HImage的生命周期。
            // bitmap = new Bitmap(iWidth, iHeight, iWidth, PixelFormat.Format8bppIndexed, ip_Gray);
            //
            // 4) 直接将图像数据复制到所需的位图顺序的位图数据对象中
            // BitmapData允许我们访问内存中的数据
            BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, iWidth, iHeight),
                ImageLockMode.WriteOnly, bitmap.PixelFormat);
            // 并行处理需要.NET Framework >= 4.0
            Parallel.For(0, iHeight, r => {
                IntPtr posRead = ip_Gray + r * iWidth;
                IntPtr posWrite = bmpData.Scan0 + r * iStride;
                for (int c = 0; c < iWidth; c++)
                    Marshal.WriteByte((IntPtr)posWrite, c, Marshal.ReadByte((IntPtr)posRead, c));
            });
            //
            // 5) 让Windows内存管理接管控制
            bitmap.UnlockBits(bmpData);
            //
            // 6) 调整调色板为灰度(线性化灰度)
            // ColorPalette没有构造函数 - > 从静态成员获取它
            ColorPalette cp_P = bitmap.Palette;
            for (int i = 0; i < 256; i++) {
                cp_P.Entries[i] = Color.FromArgb(i, i, i);
            }
            bitmap.Palette = cp_P;
        }
        if (iNumChannels == 3) {
            //
            // 1) 获取图像指针
            ho_Image.GetImagePointer3(out ip_R, out ip_G, out ip_B, out sType, out iWidth, out iHeight);
            //
            // 2) 计算Stride
            int iPadding = (4 - ((iWidth * 3) % 4)) % 4;
            int iStride = iWidth * 3 + iPadding;
            //
            // 3) 创建一个新的RGB位图对象,分配所需的(托管)内存
            bitmap = new Bitmap(iWidth, iHeight, PixelFormat.Format24bppRgb);
            //
            // 4) 直接将图像数据复制到所需的位图顺序的位图数据对象中
            // BitmapData允许我们访问内存中的数据
            BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, iWidth, iHeight),
            ImageLockMode.WriteOnly, bitmap.PixelFormat);
            Parallel.For(0, iHeight, r => {
                IntPtr posReadR = (IntPtr)((long)ip_R + r * iWidth);
                IntPtr posReadG = (IntPtr)((long)ip_G + r * iWidth);
                IntPtr posReadB = (IntPtr)((long)ip_B + r * iWidth);
                IntPtr posWrite = (IntPtr)((long)bmpData.Scan0 + r * iStride);
                for (int c = 0; c < iWidth; c++) {
                    Marshal.WriteByte(posWrite, 3 * c, Marshal.ReadByte(posReadB, c));
                    Marshal.WriteByte(posWrite, 3 * c + 1, Marshal.ReadByte(posReadG, c));
                    Marshal.WriteByte(posWrite, 3 * c + 2, Marshal.ReadByte(posReadR, c));
                }
            });
            //
            // 5) 让Windows内存管理接管控制
            bitmap.UnlockBits(bmpData);
        }
    }
    catch (Exception ex) {
        throw new Exception("将HImage转换为Bitmap失败。", ex);
    }
    return bitmap;
}

请注意,这是代码的翻译,不包括任何其他内容。

英文:

an other way could be to convert your hImage to a bitmap and then serialize this bitmap as a byte array.

heres a function to convert a hImage to a System.Drawing.Bitmap

public static Bitmap HImageToBitmap(HImage ho_Image) {
int iWidth, iHeight, iNumChannels;
IntPtr ip_R, ip_G, ip_B, ip_Gray;
String sType;
// null return object
Bitmap bitmap = null;
try {
//
// Note that pixel data is stored differently in System.Drawing.Bitmap
// a) Stride:
// stride is the width, rounded up to a multiple of 4 (padding)
// Size of data array HALCON: heigth*width, Bitmap: heigth*stride
// compare: https://msdn.microsoft.com/en-us/library/zy1a2d14%28v=vs.110%29.aspx
// b) RGB data
// HALCON: three arrays, Bitmap: one array (alternating red/green/blue)
iNumChannels = ho_Image.CountChannels();
if (iNumChannels != 1 &amp;&amp; iNumChannels != 3)
throw new Exception(&quot;Conversion of HImage to Bitmap failed. Number of channels of the HImage is: &quot; +
iNumChannels + &quot;. Conversion rule exists only for images with 1 or 3 chanels&quot;);
if (iNumChannels == 1) {
//
// 1) Get the image pointer
ip_Gray = ho_Image.GetImagePointer1(out sType, out iWidth, out iHeight);
//
// 2) Calculate the stride
int iPadding = (4 - (iWidth % 4)) % 4;
int iStride = iWidth + iPadding;
//
// 3) Create a new gray Bitmap object, allocating the necessary (managed) memory 
bitmap = new Bitmap(iWidth, iHeight, PixelFormat.Format8bppIndexed);
// note for high performance: in case of padding=0, image can be copied by reference.
// however, then the bitmap&#39;s validity relies on the HImage lifetime.
// bitmap = new Bitmap(iWidth, iHeight, iWidth, PixelFormat.Format8bppIndexed, ip_Gray);
//
// 4) Copy the image data directly into the bitmap data object, re-arranged in the required bitmap order
// BitmapData lets us access the data in memory
BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, iWidth, iHeight),
ImageLockMode.WriteOnly, bitmap.PixelFormat);
// System.Threading.Tasks.Parallel processing requires .NET framework &gt;= 4.0 
Parallel.For(0, iHeight, r =&gt; {
IntPtr posRead = ip_Gray + r * iWidth;
IntPtr posWrite = bmpData.Scan0 + r * iStride;
for (int c = 0; c &lt; iWidth; c++)
Marshal.WriteByte((IntPtr)posWrite, c, Marshal.ReadByte((IntPtr)posRead, c));
});
//
// 5) Let the windows memory management take over control
bitmap.UnlockBits(bmpData);
//
// 6) Adjust palette to grayscale (linearized grayscale)
// ColorPalette has no constructor -&gt; obtain it from the static member
ColorPalette cp_P = bitmap.Palette;
for (int i = 0; i &lt; 256; i++) {
cp_P.Entries[i] = Color.FromArgb(i, i, i);
}
bitmap.Palette = cp_P;
}
if (iNumChannels == 3) {
//
// 1) Get the image pointer
ho_Image.GetImagePointer3(out ip_R, out ip_G, out ip_B, out sType, out iWidth, out iHeight);
//
// 2) Calculate the stride
int iPadding = (4 - ((iWidth * 3) % 4)) % 4;
int iStride = iWidth * 3 + iPadding;
//
// 3) Create a new RGB Bitmap object, allocating the necessary (managed) memory 
bitmap = new Bitmap(iWidth, iHeight, PixelFormat.Format24bppRgb);
//
// 4) Copy the image data directly into the bitmap data object, re-arranged in the required bitmap order
// BitmapData lets us access the data in memory
BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, iWidth, iHeight),
ImageLockMode.WriteOnly, bitmap.PixelFormat);
Parallel.For(0, iHeight, r =&gt; {
IntPtr posReadR = (IntPtr)((long)ip_R + r * iWidth);
IntPtr posReadG = (IntPtr)((long)ip_G + r * iWidth);
IntPtr posReadB = (IntPtr)((long)ip_B + r * iWidth);
IntPtr posWrite = (IntPtr)((long)bmpData.Scan0 + r * iStride);
for (int c = 0; c &lt; iWidth; c++) {
Marshal.WriteByte(posWrite, 3 * c, Marshal.ReadByte(posReadB, c));
Marshal.WriteByte(posWrite, 3 * c + 1, Marshal.ReadByte(posReadG, c));
Marshal.WriteByte(posWrite, 3 * c + 2, Marshal.ReadByte(posReadR, c));
}
});
//
// 5) Let the windows memory management take over control
bitmap.UnlockBits(bmpData);
}
}
catch (Exception ex) {
throw new Exception(&quot;Conversion of HImage to Bitmap failed.&quot;, ex);
}
return bitmap;
}

答案2

得分: 0

以下是翻译好的代码部分:

public static byte[] ImageToByte(Image image)
{
    using (var stream = new MemoryStream())
    {
        image.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
        return stream.ToArray();
    }
}

或者

Image image = Image.FromFile(imagePath);

byte[] byteArr = new byte[] { };

using (var ms = new MemoryStream())
{
    image.Save(ms, image.RawFormat);
    byteArr = ms.ToArray();
}

对于 Image,你将需要 System.Drawing。

英文:

Can you try?

public static byte[] ImageToByte(Image image)
{
using (var stream = new MemoryStream())
{
image.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
return stream.ToArray();
}
}

Or

Image image = Image.FromFile(imagePath);
byte[] byteArr = new byte[] { };
using (var ms = new MemoryStream())
{
image.Save(ms, image.RawFormat);
byteArr = ms.ToArray();
}

For Image you will need System.Drawing

huangapple
  • 本文由 发表于 2023年2月14日 22:06:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/75448991.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定