LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Nested Loops and Global Variables with Python node

Solved!
Go to solution

Hi, 

 

I was wondering how global variables and nested loops are executed with the python node. I understand that individual functions will be called, but does that mean that global variables/things outside the function won't be called? Does everything need to be in a function for it to work with LabVIEW, and then would the other nested functions be nested nodes (nodes connected to each other in series)? Does connecting nodes in series work like that, to get to functions which are nested deeper? So far, I have looked at all the Python Node examples, but they do not do it in this way, because they only call functions using parameters, not using global variables in the function.  

 

Any help would be awesome, thanks!

0 Kudos
Message 1 of 9
(260 Views)
Solution
Accepted by topic author astrocarbonate

global variables:

do you mean something like this?

Spoiler
x = "awesome"

def myfunc():
  print("Python is " + x)

myfunc() 

https://www.w3schools.com/python/python_variables_global.asp

if yes, this should be easy to test - whats your result?

 

nested functions:

yes, this is possible as shown here:

https://forums.ni.com/t5/LabVIEW/How-to-apply-bilateral-filter-over-a-2d-matrix-image/m-p/4119453#M1...

 

Spoiler
import numpy as np
import cv2
import sys
import math


def distance(x, y, i, j):
    return np.sqrt((x-i)**2 + (y-j)**2)


def gaussian(x, sigma):
    return (1.0 / (2 * math.pi * (sigma ** 2))) * math.exp(- (float(x) ** 2) / (2 * sigma ** 2))


def apply_bilateral_filter(source, filtered_image, x, y, diameter, sigma_i, sigma_s):
    hl = int(diameter/2)
    i_filtered = 0
    Wp = 0
    i1 = 0
    while i1 < diameter:
        j1 = 0
        while j1 < diameter:
            neighbour_x = x - (hl - i1)
            neighbour_y = y - (hl - j1)
        
            if neighbour_x >= len(source):
                neighbour_x -= len(source)
            if neighbour_y >= len(source[0]):
                neighbour_y -= len(source[0])
        
            #print("neighbour_x", source[neighbour_x, neighbour_y])
            
            gi = gaussian(x=float(source[neighbour_x, neighbour_y]) - source[x,y], sigma=sigma_i)
            gs = gaussian(distance(neighbour_x, neighbour_y, x, y), sigma_s)
            w = gi * gs
            i_filtered += source[neighbour_x][neighbour_y] * w
            Wp += w
            j1 += 1
        i1 += 1
    i_filtered = i_filtered / Wp
    filtered_image[x][y] = int(round(i_filtered))


def bilateral_filter_own(source, filter_diameter, sigma_i, sigma_s):
    filtered_image = np.zeros(source.shape)
    #print(filtered_image)

    i = 0
    while i < len(source):
        j = 0
        while j < len(source[0]):
            apply_bilateral_filter(source=source, filtered_image=filtered_image, x=i, y=j, diameter=filter_diameter, sigma_i=sigma_i, sigma_s=sigma_s)
            #print(apply_bilateral_filter)            
            j += 1
        i += 1
    return filtered_image


def return_img(path):

    src=cv2.imread(path,0)
    # 0 is grayscale

    output = bilateral_filter_own(src, 6, 12.0, 16.0)
    return output

e.g. "def gaussian" is defined before "def apply_bilateral_filter" but is used within "def apply_bilateral_filter"

 

 

0 Kudos
Message 2 of 9
(217 Views)

Great, I will try this. Thanks, this should be the solution, though I'll double check in case. I appreciate it.

0 Kudos
Message 3 of 9
(198 Views)

@astrocarbonate wrote:

Hi, 

 

I was wondering how global variables and nested loops are executed with the python node. I understand that individual functions will be called, but does that mean that global variables/things outside the function won't be called? Does everything need to be in a function for it to work with LabVIEW, and then would the other nested functions be nested nodes (nodes connected to each other in series)? Does connecting nodes in series work like that, to get to functions which are nested deeper? So far, I have looked at all the Python Node examples, but they do not do it in this way, because they only call functions using parameters, not using global variables in the function.  

 

Any help would be awesome, thanks!


I'm not sure exactly what you mean by global variables not being called, but you can't access them directly in LabVIEW. You would need to wrap them in getter and setter functions of some sort. Accessing them from Python works the same way it always does.

 

