Is it possible to setPos(0.33) / use subpixel shifts?

98 views
Skip to first unread message

lpt...@gmail.com

unread,
Oct 18, 2013, 11:10:38 AM10/18/13
to psychop...@googlegroups.com
Hi,

I'd like to use subpixel shifts to increase the range/resolution of on screen disparities using psychopy, as a one pixel shift results is a fairly large jump. Can any suggest how I might be able to accomplish this? Is it possible to set simply setPos(0.33,0) which doesn't seem to produce any change, or is there a workaround?

Cheers for any help, this is holding me back slightly with my PhD progress.

Best Wishes,

Laurence

Jonathan Peirce

unread,
Oct 18, 2013, 11:32:52 AM10/18/13
to psychop...@googlegroups.com
Well, obviously the stimulus can't /really/ move by less than a pixel.
To make the pixel a smaller change you need to move the monitor further
away. If you're trying to measure precisely some acuity value then that
is exactly what you should do.

It is possible to fake sub-pixel shifts, using anti-aliasing (blurring,
essentially) and the line stimulus will do that for you if you set
interpolate=True (which is the default). The script below shows you how.
But these necessarily involve blurring.

Jon



from psychopy import visual, event, core
import numpy as np

amplitude = 0.33 #amplitude of oscillation (in pixels)
rate = 1 #rate of oscillation (in Hz)

win = visual.Window([800,800], units='pix')
stim = visual.Line(win, size=[1,400])

clock = core.Clock()
while not event.getKeys():
t = clock.getTime()
stim.setPos([np.sin(t*np.pi*2*rate) * amplitude, 0])
stim.draw()
win.flip()
> --
> You received this message because you are subscribed to the Google
> Groups "psychopy-users" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to psychopy-user...@googlegroups.com.
> To post to this group, send email to psychop...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/psychopy-users/b2330b75-1f7f-45cb-a576-c7d608073f75%40googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.

--
Jonathan Peirce
Nottingham Visual Neuroscience

http://www.peirce.org.uk/

lpt...@gmail.com

unread,
Oct 18, 2013, 12:24:53 PM10/18/13
to psychop...@googlegroups.com
Hi Jon,

Thank you for taking the time on a Friday afternoon to reply to my question.

My stimuli is a randot defined circle containing 1 pixel dots on a white background, with pixels either on full brightness, or totally off. At 3m a one pixel shift (between the left and right eye) gives about 32" of disparity, but the next step up is 64" and so on. I was hoping to be able to test values in between, without having the physically move the display during the experiment and adjusting the stimuli size etc. 

I tried the code you posed and recorded a macro video at screen refresh rate. It appears that the one pixel line fades, whilst the next triplet of pixels light to the same intensity (presumably 1/3 brightness?), fade and return the original line to full brightness. In my case i guess this would provide an oscillation between disparity levels, but be negated by the reduced noise/signal ratio.

As the stimuli is black and white, i was hoping that instead of using the RGB pixel set on one pixel, to use the GB of one pixel and the R on the next pixel to represent the 'white'. Similar to the way the white line moves in the code Rob Black posted (below) but using the setPos function to define the disparity. 

Is there a mechanism that could automatically change the colour of the line on one pixel to 'cyan' and the next to 'red', to represent the subpixel shift of a white line?? 

I suppose was I naively hoping that the setPos source code prevented shifts of less than one pixel (as the quadro card states it has 12-bit subpixel precision) and could be unprevented somehow?

I have only just started to learn programming, coming into this from a clinical background, so please forgive any badly phrased questions.

Cheers,

Laurence


Robs white line shifting by 1/3 of a pixel code:


#!/usr/bin/env python
from psychopy import core, visual, event
import scipy
import numpy

from PIL import Image

#create a window to draw in
winsize= (1920,1080)
win = visual.Window(size=winsize, pos=[0,0], screen=0, allowGUI=False, fullscr=False)

rgbArray = numpy.zeros((512,512,3), 'uint8')

img = Image.fromarray(rgbArray)

myImg = visual.GratingStim(win, tex=img, pos=(0,0), units='pix')

