Black opaque in mask

this has to be easy but i am being a bit slow !

  • white background with images (jpeg/pngs)
  • image drifting horizontally across screen (will eventually follow a path of points)
  • I have set up a mask (basically a square wave) of vert white and black bars
    But…
    when i want the image invisible i want the mask to be black not white
    so it looks like its drifting behind black bars. But opaque is white.

(i guess I could just raw some black rects in place, but it makes changing the sf more complex)

Cheers

Try setting the GratingStim color='black'. If you want more help, it would be helpful if you could update your question with:

  • Builder or Coder?
  • If Coder: paste the code!
  • Perhaps a screenshot, just to make sure (you can copy-paste from clipboard into your post - very easy).

Then we can solve instead of guessing :slight_smile:

Hi , thanks for the response,

I thought i posted in the ‘coder’ forum, but i see that it’s ‘coding’
I am using coder - just to write a feasibility demo

color = black gives the inverse, (black background and white opaque) just need to invert it! see screenshot
colour=white give an all white screen.

the code is trivial, posted below…

from psychopy import core, visual, event
from psychopy.tools.arraytools import createXYs
import numpy as np

myWin = visual.Window((1024,1000), allowGUI=False, color=1,  monitor='testMonitor', winType='pyglet', units='pix')

image = visual.ImageStim(myWin, image='bottle.png', mask=None, pos=(-450, 0) )
    

myMask = np.array([
        [-1,1,-1,1,-1,0,-1],
        ])
        
myStim = visual.GratingStim(myWin, tex=None, mask=myMask, size=1024)

while True:
    image.pos += (1, 0) 
    image.draw()
    myStim.draw()
    myWin.flip()

    if event.getKeys(keyList=['escape','q']):
        print myWin.fps()
        myWin.close()
        core.quit()
        event.clearEvents('mouse')#only really needed for pygame windows

also note the jaggy image (from png) looks fine on preview etc.

Hmmm, I don’t think that there’s a way to do this, i.e. a “Color to alpha” function. You can do it if the mask is a visual.ShapeStim, but that would be the solution you already conceptually mentioned: draw a series of vertical black rectangles.

Just for future users, here’s a function that does the trick:

    from psychopy import visual, core
    window_size = [800, 600]  # set this to something appropriate

    # Set up stimuli
    win = visual.Window(window_size, units='pix')
    bar = visual.Rect(win, height=window_size[1], fillColor='black', lineColor=None)  # set the height to your window height (or higher)

    def draw_bars(sf):
        """ Draw bars with a certain spatial frequency (sf).
        Simply moves an existing ShapeStim and draws it a the appropriate locations."""
        bar.width = window_size[0] / sf / 2
        for i in range(sf):  # a loop for each bar to draw
            x = -win.size[0]/2 + bar.width/2 + i*bar.width*2  # calculate x-position of this bar
            bar.pos = (x, 0)  # set it
            bar.draw()  # and draw (OBS: no flipping, this function simply draws)
            
    # Demo it
    draw_bars(10)
    win.flip()
    core.wait(3)

This is reasonably fast. draw_bars(100) takes 10 ms on my laptop and draw_bars(10) is around 1.5 ms.

1 Like

thanks for that, thought i was missing something as it seemed ‘obvious’ but im not familiar with the internals (i did go and have a look at opacity but see its all buried in pyglet so dont really want to go there !)

thats plenty fast enough for what i need to do for the demo (or indeed anything else!)

thanks again :slight_smile:

You can set the colour of the GratingStim (mask) to be black and set the colour of the window (background) to be white. Doesn’t that do exactly what you were asking?

As for the jagginess of the image:

  • within the image that depends on whether or not you have (linear) interpolation turned on but it should be on by default
  • on the straight outer edge of the image this will presumably go away once you have the white background that I think you were aiming for. But, if I got you wrong, you can introduce antialiasing to the outer edges by adding a mask to you image stim that has a thin row of transparent pixels around the outside and this will cause an interpolation between the colourof the background and the colour of the foreground. The amount of smoothing you get depends on the fraction of the mask that the outer line of pixels takes up
2 Likes

What @jon said! To be specific:



from psychopy import visual, core
import numpy as np

# Set up stimuli
win = visual.Window(units='pix', color='white')
image = visual.Circle(win, fillColor='red', radius=200)  # just to demo it. You want to use an image here.
myMask = np.array([[-1,1,-1,1,-1,0,-1],])
bars = visual.GratingStim(win, tex=None, color='black', mask=myMask, size=1024)

# Show it
image.draw()
bars.draw()
win.flip()
core.wait(2)

(Actually, what Jon said is what I tried to write in my first reply. I just mistyped “image” instead of “GratingStim” - now corrected for future users)

1 Like

whoop ! thanks Jon I should have written down all the combinations for the black and white and worked through it.

the jagginess occurred to me last night, but one drink too many to correct it…

I postulated the image being rotated very very slightly so i checked the code
(ripped off from a demo as i just wanted to show someone) and ori=1 !

Now the hard part is to work out what the path is he want to move the image along, I dont think it’s
describable mathematically so ill have to have either something external (which would be cool as
could put that easily under user control) or a constant list of points…

thaks both…
Cheers

here’s the final demo for anyone thats intersted,
it creates a spline from some x,y points and moves
the image along that path behind the mask

stimuli (bottle.png)

code.

from psychopy import core, visual, event
from psychopy.tools.arraytools import createXYs
import numpy as np
import scipy as sp
from scipy.interpolate import interp1d

win_width  = 1050 
win_height = 1000
path_length = win_width

myWin = visual.Window((win_width,win_height), color='white', monitor='testMonitor', units='pix')

# An image using ImageStim. and a mask
image = visual.ImageStim(myWin, mask=None,image='bottle.png')
myMask = np.array([[-1,1,-1,1,-1,1,-1],])
myStim = visual.GratingStim(myWin, tex=None, mask=myMask,  color='black', size=win_width)
left_edge = (myWin.size[0] - image.size[0] ) / 2 

#  0,0 is middle of left margin  1024,0 is middle right
x0 = [-50, 75, 225,  460,  470, 480,  490,  550,  650, 750, 850, 950, 1040]
y1 = [0,  -10, 350, -100, -150, -190, -210, -200, -100,   0, 100, 150, 50]
x1 = [x-left_edge for x in x0]
new_x = np.linspace(min(x1), max(x1), path_length)
new_y = sp.interpolate.interp1d(x1, y1, kind='cubic')(new_x)
path_points = zip(new_x, new_y)

i=0
while True:
    image.pos = path_points[i]
    image.draw()
    myStim.draw()
    myWin.flip()
    i = (i + 1) % path_length    #; print i, path_points[i]

    if event.getKeys(keyList=['escape','q']):
        print 'fps:', myWin.fps()
        myWin.close()
        core.quit()
        event.clearEvents('mouse')
1 Like

Nice spline! :wink:
Glad you got it all working