C#でTCPソケットを使った画像処理ワーカーを作る【GIMP3(Pytho-Fu)クライアント→C#画像処理サーバー】

コンピュータ

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

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秒弱となりました。

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

コメント