将8位采样转换为每个采样图像1位

时间:2015-11-23 12:39:01

标签: c# image image-processing libtiff libtiff.net

每个样本图像灰度为8位。我想用Libtiff.net转换它:

 using (Tiff input = Tiff.Open(fileIn, "r"))
            {
                using (Tiff output = Tiff.Open(fileOut, "w"))
                {
                    for (short page = 0; page < input.NumberOfDirectories(); page++)
                    {
                        input.SetDirectory(page);
                        output.SetDirectory(page);

                        if (input.GetField(TiffTag.COMPRESSION)[0].ToInt() == (int)Compression.LZW)
                        {
                            int width = input.GetField(TiffTag.IMAGEWIDTH)[0].ToInt();
                            int height = input.GetField(TiffTag.IMAGELENGTH)[0].ToInt();
                            int xres = input.GetField(TiffTag.XRESOLUTION)[0].ToInt();
                            int yres = input.GetField(TiffTag.YRESOLUTION)[0].ToInt();

                            int samplesPerPixel = input.GetField(TiffTag.SAMPLESPERPIXEL)[0].ToInt();
                            int bitsPerSample = input.GetField(TiffTag.BITSPERSAMPLE)[0].ToInt();
                            int photo = input.GetField(TiffTag.PHOTOMETRIC)[0].ToInt();

                            int scanlineSize = input.ScanlineSize();

                            byte[][] buffer = new byte[height][];


                            for (int i = 0; i < height; ++i){
                                buffer[i] = new byte[scanlineSize];
                                input.ReadScanline(buffer[i], i);    
                            }

                            output.SetField(TiffTag.IMAGEWIDTH, width);
                            output.SetField(TiffTag.IMAGELENGTH, height);
                            output.SetField(TiffTag.COMPRESSION, Compression.CCITTFAX4);
                            output.SetField(TiffTag.PHOTOMETRIC, Photometric.MINISBLACK);
                            output.SetField(TiffTag.SAMPLESPERPIXEL, 1);
                            output.SetField(TiffTag.BITSPERSAMPLE, 1);
                            output.SetField(TiffTag.XRESOLUTION, xres);
                            output.SetField(TiffTag.YRESOLUTION, yres);

                            for (int i = 0; i < height; ++i)
                                output.WriteScanline(buffer[i], i);

                            output.WriteDirectory();

                        }
                    }
                }

            }

如何将8位数组转换为1位数组图像? 我想这样做而不将字节数组转换为位图对象。 什么是正确的方法? 感谢

1 个答案:

答案 0 :(得分:0)

首先,如果您为每像素1位,请注意您获得的图像具有纯黑白像素

如果您的来源是灰度图像,那么可以在127处关闭它,并使所有&gt; 127个值&#39; 1&#39;并且所有&lt; = 127值&#39; 0&#39;,但为了获得更准确的表示,查看抖动函数可能会有用。

对于127截止方式,你只需要制作一个8位数据的数组,每个像素的亮度应该在每个字节的0-255范围内。转换为黑白是非常简单的:

for (Int32 i=0; i > imagedata.Length; i++)
    imagedata[i] = imagedata[i] > 127 ? 1 : 0;

然后,要将其转换为1位数据数组,可以使用此功能。 &#34;步幅&#34;是您在代码中获得scanlineSize的内容。请注意,此函数仅为步幅分配所需的最小字节数。

    /// <summary>
    /// Converts given raw image data for a paletted 8-bit image to lower amount of bits per pixel.
    /// </summary>
    /// <param name="data8bit">The eight bit per pixel image data</param>
    /// <param name="width">The width of the image</param>
    /// <param name="height">The height of the image</param>
    /// <param name="newBpp">The new amount of bits per pixel</param>
    /// <param name="stride">Stride used in the original image data. Will be adjusted to the new stride value.</param>
    /// <param name="bigEndian">Values inside a single byte are read from the largest to the smallest bit.</param>
    /// <returns>The image data converted to the requested amount of bits per pixel.</returns>
private static Byte[] ConvertFrom8Bit(Byte[] data8bit, Int32 width, Int32 height, Int32 bitsLength, Boolean bigEndian)
    {
        if (newBpp > 8)
            throw new ArgumentException("Cannot convert to bit format greater than 8!", "newBpp");
        if (stride < width)
            throw new ArgumentException("Stride is too small for the given width!", "stride");
        if (data8bit.Length < stride * height)
            throw new ArgumentException("Data given data is too small to contain an 8-bit image of the given dimensions", "data8bit");
    Int32 parts = 8 / bitsLength;
    // Amount of bytes to write per width
    Int32 stride = ((bpp * width) + 7) / 8;
    // Bit mask for reducing original data to actual bits maximum.
    // Should not be needed if data is correct, but eh.
    Int32 bitmask = (1 << bitsLength) - 1;
    Byte[] dataXbit = new Byte[stride * height];
    // Actual conversion porcess.
    for (Int32 y = 0; y < height; y++)
    {
        for (Int32 x = 0; x < width; x++)
        {
            // This will hit the same byte multiple times
            Int32 indexXbit = y * stride + x / parts;
            // This will always get a new index
            Int32 index8bit = y * width + x;
            // Amount of bits to shift the data to get to the current pixel data
            Int32 shift = (x % parts) * bitsLength;
            // Reversed for big-endian
            if (bigEndian)
                shift = 8 - shift - bitsLength;
            // Get data, reduce to bit rate, shift it and store it.
            dataXbit[indexXbit] |= (Byte)((data8bit[index8bit] & bitmask) << shift);
        }
    }
    return dataXbit;
}

然后,只需要创建一个正确尺寸的新1位tiff,获得它的步幅,并将这些结果字节逐行写入tiff,同时牢记步幅。

注意:我不知道这与tiff有什么关系,但在.Net中,1位图像调色板,因此您可能需要为新图像指定一个包含该图像的调色板黑与白。