See the example I posted in this topic. Also see the warnings about making sure you know what you are doing if you use threads that way, but that simplified example does at least some of what I think you are asking about.

 

Message 4 of 9
(173 Views)

ok, thanks for the kudos+ - but now, I am curious ...

 

it looks like you have to update globals like this

 

Spoiler
x = 1.0

def test():
    global x
    x += 1
    return x


print(test())


this will print 2 if run in cmd or via visual studio code

 

 

but when run the exact script via python node, I get 3 instead of 2 - when commenting out the print command  # print(test()) , the return value is 2 as it should be

 

global-test.png

 

 

 

 

0 Kudos
Message 5 of 9
(161 Views)

Interesting....

 

Would it be possible to (in one session) open the connection, change a variable through a setter method, then use the updated variable when calling another function in the same node?

 

Would this cause thread issues? 

0 Kudos
Message 6 of 9
(153 Views)

@alexderjuengere wrote:

 

but when run the exact script via python node, I get 3 instead of 2 - when commenting out the print command  # print(test()) , the return value is 2 as it should be

 


You might see the issue if you try using that script interactively in a Python shell:

 

JimB_0-1659875076048.png

 

That's effectively what you are doing in LabVIEW. Top level statements in a Python module run when the file is imported, so "print(test())" is being executed in LabVIEW as well.

 

Try this and you should see the behavior I think you expected:

 

 

x = 1.0

def test():
    global x
    x += 1
    return x

if __name__ == "__main__":
    print(test())

 

 

__name__ will normally evaluate to the name of the module, but when a module is executed as top-level it gets set to "__main__". An if block like this is the usual way to isolate code that you only want to execute automatically if the script is being run as the top-level program.

Message 7 of 9
(110 Views)

Ah, that makes more sense now! So as far as I understand, the LabVIEW really goes through your program twice. Once only looking at things outside the functions, and then the second time inside the function that is specified.

 

However, how does the result 3 come into effect? Would it not be 2, even at the first run-through? Overall, I see the result being 4 if added, though I'm not sure where the print statement would print. 

 

0 Kudos
Message 8 of 9
(100 Views)
@astrocarbonate wrote:

So as far as I understand, the LabVIEW really goes through your program twice.


No, not at all. LabVIEW behaves the same way Python does. Any code in the global space executes when a module is imported. You can then call defined functions as often as you want.

 

If you are used to writing programs in Python, the way to think of it is that you are only importing modules. The LabVIEW code takes the place of your main script. You are no longer writing a program in Python, you are writing a program in LabVIEW and utilizing Python libraries.

 

@astrocarbonate wrote:

However, how does the result 3 come into effect? Would it not be 2, even at the first run-through?


Look closely at the interactive shell screenshot. Notice that right after the import the result 2 is printed, and first time "globalvar.test()" is called it returns 3.

 

So as soon as you import the module x=1, then print(test()) executes which increments it to 2, then the first external call of test() returns 3.

 

That is the same thing LabVIEW is doing. Thinking of a Python session and the Python Node like using the interactive shell is, I suppose, another way of looking at it.

 


@astrocarbonate wrote:

Overall, I see the result being 4 if added, though I'm not sure where the print statement would print. 


It doesn't really matter where it prints. The side effect of calling the inner function still occurs.

 

As for where it prints, essentially the answer is nowhere. It is going to standard out, but there is no output window or file that you can see it in. It's basically like running something from the command line and typing "myscript.bat >nul". Everything executes, but you don't see any output.

 

For the most part, you should not be using print() in modules that you import into LabVIEW. (Or at least using it in a way that it doesn't matter to you whether you see it.) That said, if you really wanted to see the stdout stream, you can get it by redirecting the stream in some Python code.

 

The attached has some examples of all this.

 

  • originalLabVIEWmain.py - This is your LabVIEW snippet rewritten in Python. Run this to see what I mean about the module behaving the same way in Python.
  • OriginalLabVIEWmain.vi - The same logic from your snippet rewritten with the stdout redirection included so you can see the "2".
  • LabVIEWmain.vi - This VI utilizes a module that provides redirection to store the stdout and stderr output streams, makes several calls to a Python module, and retrieves the output as an array of strings.
  • pymain.py - This script makes the same set of function calls that LabVIEWmain.vi does, then prints them to the console. (Notice that nothing appears on the console until after stdoutredirect.endredirect() is called.)
0 Kudos
Message 9 of 9
(83 Views)