OpenCVSharpで2つの画像ファイルを連結するコンソールアプリ

コンピュータ

画像を右→左の順番に連結します。オプションで高さを指定出来ます。

ソースコード

ファイル名:Concat.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;
using OpenCvSharp;

class Program
{
    static int Main(string[] args)
    {
        const int OK = 0;
        const int ARG_ERROR = 1;
        const int IO_ERROR = 2;
        const int PROCESS_ERROR = 3;

        if (args.Length < 3)
        {
            Console.Error.WriteLine(
                "Usage: concat <rightImage> <leftImage> <outputImage> [height]");
            return ARG_ERROR;
        }

        string pathRight = args[0];   // 右側画像
        string pathLeft  = args[1];   // 左側画像
        string pathOut   = args[2];   // 出力画像

        // 高さオプション
        int targetHeight = -1;
        if (args.Length >= 4 && int.TryParse(args[3], out int h))
        {
            targetHeight = h;
        }

        try
        {
            using var imgRight = Cv2.ImRead(pathRight, ImreadModes.Unchanged);
            using var imgLeft  = Cv2.ImRead(pathLeft, ImreadModes.Unchanged);

            if (imgRight.Empty() || imgLeft.Empty())
            {
                Console.Error.WriteLine("Failed to load image.");
                return IO_ERROR;
            }

            using var nRight = NormalizeChannels(imgRight);
            using var nLeft  = NormalizeChannels(imgLeft);
            

            // 基準高さを決定(指定がなければ img1 の高さ)
            if (targetHeight <= 0)
                targetHeight = nRight.Height;

            // リサイズ関数
            Mat ResizeToHeight(Mat src, int height)
            {
                double scale = (double)height / src.Height;
                int width = (int)(src.Width * scale);
                Mat dst = new Mat();
                Cv2.Resize(src, dst, new Size(width, height), 0, 0, InterpolationFlags.Area);
                return dst;
            }

            using var r1 = ResizeToHeight(nRight, targetHeight);
            using var r2 = ResizeToHeight(nLeft, targetHeight);

            // 結合画像の作成(右左= img1 img2 の順番で並べる)
            int totalWidth = r1.Width + r2.Width;
            Mat result = new Mat(new Size(totalWidth, targetHeight), r1.Type());

            // 左側に img2 を貼る
            r2.CopyTo(result[new Rect(0, 0, r2.Width, targetHeight)]);
            // 右側に img1 を貼る
            r1.CopyTo(result[new Rect(r2.Width, 0, r1.Width, targetHeight)]);

            Cv2.ImWrite(pathOut, result);

            return OK;
        }
        catch (Exception ex)
        {
            Console.Error.WriteLine(ex.Message);
            return PROCESS_ERROR;
        }
    }
    static Mat NormalizeChannels(Mat src)
    {
        if (src.Channels() == 4)
            return src; // BGRA のまま

        if (src.Channels() == 3)
        {
            var dst = new Mat();
            Cv2.CvtColor(src, dst, ColorConversionCodes.BGR2BGRA);
            return dst;
        }

        if (src.Channels() == 1)
        {
            var dst = new Mat();
            Cv2.CvtColor(src, dst, ColorConversionCodes.GRAY2BGRA);
            return dst;
        }

        throw new NotSupportedException("Unsupported channel count");
}

}

コメント