Reputation: 11
I'm working on a project which needs to call python script in c#. The fact is that I'm familiar with python, but not c#, not at all.
As I have learnt, there are basically two options: Iron and Python.net, you can check it out here https://www.youtube.com/watch?v=oG5mmElsWJM&lc=UgzwcXvIteCqTjmHl2N4AaABAg.9Ls9q7VkDdc9MCYIPfOW0d. I'm struggling with python.net now. I've tried to call a simple multiply function (e.g. a * b), works perfect. But when I turned to image data, there pops up an error called "The type initializer for 'Delegates' threw an exception."
The python script I used is:
import cv2
import numpy as np
def binarise(image):
ret, img_output = cv2.threshold(image,100,255,cv2.THRESH_BINARY)
return img_output
The c# I tried is:
if (greyImage1 != null)
{
try
{
var pythonPath = @"C:\Users\Admin\anaconda3";
Environment.SetEnvironmentVariable("PATH", $@"{pythonPath};" + Environment.GetEnvironmentVariable("PATH"));
Environment.SetEnvironmentVariable("PYTHONHOME", pythonPath);
Environment.SetEnvironmentVariable("PYTHONPATH ", $@"{pythonPath}\Lib");
string scriptFile = "myfunction.py";
string pythonCode = "";
using (var streamReader = new StreamReader(scriptFile, Encoding.UTF8))
{
pythonCode = streamReader.ReadToEnd();
}
using (Py.GIL())
{
var scope = Py.CreateScope();
scope.Exec(pythonCode);
greyImage1 = (scope as dynamic).binarise(greyImage1);
pictureBox1.Image = (System.Drawing.Image)greyImage1;
this.Cursor = Cursors.Default;
}
}
catch (Exception ex) { messageL.Text = ex.Message; }
}
Anyone got any ideas? Appreciate your time and help.
Upvotes: 1
Views: 10629
Reputation: 11
[Update] I'm pretty sure the problem occurs at this line: greyImage1 = (scope as dynamic).binarise(greyImage1); This acturally turns to data type conversion. Input and output data for python script are 2d array with uint8, but I'm not sure what data type c# expects or returns back.
[update] Data communication issue has been resolved. Result from c# is just numbers, when sent it to python, we need to make it a list, then make 2D array, and then convert to uint8, so that opencv can recognize it. Result from python can be returned directly back to c#. But remember it's PyObject, so need to change this to string, and then do whatever you want.
Upvotes: 0
Reputation: 667
The main idea here is to call the script using a newly initialized process and get its standard output. This method needs an external Python interpreter to actually execute the script
public string run_cmd(string cmd, string args)
{
ProcessStartInfo start = new ProcessStartInfo();
start.FileName = "PATH_TO_PYTHON_EXE";
start.Arguments = string.Format("\"{0}\" \"{1}\"", cmd, args);
start.UseShellExecute = false;// Do not use OS shell
start.CreateNoWindow = true; // We don't need new window
start.RedirectStandardOutput = true;// Any output, generated by application will be redirected back
start.RedirectStandardError = true; // Any error in standard output will be redirected back (for example exceptions)
using (Process process = Process.Start(start))
{
using (StreamReader reader = process.StandardOutput)
{
string stderr = process.StandardError.ReadToEnd(); // Here are the exceptions from our Python script
string result = reader.ReadToEnd(); // Here is the result of StdOut(for example: print "test")
return result;
}
}
}
You can pass your command and argument which will get executed by given path of Python exe.
Remember that when you run such code you need to consider permissions of the account under which your main application is running. For example, if you want to run a script from the web service, that is hosted on IIS — be sure that all the script files that need to be executed have the right permissions for the user under which your web service’s ApplicationPool
is running.
refer this LINK for more details.
Upvotes: 0