需要C#function将灰度TIFF转换为黑白(单色/ 1BPP)TIFF

我需要一个C#函数,它将采用8位灰度TIFF的Byte [],并返回1位(黑白)TIFF的字节[]。

我对使用TIFF很新,但一般的想法是我们需要将它们从灰度或彩色转换为黑白/单色/二进制图像格式。

我们通过WCF作为Byte []接收图像,然后我们需要将此转换为黑白,以便将它们发送到进行进一步处理的组件。 我们暂时没有计划将它们保存为文件。

作为参考,在我们的测试客户端中,这是我们创建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(); 

——– ———更新

我认为这里可能有不止一个好的答案,但我们最终使用了CodeProject站点中的代码,并添加了以下方法来重载convert函数以接受Byte []以及位图:

 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(); } 

这里有一篇关于CodeProject的文章描述了你需要什么。

@neodymium有一个很好的答案,但GetPixel / SetPixel会破坏性能。 Bob Powell在这方面有一个很好的方法: 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); } 

可能想看看’Craigs Utility Library’我相信他已经有了这个function。 克雷格的实用工具库

我公司的产品dotImage将会这样做。

给定图像,您可以使用多种方法从多位转换为单位,包括简单阈值,全局阈值,局部阈值,自适应阈值,抖动(有序和Floyd Steinberg)和动态阈值。 正确的选择取决于输入图像的类型(文档,图像,图形)。

典型代码如下所示:

 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); } } } 

首先,您需要知道X,Y像素位置如何映射到数组中的索引值。 这取决于你的Byte []的构造方式。 您需要了解图像格式的详细信息 – 例如, 步幅是什么?

我没有在PixelFormat枚举中看到8位灰度TIFF 。 如果它在那里,它会告诉你你需要知道什么。

然后,遍历每个像素并查看其颜色值。 您需要确定阈值 – 如果像素的颜色高于阈值,则将新颜色设为白色; 否则,让它变黑。

如果要使用1BPP模拟灰度阴影,可以查看更高级的技术,例如抖动。

这样的东西可能会起作用,我还没有测试过。 (应该很容易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 

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

逐像素操作极其缓慢。 比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); } } } 

祝你好运,兄弟,