GIMPのPython-Fuから外部コマンドを呼び出す方法を知っているので、C#とOpenCVSharpで様々な画像処理を自作することが出来るようになりました。

Gimp3のPython-fuで外部コマンドをフィルターとして実行「適応的閾値による二値化処理 adaptiveThreshold」
GIMPには適応的閾値による二値化処理が無いようなので、OpenCVSharpのCv2.adaptiveThresholdで外部コマンド(ToLine.exe)を作り、GIMPのフィルターとして呼び出す実装になっています。外部コマンドをフィ...

C#で作るイラストから線画抽出するコンソールアプリ
適応型しきい値による2値処理を、境界がしっかりしたイラストなどに施すと、境界部分が線画のように抽出されます。2値化された画像ですので、線画としてのディティールは情報量が足りない(ギザギザ)ですが、白と黒ではっきりとしていますので範囲選択用の...
adaptiveThresholdを行う外部コマンドをGIMPから呼び出すフィルターを作成しました。
初回実行の処理時間が少し遅く3秒ほどかかります。

2回め以降は、少し速く1.5~1.7秒前後と、外部コマンドのプロセス起動に時間がかかっていると思われます。
できれば、2回目以降の速度か、もう少し時間短縮してくれると、利便性が向上します。
起動プロセスに時間がかかっていると仮定して、対策としては、あらかじめプロセスを起動しておき、TCPでリクエストで画像処理を行うワーカーを作成すれば、解決すると予想し試してみました。
C#のソースコード(ワーカー)
ファイル名:ImgProcSrv.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="OpenCvSharp4" Version="4.11.0.20250507" />
<PackageReference Include="OpenCvSharp4.runtime.win" Version="4.11.0.20250507" />
</ItemGroup>
</Project>
ファイル名:Program.cs
using System.Net;
using System.Net.Sockets;
using System.Text;
using OpenCvSharp;
var listener = new TcpListener(IPAddress.Loopback, 5001);
listener.Start();
Console.WriteLine("Image server ready.");
while (true)
{
var client = listener.AcceptTcpClient();
using var stream = client.GetStream();
byte[] buffer = new byte[4096];
int length = stream.Read(buffer, 0, buffer.Length);
string message = Encoding.UTF8.GetString(buffer, 0, length);
if (message == "quit")
break;
// Format: "IN|OUT"
var paths = message.Split('|');
string inputPath = paths[0];
string outputPath = paths[1];
using Mat im = Cv2.ImRead(inputPath, ImreadModes.Grayscale);
using var work = new Mat();
Cv2.AdaptiveThreshold(im, work, 255.0,
AdaptiveThresholdTypes.GaussianC,
ThresholdTypes.BinaryInv,
51, 20);
using var element = Cv2.GetStructuringElement(
MorphShapes.Ellipse, new Size(3, 3));
Cv2.Dilate(work, work, element);
Cv2.Erode(work, work, element);
using var dst = new Mat();
Cv2.BitwiseNot(work, dst);
Cv2.ImWrite(outputPath, dst);
byte[] reply = Encoding.UTF8.GetBytes("ok");
stream.Write(reply, 0, reply.Length);
}
listener.Stop();
Console.WriteLine("Server shutdown.");
Python-Fuスクリプト(クライアント)
ファイル名:my-tolinesrv/my-tolinesrv.py
using System.Net;
using System.Net.Sockets;
using System.Text;
using OpenCvSharp;
var listener = new TcpListener(IPAddress.Loopback, 5001);
listener.Start();
Console.WriteLine("Image server ready.");
while (true)
{
var client = listener.AcceptTcpClient();
using var stream = client.GetStream();
byte[] buffer = new byte[4096];
int length = stream.Read(buffer, 0, buffer.Length);
string message = Encoding.UTF8.GetString(buffer, 0, length);
if (message == "quit")
break;
// Format: "IN|OUT"
var paths = message.Split('|');
string inputPath = paths[0];
string outputPath = paths[1];
using Mat im = Cv2.ImRead(inputPath, ImreadModes.Grayscale);
using var work = new Mat();
Cv2.AdaptiveThreshold(im, work, 255.0,
AdaptiveThresholdTypes.GaussianC,
ThresholdTypes.BinaryInv,
51, 20);
using var element = Cv2.GetStructuringElement(
MorphShapes.Ellipse, new Size(3, 3));
Cv2.Dilate(work, work, element);
Cv2.Erode(work, work, element);
using var dst = new Mat();
Cv2.BitwiseNot(work, dst);
Cv2.ImWrite(outputPath, dst);
byte[] reply = Encoding.UTF8.GetBytes("ok");
stream.Write(reply, 0, reply.Length);
}
listener.Stop();
Console.WriteLine("Server shutdown.");
実行結果
時間を計測したところ1.2秒弱となりました。

希望通りの速度が出るようになりました。あらかじめワーカー側のプログラムを起動する作業が増えますが、フィルター操作が快適に行えるので悪くないバーターだと思います。

コメント