はじめに
蛍光画像などでは8bitグレースケールを扱うことがあります。
Image-Jなど画像処理ソフトウェアを使っても良いですが、仕組みを知っていると効率も上がるので学習してみました。
そのひとつとしてC#とLibTiff.Netを使って8bitグレースケールsingle TIFFを表示する方法を紹介します。
WindowsのVisual C#でコンパイルして動かしました。
実行ファイルはLinuxでも動作します。
環境
WindowsではMicrosoftからVisual C#をダウンロード、プロジェクトを作成して実行ファイルを作成します。

Linuxで動かす場合はWindowsで使用した「.NET Framework」のバージョンに対応したパッケージをインストールする必要があります。

LibTiff.Net
libtiffのC#版でWindowsとLinuxで使います。
コンパイル(環境1)
「スタート」→「Microsoft Visual Studio 2019」→「Visual Studio コマンドプロンプト(2019)」を使います。
ソース名がhoge.cs、実行ファイル名をout.exeとするとき、以下のようにコンパイルします。
csc /lib:.\ /reference:BitMiracle.LibTiff.NET.dll /out:out.exe hoge.cs ファイルが複数ある場合 csc /lib:.\ /reference:BitMiracle.LibTiff.NET.dll /out:out.exe hoge1.cs hoge2.cs
コンパイル(環境2)
ソースの改行コードはLFにしてください。
mcs -r:./BitMiracle.LibTiff.NET.dll -out:out.exe hoge.cs 又は、 dmcs -r:./BitMiracle.LibTiff.NET.dll -out:out.exe hoge.cs ファイルが複数ある場合 mcs -r:./BitMiracle.LibTiff.NET.dll -out:out.exe hoge1.cs hoge2.cs 又は、 dmcs -r:./BitMiracle.LibTiff.NET.dll -out:out.exe hoge1.cs hoge2.cs 実行は以下。 chmod 755 ./out.exe ./out.exe
実行結果
Linuxで実行したときのスクリーンショットです。
Windowsでも同様になります。

DLLを登録する
TIFFの解析に「BitMiracle.LibTiff.NET.dll」を使うので「MS Visual C#」に登録します。
「プロジェクト」→「参照の追加」→「参照」タブからファイルを指定する。
出力ウィンドウの表示
「MS Visual C#」を使う場合、「Debug.WriteLine」などでデバッグ情報を出力します。
デバッグ情報は、標準では表示されないので、デバッグ中にメニューバーから操作して表示します。
「デバッグ」→「ウィンドウ」→「出力」
ソース
「8bit.tif」は自前で準備するか、以前の記事のソースを使って作成してください。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
// PixelFormat
using System.Drawing.Imaging;
// Marshal.Copy
using System.Runtime.InteropServices;
// libtiff.net
using BitMiracle.LibTiff.Classic;
// Debug
using System.Diagnostics;
namespace Tiff8bitShowForm
{
public partial class Form1 : Form
{
// TIFFの縦横サイズ
static public int tif_width, tif_height;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
int i;
string fileName = "8bit.tif";
byte[] tif_byte = readTiff(fileName);
Debug.WriteLine(tif_width);
Debug.WriteLine(tif_height);
PixelFormat bmpPixelFormat = PixelFormat.Format8bppIndexed;
Bitmap bmp = new Bitmap(tif_width, tif_height, bmpPixelFormat);
// パレットを設定する(グレースケール)
ColorPalette palette = bmp.Palette;
Color[] entry = palette.Entries;
for (i = 0; i < entry.Length; i++)
{
entry[i] = Color.FromArgb(i, i, i);
}
bmp.Palette = palette;
// Pixelデータの領域を確保
//Rectangle rect = new Rectangle(0, 0, tif_width, tif_height);
Rectangle rect = new Rectangle(Point.Empty, bmp.Size);
// BitmapDataのインスタンスを生成・BitmapのLock
// WriteOnly / ReadWrite / ReadOnly / UserInputBuffer
BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmpPixelFormat);
/* 方法1
// 方法1
for (i = 0; i < tif_height; i++)
{
IntPtr line = (IntPtr)((Int64)bmpData.Scan0 + i * bmpData.Stride);
Marshal.Copy(tif_byte, i * tif_width, line, tif_height);
}
*/
///*
// 方法2
// 各項目を抽出
IntPtr ptr = bmpData.Scan0;
// マネージ配列からアンマネージメモリ、又はその逆のコピー。
// アンマネージメモリとは、CLR(Common Language Runtime)に
// 準拠していないコードを含んでいるコードの総称。
Marshal.Copy(tif_byte, 0, ptr, tif_byte.Length);
//*/
// BitmapのLock解除
bmp.UnlockBits(bmpData);
// PictureBoxのサイズ設定・描画
pictureBox1.Image = bmp;
pictureBox1.Location = new Point(0, 0);
pictureBox1.Size = bmp.Size;
// Formのサイズ設定・リサイズ禁止
//this.ClientSize = new System.Drawing.Size(tif_width, tif_height);
this.ClientSize = bmp.Size;
this.FormBorderStyle = FormBorderStyle.FixedSingle;
}
// read TIFF
private static byte[] readTiff(string fname)
{
int i, j;
ushort samplesperpixel, bitspersample;
double resolution_x, resolution_y;
using (Tiff tif = Tiff.Open(fname, "r"))
{
if (tif == null)
{
Debug.WriteLine("Can not read Tiff file.");
}
tif_width = tif.GetField(TiffTag.IMAGEWIDTH)[0].ToInt();
tif_height = tif.GetField(TiffTag.IMAGELENGTH)[0].ToInt();
resolution_x = tif.GetField(TiffTag.XRESOLUTION)[0].ToDouble();
resolution_y = tif.GetField(TiffTag.YRESOLUTION)[0].ToDouble();
bitspersample = tif.GetField(TiffTag.BITSPERSAMPLE)[0].ToUShort();
samplesperpixel = tif.GetField(TiffTag.SAMPLESPERPIXEL)[0].ToUShort();
Debug.WriteLine(tif_width);
Debug.WriteLine(tif_height);
Debug.WriteLine(resolution_x);
Debug.WriteLine(resolution_y);
Debug.WriteLine(bitspersample);
Debug.WriteLine(samplesperpixel);
// 画像データの確保
byte[] buf_byte = new byte[tif_width * tif_height * sizeof(byte)];
// 1ラインのデータ配列
byte[] scanline = new byte[tif.ScanlineSize()];
Debug.Indent();
// 読み取ったデータを格納
for (i = 0; i < tif_height; i++)
{
tif.ReadScanline(scanline, i);
for (j = 0; j < tif_width; j++)
{
buf_byte[tif_width * i + j] = scanline[j];
//Debug.WriteLine(scanline[j]);
}
}
return buf_byte;
}
}
}
}


Comments