A class for displaying 2-dimensional images either singly or in a movie sequence
![]() | A: Informational Variables
| ||||||||||||||||||||||||||||||||||||||||||||
![]() | B: Behavioral Variables.
| ||||||||||||||||||||||||||||||||||||||||||||
![]() | C: Constructors. | ||||||||||||||||||||||||||||||||||||||||||||
![]() | D: Initialization routines.
| ||||||||||||||||||||||||||||||||||||||||||||
![]() | E: Color Lookup Table (CLUT) manipulation routines.
| ||||||||||||||||||||||||||||||||||||||||||||
![]() | F: Image storage and display-preparation routines.
| ||||||||||||||||||||||||||||||||||||||||||||
![]() | G: Movie sequence and 2D image/movie-frame display routines.
| ||||||||||||||||||||||||||||||||||||||||||||
![]() | H: Easy methods for choosing image presentation locations.
|
A class for displaying 2-dimensional images either singly or in a movie sequence. The class allows manipulation of the color lookup table (CLUT) and provides easy access to information about the operating system and the video characteristics.An important requirment for image display in psychophysical experiments is fine control of pixel luminance. To this end the mvl_video_manager class provides two methods for CLUT linearization. First, you can use the linearization method provided for in Denis Pelli's VideoToolbox. All you need is the file created by that calibration program. That data includes information regarding your ISR video-attenuator, if you have one.
Alternatively, you can use the linearization method provided by this package. The method also allows for use of a resistive network (ISR Video Attenuator or otherwise) for increasing luminance resolution but requires neither a photometer nor a voltmeter. Instead the monitor-luminance and attenuator characteristics are measured psychophysically.
The MVL Linearization Method
Our task in linearization is to produce a sequence of DAC values (perhaps RGB, or reg/green/blue DAC-value triplets) that produce a linear change of perceived luminance on the target display with linear changes of pixel value. That is, we want to to have
Perceived_Luminance(Pixel_Value) = MinLuminance + Konstant*Pixel_ValueThe relationship of the function that maps a video DAC value to a screen luminance in cathode ray tubes(CRT's)L = f(DAC value)is generally nonlinear. This is the function normally measured using a photometer. In practice we use the inverse of f(), call it g(), to compute the DAC value required for the requested luminance. The linearization method provided by this package g() takes the formDAC value = g(LF)where LF is a fraction of the luminance range. If a DAC value of 0 produces LMin, and a maximum dac value (that is, (2**DacBits-1), where ** denotes exponentiation) produces LMax, then LF = (L-LMin)/(LMax-LMin).Historically this process (that is, use of g()) has been galled gamma correction because f() was often taken to be of the form alpha+beta*(L**gamma). This is not really adequate for good linearization of any monitor, so we adopt a form for g() of:
DAC value = exp(p)where exp(p) is the Natural Exponential function, p is a polynomial in ln(LF), and ln() is the Natural Logarithm. The nth order polynomial p has parameters {a0, a1, ... an}. A first order polynomial produces a two parameter a0*(L**(1/a1)). This is equivalent to the historical gamma function: Beta*L**Gamma where Beta=a0 and Gamma=(1/a1). Since a first order polynomial is not generally adequate for all hardware we allow higher order polynomials in our calibration.The Attenuator Characteristics
Generally, the resistive network (e.g. Video Attenuator) produces a (linear) weighted sum of the voltages from the red, blue and green guns and the result is output onto the green channel:
Vgreen_out = Ar*Vred + Ag*Vgreen + Ab*Vblue where Ar, Ag, and Ab are constants that satisfy Ar + Ag + Ab = 1.0 and where (at least, for the Video Attenuator) Ab > Ag > ArFor the Video Attenuator, Ar > Ab/256. Assuming this to be true for any attanuator used with this software, we can use the red gun (alone) to interpolate between luminances produced by integral values of the blue gun. To measure this, the calibration program included with this software finds the red gun dac value that makesBlueDacValue + RedDacValue == BlueDacValue+Deltatrue for some Delta. The number of red gun steps per blue step is all we need to know, assuming that the gains for each of the red, green and blue guns are independent. (This is unlikely, but the assumption works well enough.) This 'step-count' is used in the linearization process.
gestalt68k: 1 -- Motorola MC68k gestaltPowerPC: 2 -- IBM PowerPC
IML_LINT CPUType
gestaltCPU68000: 1 -- Various 68k CPUs...
gestaltCPU68010: 2
gestaltCPU68020: 3
gestaltCPU68030: 4
gestaltCPU68040: 5
gestaltCPU601: 0x101, -- IBM 601, etc.
gestaltCPU603: 0x103,
gestaltCPU604: 0x104
IML_LINT FPUType
gestaltNoFPU: 0 -- no FPU
gestalt68881: 1 -- 68881 FPU
gestalt68882: 2 -- 68882 FPU
gestalt68040FPU: 3 -- 68040 built-in FPU
IML_LINT QuickDrawVersion
gestaltOriginalQD: 0x000 -- original 1-bit QD
gestalt8BitQD: 0x100 -- 8-bit color QD
gestalt32BitQD: 0x200 -- 32-bit color QD
gestalt32BitQD11: 0x201 -- 32-bit color QDv1.1
gestalt32BitQD12: 0x220 -- 32-bit color QDv1.2
gestalt32BitQD13: 0x230 -- 32-bit color QDv1.3
IML_USINT CLUTSegmentLength
IML_DOUBLE MeanLuminance
MinLuminance + MeanLFraction*(MaxLuminance+MinLuminance).
Generally, the resistive network (e.g. ISR Video Attenuator) produces a
linear, weighted sum of the voltages from the red, blue and green CRT
guns, and the resulting voltage is output to the green channel:
THIS IS A ROYAL PAIN.
So, this method does window filling (clearing) using a pre-set image
of size Speed x Speed pixels. :-)
IML_LINT set_dgp_calibration(const char * FileName=NULL)
void set_attenuator_red_steps( IML_FLOAT RedSteps )
Vgreen_out = Ar*Vred + Ag*Vgreen + Ab*Vblue
where Ar, Ag, and Ab are constants that satisfy
Ar + Ag + Ab ~ 1.0
and where (at least, for the Video Attenuator)
Ab > Ag > Ar
For the Video Attenuator, Ar > Ab/(MaxDac+1). Assuming this to be true
for any attanuator used with this software, we can use the red
gun (alone) to interpolate between luminances produced by integral values
of the blue gun. To measure this, the calibration program included
with this software finds the red gun dac value that makes
BlueDacValue + RedDacValue == BlueDacValue+Delta
true for some Delta. The number of red gun steps per blue
step is all we need to know, assuming that the gain for each
of the red, green and blue guns
are independent. (This is unlikely, but the assumption works
well enough.) This 'step-count' is used in the linearization
process.
void set_mvl_calibration(IML_FLOAT B, IML_FLOAT G, IML_FLOAT MinL, IML_FLOAT MaxL)
DacValue = B*L**(1/G)
where '**' denotes exponentiation.
B should usually be set to (or be close to) MaxDac. MinL and MaxL are
the minimum and maximum luminance values as measured with a photometer. MinL
and MaxL values are not necessary for the linearization.
L is a luminance as a fraction of maximum; L=0.0 at MinL and L=1.0 at MaxL.
void set_mvl_calibration(polynomial IML_REF CalibrationInfo, IML_FLOAT MinL, IML_FLOAT MaxL)
DAC value = exp(p)
where exp(p) is the Natural Exponential function, p is
a polynomial in ln(LF), and ln() is the Natural Logarithm.
The nth order polynomial p has parameters {a0, a1, ... an}.
MinL and MaxL are the minimum and maximum luminance values as measured with
a photometer. L is a luminance as a fraction of maximum; L=0.0 at MinL
and L=1.0 at MaxL. Accurate values of MinL and MaxL are not necessary for
linearization, only for your publications ;).
void use_dgp_calibration(void)
void use_mvl_calibration(void)
void use_mvl_window_filling(IML_USINT Speed = 64)
PmBackColor( CLUT_Entry );
EraseRect( &Rect );
with CLUT_Entry value of 0 or 255 (for 8-bit DAC video hardware)
will often fail because the Color manager strongly objects to meddling
with the first and last CLUT entries. If you do this after filling
the CLUT with a linearized sequence, the Color Manager will likely
re-fill the first and last entries with white and black (full and no
luminance) respectively.
void linearize_clut(IML_DOUBLE MeanL, IML_DOUBLE MaxC)
void linearize_clut(IML_DOUBLE MeanL, IML_DOUBLE MaxC, IML_USINT Start, IML_USINT Length)
void set_clut_entry(IML_SINT Entry, IML_SINT R, IML_SINT G, IML_SINT B)
void set_clut_entry(IML_SINT Entry, mvl_rgb IML_REF RGB)
void identity_clut(IML_UBYTE RorGorB, IML_USINT StartCLUTEntry, IML_USINT Length, IML_FLOAT StartDacValue, IML_FLOAT DeltaDac)
(short int)(0.5 + StartDac + (CLUTEntry-StartCLUT)*DeltaDac)
for CLUTEntry going from StartCLUT to StartCLUT+CLUTLength-1. The values are
stored in any combination of red, green and blue DAC entries as designated by
the RorGorB parameter. RorGorB should be one of
mvl_video_manager::RED_GUN
mvl_video_manager::GREEN_GUN
mvl_video_manager::BLUE_GUN
mvl_video_manager::ALL_GUNS
or any bit-wise OR'ed combination. ALL_GUNS is equivalent to
mvl_video_manager::RED_GUN | mvl_video_manager::GREEN_GUN | mvl_video_manager::BLUE_GUN
mvl_clut IML_PTR get_clut_copy(void)
mvl_clut & CLUT_Reference = *MacVideo.get_clut_copy();
Then you can alter the copy of the clut to your heart's content, and load
it back into the hardware later. But remember to delete the
CLUT copy when you're done! That is:
delete &CLUT_Reference;
void set_default_clut(mvl_clut IML_REF CLUT)
void load_clut(mvl_clut IML_REF CLUT)
void load_clut_entry(mvl_clut IML_REF CLUT, IML_SINT Entry)
MinLuminance + Luminance*(MaxLuminance-MinLuminance).
void fill_window_absolute(IML_SINT CLUT_Index)
IML_SINT store_image_sequence(iml_ubyte_image IML_REF Image)
IML_SINT update_image_sequence(iml_ubyte_image IML_REF Image, IML_USINT ImSeqID)
IML_SINT create_blit_sequence(IML_USINT ImSeqID, mvl_screen_position IML_REF DestPos, iml_imageframe_sequence IML_REF FrameSeq)
void clear_blit_sequences(void)
IML_SINT add_to_group(IML_USINT BlitSeqID, IML_USINT GroupID=0)
IML_SINT clear_group(IML_SINT GroupID = -1)
IML_FLOAT play_blit_group(IML_SINT GroupID = -1)
IML_SINT display_frame(IML_USINT ImSeqID, IML_USINT Frame, mvl_screen_position IML_REF DestPos)
IML_SINT display_image( iml_ubyte_image IML_REF Image, mvl_screen_position IML_REF DestPos)
mvl_screen_position get_grid_size(IML_USINT XSize, IML_USINT YSize, IML_USINT Spacing=0)
mvl_screen_position get_screen_position(IML_SINT ImageIndex, IML_USINT XSize, IML_USINT YSize, IML_USINT Spacing=0)
0 1 2
3 4 5
6 7 8
The second method allows for special positions on the display to
be selected. ImageIndex can be passed the values:
mvl_video_manager::CENTER
mvl_video_manager::UPPER_LEFT
mvl_video_manager::UPPER_RIGHT
mvl_video_manager::LOWER_LEFT
mvl_video_manager::LOWER_RIGHT
This selects the obvious centered or justified image positions.
mvl_screen_position get_screen_position(mvl_screen_position & XY, IML_USINT XSize, IML_USINT YSize, IML_USINT Spacing=0)
0,0 0,1 0,2
1,0 1,2 1,2
2,0 2,1 2,2
generated by doc++