はじめに
以下のPythonスクリプトを実行するためのGUIをWPFで作成しました。touch-sp.hatenablog.com
完成図
方法
Python側で作成された多数の画像をどのようにC#側に渡すか?いろいろ試しましたが結局いったんファイルに保存する最も簡単な方法を採用しました。PYTHONNETを使う、メモリーを操作するなどなど方法はいろいろあるかと思いますがどれも難易度が高く今後の課題です。Python側からC#にはファイル名だけ送信することにしました。それに従いC#でファイルを開きます。
開発環境
Windows 11 Core i7-7700K + GTX 1080 Visual Studio Community 2019 .NET 5.0 Python 3.7.9 mxnet-cu102==1.7.0
Pythonスクリプト
変更点
今回のポイントはPython側の変更を最小限にできたことです。元のPythonスクリプトに1行追加しただけです。
print(output_filename)
これでC#側にファイル名が送信されます。
最終的なPythonファイル
import sys import os import glob import mxnet as mx from master import net from master import utils os.makedirs('result', exist_ok=True) if mx.context.num_gpus() >0: ctx = mx.gpu() content_size = 1024 set_cuda = 1 else: ctx = mx.cpu() content_size = 512 set_cuda = 0 input_file = sys.argv[1] style_files = glob.glob('./master/images/styles/*.jpg') content_image = utils.tensor_load_rgbimage(input_file, ctx, size=content_size, keep_asp=True) style_model = net.Net(ngf=128) style_model.load_parameters('./master/models/21styles.params', ctx=ctx) for style_file in style_files: output_filename = os.path.basename(style_file) style_image = utils.tensor_load_rgbimage(style_file, ctx, size=512) style_image = utils.preprocess_batch(style_image) style_model.set_target(style_image) output = style_model(content_image) utils.tensor_save_bgrimage(output[0], os.path.join('result', output_filename), set_cuda) print(output_filename)
C#コード
MainWindow.xaml.cs
using System; using System.Diagnostics; using System.IO; using System.Threading.Tasks; using System.Windows; using System.Windows.Media.Imaging; namespace StyleTransfer { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); WindowSettings(); } private void PushExecuteButton(object sender, RoutedEventArgs e) { if (String.IsNullOrEmpty(selectedPythonPath)) return; if (String.IsNullOrEmpty(selectedImagePath)) return; Task<string> t = Task<string>.Run(() => PythonCall()); string results = t.Result; string[] x = results.Split("\r\n"); for(int i = 0; i < x.Length; i++) { if (!String.IsNullOrEmpty(x[i])) { string currentPath = "result/" + x[i]; var bitmap = new BitmapImage(); using (var stream = File.OpenRead(currentPath)) { bitmap.BeginInit(); bitmap.CacheOption = BitmapCacheOption.OnLoad; bitmap.StreamSource = stream; bitmap.EndInit(); } imageBox[i].Source = bitmap; } } } private string PythonCall() { string result; var myProcess = new Process { StartInfo = new ProcessStartInfo(selectedPythonPath) { UseShellExecute = false, RedirectStandardOutput = true, CreateNoWindow = true, Arguments = "transfer.py" + " " + selectedImagePath } }; myProcess.Start(); result = myProcess.StandardOutput.ReadToEnd(); myProcess.WaitForExit(); myProcess.Close(); return result; } } }
WindowSettings.cs
using Microsoft.Win32; using System.Windows; using System.Windows.Controls; namespace StyleTransfer { public partial class MainWindow : Window { string selectedPythonPath; string selectedImagePath; Button selectPythonButton = new Button() { Content = new Viewbox() { Child = new Label() { Content = "Select Python Interpreter" } }, Margin = new Thickness(5) }; Label selectedPythonLabel = new Label() { Content = "", VerticalAlignment = VerticalAlignment.Center, HorizontalAlignment = HorizontalAlignment.Left }; Button selectImageButton = new Button() { Content = new Viewbox() { Child = new Label() { Content = "Select Image" } }, Margin = new Thickness(5) }; Label selectedImageLabel = new Label() { Content = "", VerticalAlignment = VerticalAlignment.Center, HorizontalAlignment = HorizontalAlignment.Left }; Image[] imageBox = new Image[24]; Button executeButton = new Button() { Content = new Viewbox() { Child = new Label() { Content = "Execute" } }, Margin = new Thickness(5) }; private void WindowSettings() { Title = "Style Transfer"; selectPythonButton.Click += PushselectPythonButton; selectImageButton.Click += PushselectImageButton; executeButton.Click += PushExecuteButton; Grid mainGrid = Myfunc.NewGrid("1,1,10,1", ""); Content = mainGrid; Grid pythonGrid = Myfunc.NewGrid("", "3,7"); mainGrid.AddChild(pythonGrid, 0, 0, 1, 1); pythonGrid.AddChild(selectPythonButton, 0, 0, 1, 1); pythonGrid.AddChild(selectedPythonLabel, 0, 1, 1, 1); Grid ImageSelectGrid = Myfunc.NewGrid("", "3,7"); mainGrid.AddChild(ImageSelectGrid, 1, 0, 1, 1); ImageSelectGrid.AddChild(selectImageButton, 0, 0, 1, 1); ImageSelectGrid.AddChild(selectedImageLabel, 0, 1, 1, 1); Grid ImageGrid = Myfunc.NewGrid("1,1,1,1", "1,1,1,1,1,1"); mainGrid.AddChild(ImageGrid, 2, 0, 1, 1); for (int i = 0; i < 24; i++) { imageBox[i] = new Image() { Margin = new Thickness(5) }; ImageGrid.AddChild(imageBox[i], i / 6, i % 6, 1, 1); } Grid ButtonGrid = Myfunc.NewGrid("", "1,1,1"); mainGrid.AddChild(ButtonGrid, 3, 0, 1, 1); ButtonGrid.AddChild(executeButton, 0, 1, 1, 1); } private void PushselectPythonButton(object sender, RoutedEventArgs e) { var dialog = new OpenFileDialog(); dialog.Filter = "Python実行ファイル (*.exe)|*.exe"; if (dialog.ShowDialog() == true) { selectedPythonPath = dialog.FileName; selectedPythonLabel.Content = selectedPythonPath; } } private void PushselectImageButton(object sender, RoutedEventArgs e) { var dialog = new OpenFileDialog(); dialog.Filter = "画像ファイル (*.jpg, *.png)|*.jpg;*png"; if (dialog.ShowDialog() == true) { selectedImagePath = dialog.FileName; selectedImageLabel.Content = selectedImagePath; } } } }
MyFunc.cs
using System.Windows; using System.Windows.Controls; static class Myfunc { public static Grid NewGrid(string row, string col) //引数はカンマ区切りで { Grid grid = new Grid(); string[] grid_row = row.Split(","); string[] grid_col = col.Split(","); if (grid_row.Length > 1) { foreach (string each in grid_row) { if (int.TryParse(each, out int each_num)) { grid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(each_num, GridUnitType.Star) }); } else { grid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto }); } } } if (grid_col.Length > 1) { foreach (string each in grid_col) { if (int.TryParse(each, out int each_num)) { grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(each_num, GridUnitType.Star) }); } else { grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Auto }); } } } return grid; } public static Grid AddChild(this Grid grid, UIElement element, int row, int col, int row_span, int col_span) { Grid.SetRow(element, row); Grid.SetRowSpan(element, row_span); Grid.SetColumn(element, col); Grid.SetColumnSpan(element, col_span); grid.Children.Add(element); return grid; } }