for x in range(15,200):
    x2=x+15
    rgbArray[0::2,x-1,2] = 0   # DRAW WHITE LINE REMOVE PREV BLUE, PAINT RGB
    rgbArray[0::2,x,0] = 255
    rgbArray[0::2,x,1] = 255
    rgbArray[0::2,x,2] = 255
    
    img = Image.fromarray(rgbArray)
    myImg.setTex(img)
    myImg.draw()
    win.flip()
    
    rgbArray[0::2,x,0] = 0   # DRAW WHITE LINE REMOVE PREV RED, PAINT GBR
    rgbArray[0::2,x,1] = 255
    rgbArray[0::2,x,2] = 255
    rgbArray[0::2,x+1,0] = 255
    
    img = Image.fromarray(rgbArray)
    myImg.setTex(img)
    myImg.draw()
    win.flip()
    
    rgbArray[1::2,x2,1] = 0   # DRAW WHITE LINE REMOVE PREV GREEN, PAINT BRG
    rgbArray[1::2,x2,2] = 255
    rgbArray[1::2,x2+1,0] = 255
    rgbArray[1::2,x2+1,1] = 255

    img = Image.fromarray(rgbArray)
    myImg.setTex(img)
    myImg.draw()
    win.flip()


lpt...@gmail.com

unread,
Oct 22, 2013, 4:43:57 AM10/22/13
to psychop...@googlegroups.com
Hi,

Can you clarify why it can't move by less than a pixel if the stimulus is black and white? It is physically possible - can psychopy not do it through set pos - or is there a mechanism to ensure it can't, that could be 'switched off'?

Cheers

Jonathan Peirce

unread,
Oct 22, 2013, 5:29:24 AM10/22/13
to psychop...@googlegroups.com
PsychoPy can set the intensities of any pixel to any value you like. So, ultimately, anything that's physically possible with the screen PsychoPy can do. No capabilities of your hardware are being "turned off". What set of pixel intensities would you like presented on the screen to create this sub-pixel shift? They can be achieved.

The trick that you had code for from Rob was doing something shows an interesting workaround (which I've not seen before) but it has some limitations. It uses the fact that on many monitors each pixel actually has 3 spatially separated "sub-pixels" for the red, green and blue components. If these are packed  a dense regular array then we could move a line by 1/3 of a pixel by turning off the blue colour in our target pixel and borrowing the blue sub-pixel from the pixel to the left etc. Caveats:
    - It's display-dependent. In some types of monitor the red, green and blue aren't arranged into columns, so the jumps you have to make are more complicated. The, for some displays (e.g. most DLPs) there are no sub-pixels in space; the red, green blue components are presented sequentially at one location, so this trick won't work at all. See here for some examples of different geometries:
    http://en.wikipedia.org/wiki/Subpixel_rendering
    - It's direction dependent. It can obviously only work in the horizontal direction, if that's how your sub-pixels are aligned.
    - It will also only give you shifts of 1/3 of a pixel
So, how well do you know the geometry of your screen sub-pixels?

Just to be clear, none of the above is anything to do with the sub-pixel calculations you've read about for your graphics card. Your card doesn't know anything about the mechanisms of your display. It just spits out rgb values. The high-precision subpixel provision is for doing calculations before presenting to the screen. When the data go to the screen pixel values are all that (can) exist.

Hope that helps,
Jon

For more options, visit https://groups.google.com/groups/opt_out.

-- 
Jonathan Peirce
Nottingham Visual Neuroscience

http://www.peirce.org.uk

This message and any attachment are intended solely for the addressee and may contain confidential information. If you have received this message in error, please send it back to me, and immediately delete it.   Please do not use, copy or disclose the information contained in this message or in any attachment.  Any views or opinions expressed by the author of this email do not necessarily reflect the views of the University of Nottingham.

This message has been checked for viruses but the contents of an attachment may still contain software viruses which could damage your computer system, you are advised to perform your own checks. Email communications with the University of Nottingham may be monitored as permitted by UK legislation.


lpt...@gmail.com

unread,
Oct 22, 2013, 6:35:58 AM10/22/13
to psychop...@googlegroups.com
Hi,

Thanks for the reply, I'm getting to know the geometry of the subpixels pretty well (hopefully will have attached a macro photo of them). I'm waiting for the loan of a heamocytometer to accurately measure the sub pixel sizes, and spaces in between so can get an accurate number. 

As the stimuli will be white/black, i assume the intensities will either be on full or off full, so I think that should make the process easier? Just have no idea on the code.

So the graphics card doesn't transmit per subpixel instructions, rather per pixel? hence would have to be a colour instruction?

Cheers

Laurence 
LCD Macro Pic.jpg
Reply all
Reply to author
Forward
0 new messages