需要C#功能,灰度TIFF转换成黑白(单色/ 1bpp映射)TIFF(Need C# functio

2019-06-26 15:09发布

我需要,将采取一个8比特灰度级的TIFF的字节[],并返回一个字节[]中的1位(黑白)TIFF的C#函数。

我是相当新的与TIFF格式的工作,但总的想法是,我们需要把它们从灰度或彩色转换为黑白/黑白/二进制图像格式。

我们收到通过WCF的图像作为一个byte [],那么我们就需要进行这种转换为黑白以便将它们发送到哪个做进一步处理的部件。 我们不会在这一点计划,永远将其保存为文件。

作为参考,在我们的测试客户端,这是我们如何创建字节]:

        FileStream fs = new FileStream("test1.tif", FileMode.Open, FileAccess.Read);
        this.image = new byte[fs.Length];
        fs.Read(this.image, 0, System.Convert.ToInt32(fs.Length));
        fs.Close();

-------- ---------更新

我觉得这里可能有超过1个很好的答案,但我们最终使用的代码从CodeProject上的网站下面的方法添加到重载转换函数接受字节]以及位图:

public static Byte[] ConvertToBitonal(Byte[] original)
    {
        Bitmap bm = new Bitmap(new System.IO.MemoryStream(original, false));
        bm = ConvertToBitonal(bm);
        System.IO.MemoryStream s = new System.IO.MemoryStream();
        bm.Save(s, System.Drawing.Imaging.ImageFormat.Tiff);
        return s.ToArray();
    }

Answer 1:

在CodeProject上的一篇文章在这里描述你所需要的。



Answer 2:

@neodymium有一个很好的答案,但GetPixel / SetPixel会杀了性能。 鲍勃·鲍威尔在这里有一个伟大的方法: http://www.bobpowell.net/onebit.htm

C#:

    private Bitmap convertTo1bpp(Bitmap img)
    {
        BitmapData bmdo = img.LockBits(new Rectangle(0, 0, img.Width, img.Height),
                                       ImageLockMode.ReadOnly, 
                                       img.PixelFormat);

        // and the new 1bpp bitmap
        Bitmap bm = new Bitmap(img.Width, img.Height, PixelFormat.Format1bppIndexed);
        BitmapData bmdn = bm.LockBits(new Rectangle(0, 0, bm.Width, bm.Height),
                                      ImageLockMode.ReadWrite, 
                                      PixelFormat.Format1bppIndexed);

        // scan through the pixels Y by X
        for(int y = 0; y < img.Height; y++)
        {
            for(int x = 0; x < img.Width; x++)
            {
                // generate the address of the colour pixel
                int index = y * bmdo.Stride + x * 4;

                // check its brightness
                if(Color.FromArgb(Marshal.ReadByte(bmdo.Scan0, index + 2), 
                                  Marshal.ReadByte(bmdo.Scan0, index + 1), 
                                  Marshal.ReadByte(bmdo.Scan0, index)).GetBrightness() > 0.5F)
                {
                    setIndexedPixel(x, y, bmdn, true); // set it if its bright.
                }
             }
        }

        // tidy up
        bm.UnlockBits(bmdn);
        img.UnlockBits(bmdo);
        return bm;
    }

    private void setIndexedPixel(int x, int y, BitmapData bmd, bool pixel)
    {
        int index = y * bmd.Stride + (x >> 3);
        byte p = Marshal.ReadByte(bmd.Scan0, index);
        byte mask = (byte)(0x80 >> (x & 0x7));

        if (pixel)
        {
            p |= mask;
        }
        else
        {
            p &= (byte)(mask ^ 0xFF);
        }

        Marshal.WriteByte(bmd.Scan0, index, p);
    }


Answer 3:

可能想看看“克雷格斯实用工具库”我相信他在地方的功能。 克雷格的实用工具库



Answer 4:

我公司的产品, dotImage ,将做到这一点。

给定一个图像,您可以使用多种方法,包括简单的阈值,全局阈值,局部阈值,自适应阈值,抖动(有序和弗洛伊德·斯坦伯格),以及动态阈值从多位转换为单个位。 正确的选择依赖于输入图像(文档,图像,图形)的类型。

典型的代码如下所示:

AtalaImage image = new AtalaImage("path-to-tiff", null);
ImageCommand threshold = SomeFactoryToConstructAThresholdCommand();
AtalaImage finalImage = threshold.Apply(image).Image;

SomeFactoryToConstructAThresholdCommand()是将返回一个新命令,将处理图像的方法。 这可能是那样简单

return new DynamicThresholdCommand();

要么

return new GlobalThresholdCommand();

而一般来说,如果你正在寻找到转换整个多页TIFF为黑色和白色,你会做这样的事情:

// open a sequence of images
FileSystemImageSource source = new FileSystemImageSource("path-to-tiff", true);

