3

8ビットのグレースケールTIFFのByte[]を受け取り、1ビット(白黒)のTIFFのByte []を返すC#関数が必要です。

私は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サイトのコードを使用し、次のメソッドを追加して、変換関数をオーバーロードして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();
    }
4

8 に答える 8

4

ここに、必要なものを説明するCodeProjectに関する記事があります。

于 2009-07-23T17:54:22.670 に答える
3

@neodymiumには良い答えがありますが、GetPixel/SetPixelはパフォーマンスを低下させます。ボブパウエルは素晴らしい方法を持っています。

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);
    }
于 2009-07-23T18:08:32.297 に答える
2

'CraigsUtilityLibrary'をチェックしたいかもしれません。彼はその機能を備えていると思います。 クレイグのユーティリティライブラリ

于 2009-07-23T17:16:08.863 に答える
1

私の会社の製品である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);
        }
    }
}
于 2009-07-23T17:40:13.243 に答える
0

まず、X、Yピクセルの位置が配列内のインデックス値にどのようにマッピングされるかを知る必要があります。 これは、Byte[]がどのように構築されたかによって異なります。 あなたはあなたの画像フォーマットの詳細を知る必要があります-例えば、ストライドは何ですか?

PixelFormat列挙に8ビットグレースケールTIFFが表示されません。 それがそこにあった場合、それはあなたが知る必要があることを教えてくれるでしょう。

次に、各ピクセルを反復処理して、そのカラー値を確認します。しきい値を決定する必要があります。ピクセルの色がしきい値を超えている場合は、新しい色を白にします。それ以外の場合は、黒にします。

1BPPを使用してグレースケールシェーディングをシミュレートする場合は、ディザリングなどのより高度な手法を検討できます。

于 2009-07-23T17:26:13.227 に答える
0

このようなものが機能する可能性がありますが、私はそれをテストしていません。(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

あなたが探している用語は「リサンプリング」だと思います。

于 2009-07-23T17:51:53.300 に答える
0

ピクセルごとの操作は非常に遅いです。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;
    }

完璧な方法は、BWのみを含むCCITTデコードtifに変換することです。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);
            }
        }
    }

幸運の仲間、

于 2017-04-25T04:13:35.833 に答える
0

私はこのコードをテストし、うまく機能しました:

//You should use System.Linq for this to work
public static ImageCodecInfo TiffCodecInfo => ImageCodecInfo.GetImageDecoders().
    FirstOrDefault(decoder => decoder.FormatID == ImageFormat.Tiff.Guid);

//Encapsulate this in a try catch block for possible exceptions
public static Bitmap ConvertToBitonal(Bitmap original)
{
    EncoderParameters encoderParameters;
    MemoryStream ms = new MemoryStream();
    Bitmap result;

    encoderParameters = new EncoderParameters(1);
    encoderParameters.Param[0] = new EncoderParameter(Encoder.ColorDepth, 1L);
    original.Save(ms, TiffCodecInfo, encoderParameters);
    result = new Bitmap(Image.FromStream(ms));
    ms.Dispose();
    return result;
}
于 2021-02-04T17:53:36.063 に答える