using (FileStream outstm = new FileStream("outputpath", FileMode.Create)) {
    // make an encoder and a threshold command
    TiffEncoder encoder = new TiffEncoder(TiffCompression.Auto, true);
    // dynamic is good for documents -- needs the DocumentImaging SDK
    ImageCommand threshold = new DynamicThreshold();

    while (source.HasMoreImages()) {
        // get next image
        AtalaImage image = source.AcquireNext();
        AtalaImage final = threshold.Apply(image).Image;
        try {
            encoder.Save(outstm, final, null);
        }
        finally {
            // free memory from current image
            final.Dispose();
            // release the source image back to the image source
            source.Release(image);
        }
    }
}


Answer 5:

首先,你需要知道如何在X,Y像素位置映射到你数组中的索引值。 这将取决于你如何字节构建[]。 你需要知道你的图像格式的细节-例如,什么是步幅 ?

我看不出在8位灰度TIFF 的PixelFormat枚举。 如果它在那里,它会告诉你你需要知道的。

然后,遍历每个像素,并看它的颜色值。 你需要在一个阈值决定 - 如果像素的颜色高于阈值,使新颜色白色; 否则,使其变黑。

如果要模拟与1bpp映射灰度阴影,你可以看看更先进的技术,如抖动。



Answer 6:

像这样的东西可能会奏效,我没有测试它。 (应该很容易C#吧。)

    Dim bmpGrayscale As Bitmap = Bitmap.FromFile("Grayscale.tif")
    Dim bmpMonochrome As New Bitmap(bmpGrayscale.Width, bmpgrayscale.Height, Imaging.PixelFormat.Format1bppIndexed)
    Using gfxMonochrome As Graphics = Graphics.FromImage(bmpMonochrome)
        gfxMonochrome.Clear(Color.White)
    End Using
    For y As Integer = 0 To bmpGrayscale.Height - 1
        For x As Integer = 0 To bmpGrayscale.Width - 1
            If bmpGrayscale.GetPixel(x, y) <> Color.White Then
                bmpMonochrome.SetPixel(x, y, Color.Black)
            End If
        Next
    Next
    bmpMonochrome.Save("Monochrome.tif")

这也许是一个更好的办法还是:

Using bmpGrayscale As Bitmap = Bitmap.FromFile("Grayscale.tif")
    Using bmpMonochrome As New Bitmap(bmpGrayscale.Width, bmpgrayscale.Height, Imaging.PixelFormat.Format1bppIndexed)
        Using gfxMonochrome As Graphics = Graphics.FromImage(bmpMonochrome)
            gfxMonochrome.CompositingQuality = Drawing2D.CompositingQuality.HighQuality
            gfxMonochrome.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
            gfxMonochrome.DrawImage(bmpGrayscale, new Rectangle(0, 0, bmpMonochrome.Width, bmpMonochrome.Height)
        End Using
        bmpMonochrome.Save("Monochrome.tif")
    End Using
End Using

我相信你正在寻找的术语是“重采样”。



Answer 7:

由像素处理像素的极端缓慢的。 比System.DrawImage慢40倍。 System.Draw图像是半溶液中,破坏了图像(300dpi的 - > 96DPI)和在300dpi的源200-400kb大的结果的文件产生。

        public static Image GetBlackAndWhiteImage(Image SourceImage)
    {

        Bitmap bmp = new Bitmap(SourceImage.Width, SourceImage.Height);

        using (Graphics gr = Graphics.FromImage(bmp)) // SourceImage is a Bitmap object
        {
            var gray_matrix = new float[][] {
            new float[] { 0.299f, 0.299f, 0.299f, 0, 0 },
            new float[] { 0.587f, 0.587f, 0.587f, 0, 0 },
            new float[] { 0.114f, 0.114f, 0.114f, 0, 0 },
            new float[] { 0,      0,      0,      1, 0 },
            new float[] { 0,      0,      0,      0, 1 }
        };

            var ia = new System.Drawing.Imaging.ImageAttributes();
            ia.SetColorMatrix(new System.Drawing.Imaging.ColorMatrix(gray_matrix));
            ia.SetThreshold(float.Parse(Settings.Default["Threshold"].ToString())); // Change this threshold as needed
            var rc = new Rectangle(0, 0, SourceImage.Width, SourceImage.Height);
            gr.DrawImage(SourceImage, rc, 0, 0, SourceImage.Width, SourceImage.Height, GraphicsUnit.Pixel, ia);
        }
        return bmp;
    }

完美的方式只是简单转换为CCITT解码TIF,仅包含BW。 与30-50kb结果文件要比较有效的方法,300DPI也仍然正确,以及:

        public void toCCITT(string tifURL)
    {
        byte[] imgBits = File.ReadAllBytes(tifURL);

        using (MemoryStream ms = new MemoryStream(imgBits))
        {
            using (Image i = Image.FromStream(ms))
            {
                EncoderParameters parms = new EncoderParameters(1);
                ImageCodecInfo codec = ImageCodecInfo.GetImageDecoders()
                                                     .FirstOrDefault(decoder => decoder.FormatID == ImageFormat.Tiff.Guid);

                parms.Param[0] = new EncoderParameter(Encoder.Compression, (long)EncoderValue.CompressionCCITT4);

                i.Save(@"c:\test\result.tif", codec, parms);
            }
        }
    }

祝你好运,兄弟,



文章来源: Need C# function to convert grayscale TIFF to black & white (monochrome/1BPP) TIFF