unit Camera; {Routines used by the NIH Image to support Data Translation and Scion (LG-3, AG-5 or VG-5) frame grabber cards, and QuickTime compatible digitizers.} interface uses Types, Memory, QuickDraw, QuickDrawText, Packages, Menus, Events, Fonts, Scrap, ToolUtils, Resources, Errors, Palettes, StandardFile, Windows, Controls, TextEdit, Files, Dialogs, TextUtils, Finder, MixedMode, Processes, QDOffscreen, Components, QuickTimeComponents, ImageCompression, GestaltEqu, OSUtils, globals, Utilities, Graphics, File1, Analysis, Lut; function DoAveragingOptions: boolean; procedure AverageFrames; procedure GetFrame; procedure CaptureAndDisplayFrame; procedure HighlightPixels; procedure ShowTriggerMessage; procedure StartDigitizing; procedure StopDigitizing; function GetFGPixel (h, v: integer): integer; procedure WaitForTrigger; procedure ShowChannel; procedure ShowVideoControl; procedure UpdateVideoControl; procedure DoVideoControl (item: integer); procedure SelectCameraWindow; procedure SetOffset (var offset, gain: integer); procedure SetGain (var offset, gain: integer); procedure ShowOffsetAndGain (offset, gain: integer); procedure ShowVideoDialog; procedure StartFrame; procedure StopFrame; implementation type IntPtr = ^integer; var SavePicBaseAddr: ptr; StopFlagLoc: IntPtr; procedure GetGrabDepth(var bitDepth: LongInt); var vdigInfo: DigitizerInfo; begin if VDGetDigitizerInfo(vdig, vdigInfo) = noErr then begin if DigitizerMode = digitizeGrayscale then begin if band(vdigInfo.outputCapabilityFlags, digiOutDoes8) <> 0 then bitDepth := 8 {first choice} else if band(vdigInfo.outputCapabilityFlags, digiOutDoes32) <> 0 then bitDepth := 32 {second choice} else if (band(vdigInfo.outputCapabilityFlags, digiOutDoes16) <> 0) then bitDepth := 16; {last choice} end else begin {capture color} if band(vdigInfo.outputCapabilityFlags, digiOutDoes32) <> 0 then bitDepth := 32 {first choice} else if band(vdigInfo.outputCapabilityFlags, digiOutDoes16) <> 0 then bitDepth := 16 {second choice} else if (band(vdigInfo.outputCapabilityFlags, digiOutDoes8) <> 0) then bitDepth := 8; {last choice} end; end; ShowMessage(StringOf('grab depth=', bitDepth)); end; procedure SetVideoStandard; var err: ComponentResult; inFlags, outFlags: LongInt; vdigInfo: DigitizerInfo; begin if VDGetDigitizerInfo(vdig, vdigInfo) <> noErr then exit(SetVideoStandard); case DigitizerStandard of NTSCStd: if band(vdigInfo.inputCapabilityFlags, digiInDoesNTSC) <> 0 then err := VDSetInputStandard(vdig, ntscIn); PALStd: if band(vdigInfo.inputCapabilityFlags, digiInDoesPAL) <> 0 then err := VDSetInputStandard(vdig, palIn); SECAMStd: if band(vdigInfo.inputCapabilityFlags, digiInDoesSECAM) <> 0 then err := VDSetInputStandard(vdig, secamIn); otherwise; end; err := VDGetCurrentFlags(vdig, inFlags, outFlags); if err = noErr then if band(inFlags, digiInDoesNTSC) <> 0 then DigitizerStandard := NTSCStd else if band(inFlags, digiInDoesPAL) <> 0 then DigitizerStandard := PALStd else if band(inFlags, digiInDoesSECAM) <> 0 then DigitizerStandard := SECAMStd; end; procedure SetVideoInput; var err: ComponentResult; maxChannel, currentChannel: integer; begin err := VDGetNumberOfInputs(vdig, maxChannel); if (VideoChannel <= maxChannel) and (err = noErr) then err := VDSetInput(vdig, VideoChannel) else begin VideoChannel := 0; err := VDSetInput(vdig, 0); end; err := VDGetInput(vdig, currentChannel); if err = noErr then VideoChannel := currentChannel; end; function SetupVdig: boolean; var mPtr: MatrixRecordPtr; vdErr: ComponentResult; vdigInfo: DigitizerInfo; DummyMatrixRecord, bitDepth: LongInt; err: OSErr; flags: GWorldFlags; SaveGDevice: GDHandle; gwRect, srcRrect, globalRect: rect; str: str255; begin SetupVdig := false; SetRect(gwRect, 0, 0, fgWidth, fgHeight); bitDepth := 8; GetGrabDepth(bitDepth); SetVideoInput; if bitDepth = 8 then vdErr := VDSetInputColorSpaceMode(vdig, 0); {grayscale} SaveGDevice := GetGDevice; SetGDevice(osGDevice); if bitDepth = 8 then GWorldLUT := GetCTable(40) {grayscale LUT} else GWorldLUT := nil; flags := 0; err := NewGWorld(osGWorld, bitDepth, gwRect, GWorldLUT, nil, flags); SetGDevice(SaveGDevice); if err <> NoErr then begin PutMemoryAlert; CloseVdig; exit(SetupVdig); end; fgPixMap := GetGWorldPixMap(osGWorld); if not LockPixels(fgPixMap) then begin CloseVdig; exit(SetupVdig); end; {err := LockMemoryContiguous(GetPixBaseAddr(fgPixMap), 2097152);} vdErr := VDGetActiveSrcRect(vdig, 0, srcRrect); if vdErr = noErr then vdErr := VDSetDigitizerRect(vdig, srcRrect); DummyMatrixRecord := LongInt(nil); mPtr := MatrixRecordPtr(ptr(DummyMatrixRecord)); vdErr := VDSetPlayThruDestination(vdig, fgPixMap, gwRect, MatrixRecord(mPtr^), nil); if vdErr = noErr then SetupVdig := true else begin {we will try again when Camera window is open} DisposeGWorld(osGWorld); osGWorld := nil; GWorldLUT := nil; fgPixMap := nil; (* if vdErr = -2208 then str := concat(cr, '(Try turning virtual memory or RAM Doubler off.)') else str := ''; PutError(StringOf('Video digitizer error ', vdErr, str)); *) SetupVdig := true end; end; procedure SetPlayThruDestination; var mPtr: MatrixRecordPtr; vdErr: ComponentResult; DummyMatrixRecord, bitDepth: LongInt; gwRect: rect; str: String; begin SetRect(gwRect, 0, 0, fgWidth, fgHeight); fgPixMap := CGrafPtr(info^.wptr)^.PortPixMap; DummyMatrixRecord := LongInt(nil); mPtr := MatrixRecordPtr(ptr(DummyMatrixRecord)); {vdErr := VDSetPlayThruOnOff(vdig, vdPlayThruOff);} vdErr := VDSetPlayThruDestination(vdig, fgPixMap, gwRect, MatrixRecord(mPtr^), nil); if vdErr <> noErr then begin CloseVdig; str := ''; if vdErr=badDepthErr then str := ' (Cannot digitize using this screen depth)'; PutError(StringOf('Video digitizer error ', vdErr, str)); end; GrabbingToScreen := true; {vdErr := VDSetPlayThruOnOff(vdig, vdPlayThruOn);} end; procedure LookForVDig(var vdigError: boolean); {Look for a QuickTime video digitizer component} var result: LongInt; videoDesc: ComponentDescription; srcRrect: rect; vdErr: ComponentResult; vdigID: Component; begin vdigError := false; if Gestalt(gestaltQuickTime, result) <> noErr then begin ShowMessage('No QuickTime'); exit(LookForVDig); end; {$IFC PowerPC} if Gestalt(gestaltQuickTimeFeatures, result) <> noErr then begin ShowMessage('No QuickTime PPC support'); exit(LookForVDig); end; {$ENDC} videoDesc.componentType := VideoDigitizerComponentType; videoDesc.componentSubType := OSType(0); {any subtype} if UseBuiltinDigitizer then videoDesc.componentManufacturer := 'appl' else videoDesc.componentManufacturer := OSType(0); videoDesc.componentFlags := 0; videoDesc.componentFlagsMask := 0; vdigID :=FindNextComponent(Component(0), videoDesc); if vdigID = Component(0) then begin videoDesc.componentManufacturer := OSType(0); {any manufacturer} vdigID :=FindNextComponent(Component(0), videoDesc); if vdigID = Component(0) then begin ShowMessage('No vdig found'); exit(LookForVDig); end; end; vdig := OpenComponent(vdigID); if vdig = nil then begin ShowMessage('Unable to open vdig'); vdigError := true; exit(LookForVDig); end; SetVideoStandard; vdErr := VDGetDigitizerRect(vdig, srcRrect); {vdErr := VDGetActiveSrcRect(vdig, 0, srcRrect);} if vdErr = noErr then with srcRrect do begin fgWidth := (right - left) div fgScale; fgHeight := (bottom - top) div fgScale; end else begin fgWidth := 320; fgHeight := 240; end; FrameGrabber := QTvdig; if not SetupVdig then vdigError := true; HighlightSaturatedPixels := false; end; procedure CorrectShadingOfLine (PicPtr, BFPtr: ptr; width, BFMean: integer); {$IFC PowerPC} VAR PicLine,BFLine:LinePtr; i,value:LongInt; BEGIN PicLine:=LinePtr(PicPtr); BFLine:=LinePtr(BFPtr); FOR i:=0 TO width-1 DO BEGIN value:=PicLine^[i]; value:=255-value; value:=(value * BFMean + (BFLine^[i] div 2)) DIV BFLine^[i]; IF value>254 THEN value:=254; IF value<1 THEN value:=1; PicLine^[i]:=255-value; END; END; {$ELSEC} {a0=data pointer} {a1=blank field data pointer} {d0=count} {d1=pixel value} {d2=blank field pixel value} {d3=blank field mean} {d4=temp} {d5=max pixel value(245)} {d6=min pixel value(1)} inline $4E56, $0000, { link a6,#0} $48E7, $FEC0, { movem.l a0-a1/d0-d6,-(sp)} $206E, $000C, { move.l 12(a6),a0} $226E, $0008, { move.l 8(a6),a1} $4280, { clr.l d0} $302E, $0006, { move.w 6(a6),d0} $362E, $0004, { move.w 4(a6),d3} $2A3C, $0000, $00FE, { move.l #254,d5} $2C3C, $0000, $0001, { move.l #1,d6} $5380, { subq.l #1,d0} $4281, { clr.l d1} $4282, { clr.l d2} $1210, {L1 move.b (a0),d1} $1419, { move.b (a1)+,d2} $4601, { not.b d1} $C2C3, { mulu.w d3,d1} $2802, { move.l d2,d4} $E244, { asr.w #1,d4} $D284, { add.l d4,d1} $82C2, { divu.w d2,d1} $B245, { cmp.w d5,d1} $6F02, { ble.s L2} $3205, { move.w d5,d1} $B246, {L2 cmp.w d6,d1} $6C02, { bge.s L3} $3206, { move.w d6,d1} $4601, {L3 not.b d1} $10C1, { move.b d1,(a0)+} $51C8, $FFDE, { dbra d0,L1} $4CDF, $037F, { movem.l (sp)+,a0-a1/d0-d6} $4E5E, { unlk a6} $DEFC, $000C; { add.w #12,sp} {$ENDC} procedure CorrectShading; var i, tag, width: integer; offset, NextUpdate: LongInt; p1, p2: ptr; str: str255; MaskRect:rect; begin with info^ do begin if ImageSize <> BlankFieldInfo^.ImageSize then begin beep; exit(CorrectShading); end; ShowWatch; tag:=0; NextUpdate:=TickCount+6; width:=PicRect.right; p1 := PicBaseAddr; p2 := BlankFieldInfo^.PicBaseAddr; for i := 1 to nLines do begin CorrectShadingOfLine(p1, p2, PixelsPerLine, BlankFieldMean); p1 := ptr(ord4(p1) + info^.BytesPerRow); p2 := ptr(ord4(p2) + BlankFieldInfo^.BytesPerRow); if TickCount>=NextUpdate then begin SetRect(MaskRect, 0, tag, width, i); UpdateScreen(MaskRect); tag:=i; NextUpdate:=TickCount+6; end; end; SetRect(MaskRect, 0, tag, width, nLines); UpdateScreen(MaskRect); str := title; if SpatiallyCalibrated then str := concat(str, chr($13)); {Black Diamond} if fit <> uncalibrated then str := concat(str, ''); if wptr <> nil then SetWTitle(wptr, concat(str, ' (Corrected)')); end; end; procedure CopyVdigImageOffscreen; var SaveExtraColors: integer; begin with info^ do begin SaveExtraColors := 0; if (LUTMode = Grayscale) and (not IdentityFunction or (nExtraColors <> 0)) then begin SaveExtraColors := nExtraColors; nExtraColors := 0; ResetGrayMap; end; CopyOffscreen(fgPixMap, osPort^.portPixMap, PicRect, PicRect); if SaveExtraColors <> 0 then begin nExtraColors := SaveExtraColors; LoadLUT(ctable); end; UpdatePicWindow; end; {with} end; procedure StartFrame; begin if CurrentBufferIsZero then begin if FrameGrabber = ScionAG5 then BufferReg^ := $81 else BufferReg^ := 0 end else begin if FrameGrabber = ScionAG5 then BufferReg^ := $89 else BufferReg^ := 1; end; if ExternalTrigger then begin if FrameGrabber = ScionAG5 then ControlReg^ := bor(bor(ord(AG5GrabMode), $90), bsl(ord(AG5LutMode and not ControlKeyDown), 2)) else ControlReg^ := $90 {Start frame capture} end else begin if FrameGrabber = ScionAG5 then ControlReg^ := bor(bor(ord(AG5GrabMode), $80), bsl(ord(AG5LutMode and not ControlKeyDown), 2)) else ControlReg^ := $80; {Start frame capture} end; FlushCache; end; procedure StopFrame; var ticks, timeout: LongInt; begin if ExternalTrigger then begin {Wait for trigger} repeat if button then ExternalTrigger := false; until (BitAnd(ControlReg^, $80) = $80) or not ExternalTrigger; ControlReg^ := 0; end {if External Trigger} else begin TimeOut := TickCount + 30; {1/2sec. timeout} while BitAnd(ControlReg^, $80) = 0 do begin {Wait for it to complete} if TickCount > TimeOut then begin ControlReg^ := 0; leave end; end; ControlReg^ := 0; end; with fgPort^ do with PortPixMap^^ do if CurrentBufferIsZero then BaseAddr := ptr(fgSuperSlotBase0) else BaseAddr := ptr(fgSuperSlotBase1); CurrentBufferIsZero := not CurrentBufferIsZero; fgFrameCount := fgFrameCount + 1; end; procedure StopDigitizing; begin if digitizing then with info^ do begin if DoubleBuffering then StopFrame; FlushCache; ShowFrameRate('', fgStartTicks, fgFrameCount); if vdig <> nil then CopyVdigImageOffscreen else CopyOffscreen(fgPixMap, osPort^.portPixMap, PicRect, PicRect); SetMenuItemText(SpecialMenuH, StartItem, 'Start Capturing'); Digitizing := false; ContinuousHistogram := false; if DoubleBuffering then begin {StopFrame;} BufferReg^ := 0; CurrentBufferIsZero := true; DoubleBuffering := false; with fgPort^ do with PortPixMap^^ do BaseAddr := ptr(fgSuperSlotBase0) end; with info^ do if PictureType = FrameGrabberType then begin title := 'Camera'; UpdateTitleBar; if HighlightSaturatedPixels then LoadLUT(ctable); end; if (ScreenDepth<>8) and HighlightSaturatedPixels then UpdatePicWindow; if (BlankFieldInfo <> nil) and not OptionKeyDown then CorrectShading; end; end; procedure GetFrame; var ticks, timeout: LongInt; temp:integer; vdigErr: ComponentResult; begin case FrameGrabber of ScionLG3, ScionVG5f: if ExternalTrigger then begin {Wait for trigger} ControlReg^ := $90; repeat if button then ExternalTrigger := false; until (band(ControlReg^, $80) = $80) or not ExternalTrigger; ControlReg^ := 0; if Digitizing then StopDigitizing; UpdateVideoControl; end {if External Trigger} else begin TimeOut := TickCount + 30; {1/2sec. timeout} ControlReg^ := $80; {Start frame capture} while band(ControlReg^, $80) = 0 do begin {Wait for it to complete} if TickCount > TimeOut then begin ControlReg^ := 0; leave end; end; ControlReg^ := 0; end; ScionAG5: if ExternalTrigger then begin {Wait for trigger} ControlReg^ := bor(bor(ord(AG5GrabMode), $90), bsl(ord(AG5LutMode and not ControlKeyDown), 2)); repeat if button then ExternalTrigger := false; until (band(ControlReg^, $80) = $80) or not ExternalTrigger; ControlReg^ := 0; if Digitizing then StopDigitizing; UpdateVideoControl; end {if External Trigger} else begin TimeOut := TickCount + 30; {1/2sec. timeout} ControlReg^ := bor(bor(ord(AG5GrabMode), $80), bsl(ord(AG5LutMode and not ControlKeyDown), 2)); {Start frame capture} repeat if TickCount > TimeOut then leave; temp:=ControlReg^; {ppc-bug} until band(temp, $80) <> 0; {Wait for it to complete} ControlReg^ := 0; end; QuickCapture: if ExternalTrigger then begin {Wait for trigger} ControlReg^ := $82; {Set Busy and External Trigger Enable bits} repeat if button then ExternalTrigger := false; temp:=ControlReg^; {ppc-bug} until (band(temp, $80) = 0) or not ExternalTrigger; if Digitizing then StopDigitizing; UpdateVideoControl; end {if External Trigger} else begin TimeOut := TickCount + 30; {1/2sec. timeout} ControlReg^ := $80; {Start frame capture by setting busy bit} repeat if TickCount > TimeOut then leave; temp:=ControlReg^; {ppc-bug} until band(temp, $80) = 0; {Wait for frame capture to complete} end; QTvdig: begin if ExternalTrigger then begin {Wait for mouse press} repeat until button; ExternalTrigger := false; end; if (vdig <> nil) and (fgPixMap=nil) then SetPlayThruDestination; if vdig <> nil then vdigErr := VDGrabOneFrame(vdig); end; end; {case} fgFrameCount := fgFrameCount + 1; FlushCache; end; procedure CaptureAndDisplayFrame; var tPort: GrafPtr; SaveGDevice: GDHandle; begin with info^ do begin if (PictureType <> FrameGrabberType) or (PixelsPerLine <> fgWidth) or (nlines <> fgHeight) then begin Digitizing := false; exit(CaptureAndDisplayFrame); end; if DoubleBuffering then begin StopFrame; StartFrame; end else GetFrame; if GrabbingToScreen then exit(CaptureAndDisplayFrame); SaveGDevice := GetGDevice; SetGDevice(GetMainDevice); getPort(tPort); SetPort(wptr); SetFColor(BlackIndex); SetBColor(WhiteIndex); if (FrameGrabber = QTvdig) and (LUTMode <> grayscale) and (ScreenDepth <= 8) then CopyBits(BitMapHandle(fgPixMap)^^, BitMapHandle(CGrafPtr(wptr)^.PortPixMap)^^, SrcRect, wrect, ditherCopy, nil) else CopyBits(BitMapHandle(fgPixMap)^^, BitMapHandle(CGrafPtr(wptr)^.PortPixMap)^^, SrcRect, wrect, srcCopy, nil); SetPort(tPort); SetGDevice(SaveGDevice); end; end; procedure SetReg (index, value: integer); const RegOffset = $f5fe0; var reg: ptr; begin reg := ptr(fgSlotBase + RegOffset + index * 4); reg^ := value; end; {$ifc PowerPC} {ppc-bug} procedure SwapMMUMode(var mode:SignedByte); begin end; {$endc} procedure SelectCameraWindow; {If there is a Camera window, activate it, otherwise, do nothing.} var i: integer; TempInfo: InfoPtr; begin for i := 1 to nPics do begin TempInfo := pointer(WindowPeek(PicWindow[i])^.RefCon); if TempInfo^.PictureType = FrameGrabberType then begin if PicWindow[i] <> nil then begin if OpPending then KillRoi; SelectWindow(PicWindow[i]); Info := TempInfo; ActivateWindow; end; {if} leave; end; {if} end; {for} end; procedure HighlightPixels; var lut: MyCSpecArray; begin with info^ do begin lut := ctable; lut[1].rgb := Highlight1; lut[254].rgb := Highlight254; LoadLUT(lut); end; end; procedure ShowTriggerMessage; begin if ExternalTrigger and (frameGrabber <> noFrameGrabber) then ShowMessage(concat('EXTERNAL TRIGGER MODE', crStr, '(Press mouse button to exit)')); end; procedure StartDigitizing; var i, width, height: integer; trect: rect; NewWindow: boolean; vdigError: boolean; begin if FrameGrabber = NoFrameGrabber then begin LookForVDig(vdigError); if vdigError then exit(StartDigitizing); end; if FrameGrabber = NoFrameGrabber then begin PutError('Capturing requires a Data Translation, Scion or QuickTime compatible frame grabber.'); AbortMacro; exit(StartDigitizing) end; if Digitizing then begin StopDigitizing; if BlankFieldInfo <> nil then wait(15); FlushEvents(EveryEvent, 0); {In case user holds key down too long} exit(StartDigitizing) end; if info^.PictureType <> FrameGrabberType then SelectCameraWindow; NewWindow := false; with info^ do if (PictureType <> FrameGrabberType) or (PixelsPerLine <> fgWidth) or (nlines <> fgHeight) then begin if not NewPicWindow('Camera', fgWidth, fgHeight) then exit(StartDigitizing); if FrameGrabber = QTvdig then with info^ do begin fgPort := osPort; fgSlotBase := LongInt(PicBaseAddr); fgRowBytes := BytesPerRow; end; NewWindow := true; end; with info^ do begin PictureType := FrameGrabberType; if NewWindow and (not EqualRect(SrcRect, PicRect)) then {Center Frame} with SrcRect do begin width := right - left; height := bottom - top; left := (PicRect.right - width) div 2; right := left + width; top := (PicRect.bottom - height) div 2; bottom := top + height; end; KillRoi; if ScaleToFitWindow then ScaleToFit; with SrcRect do begin width := right - left; left := band(left, $fffc); right := left + width; end; GetWindowRect(wptr, trect); with trect do if band(left, 3) <> 0 then MoveWindow(wptr, band(left, $fffc), top, true); {Forces window to be word aligned} with SrcRect do {Prevents bus errors when Camera window moved.} if (top = 0) and (bottom < PicRect.bottom) then begin top := top + 1; bottom := bottom + 1; end; ResetFrameGrabber; Digitizing := true; SetMenuItemText(SpecialMenuH, StartItem, 'Stop Capturing'); changes := true; BinaryPic := false; UpdateTitleBar; if HighlightSaturatedPixels then HighlightPixels; end; {with info} fgFrameCount := 0; fgStartTicks := TickCount; ContinuousHistogram := false; ShowTriggerMessage; if PCIFramegrabber and not ExternalTrigger then begin DoubleBuffering := true; CurrentBufferIsZero := true; StartFrame; end; end; procedure AddLineToSum (src, dst: ptr; width: LongInt); {$IFC PowerPC} type SumLineType = array[0..2047] of integer; fptr = ^SumLineType; var FrameLine: LinePtr; SumLine: fptr; i: integer; begin FrameLine := LinePtr(src); SumLine := fptr(dst); for i := 0 to width - 1 do SumLine^[i] := SumLine^[i] + FrameLine^[i]; end; {$ELSEC} inline {a0=data pointer} {a1=sum buffer pointer} {d0=count} {d1=pixel value} {d2=temp} $4E56, $0000, {link a6,#0} $48E7, $E0C0, {movem.l a0-a1/d0-d2,-(sp)} $206E, $000C, {move.l 12(a6),a0} $226E, $0008, {move.l 8(a6),a1} $202E, $0004, {move.l 4(a6),d0} $5380, {subq.l #1,d0} $4281, {clr.l d1} $4282, {clr.l d2} $1218, {L1 move.b (a0)+,d1} $3411, {move.w (a1),d2} $D441, {add.w d1,d2} $32C2, {move.w d2,(a1)+} $51C8, $FFF6, {dbra d0,L1} $4CDF, $0307, {movem.l (sp)+,a0-a1/d0-d2} $4E5E, {unlk a6} $DEFC, $000C; {add.w #12,sp} {$ENDC} function DoAveragingOptions: boolean; const FramesID = 8; VideoRateID = 9; SumID = 10; ShowID = 11; FixID = 12; MinID = 13; MaxID = 14; OnChipID = 15; var mylog: DialogPtr; item, i: integer; begin InitCursor; mylog := GetNewDialog(140, nil, pointer(-1)); if not SumFrames then begin ShowIntegratedValues := false; FixIntegrationScale := false; end; SetDNum(MyLog, FramesID, FramesToAverage); SetDlogItem(mylog, SumID, ord(SumFrames)); SetDlogItem(mylog, VideoRateID, ord(VideoRateAveraging)); SetDlogItem(mylog, ShowID, ord(ShowIntegratedValues)); SetDlogItem(mylog, FixID, ord(FixIntegrationScale)); SetDlogItem(mylog, OnChipID, ord(IntegrateOnChip)); SetDNum(MyLog, MinID, IntegrationMin); SetDNum(MyLog, MaxID, IntegrationMax); SelectDialogItemText(MyLog, FramesID, 0, 32767); repeat ModalDialog(nil, item); if item = FramesID then FramesToAverage := GetDNum(MyLog, FramesID); if item = SumID then begin SumFrames := not SumFrames; if SumFrames then IntegrateOnChip := false else begin FixIntegrationScale := false; ShowIntegratedValues := false; end; SetDlogItem(mylog, SumID, ord(SumFrames)); SetDlogItem(mylog, FixID, ord(FixIntegrationScale)); SetDlogItem(mylog, ShowID, ord(ShowIntegratedValues)); SetDlogItem(mylog, OnChipID, ord(IntegrateOnChip)); end; if item = VideoRateID then begin VideoRateAveraging := not VideoRateAveraging; if VideoRateAveraging then IntegrateOnChip := false; SetDlogItem(mylog, VideoRateID, ord(VideoRateAveraging)); SetDlogItem(mylog, OnChipID, ord(IntegrateOnChip)); end; if item = ShowID then begin ShowIntegratedValues := not ShowIntegratedValues; if ShowIntegratedValues then begin SumFrames := true; IntegrateOnChip := false; end; SetDlogItem(mylog, ShowID, ord(ShowIntegratedValues)); SetDlogItem(mylog, SumID, ord(SumFrames)); SetDlogItem(mylog, OnChipID, ord(IntegrateOnChip)); end; if item = FixID then begin FixIntegrationScale := not FixIntegrationScale; if FixIntegrationScale then begin SumFrames := true; IntegrateOnChip := false; end; SetDlogItem(mylog, FixID, ord(FixIntegrationScale)); SetDlogItem(mylog, SumID, ord(SumFrames)); SetDlogItem(mylog, OnChipID, ord(IntegrateOnChip)); end; if (item = MinID) or (item = MaxID) then begin if item = MinID then IntegrationMin := GetDNum(MyLog, MinID) else IntegrationMax := GetDNum(MyLog, MaxID); SumFrames := true; FixIntegrationScale := true; IntegrateOnChip := false; SetDlogItem(mylog, SumID, ord(SumFrames)); SetDlogItem(mylog, FixID, ord(FixIntegrationScale)); SetDlogItem(mylog, OnChipID, ord(IntegrateOnChip)); end; if item = OnChipID then begin IntegrateOnChip := not IntegrateOnChip; if IntegrateOnChip then begin SumFrames := false; VideoRateAveraging := false; FixIntegrationScale := false; ShowIntegratedValues := false; end; SetDlogItem(mylog, OnChipID, ord(IntegrateOnChip)); SetDlogItem(mylog, SumID, ord(SumFrames)); SetDlogItem(mylog, VideoRateID, ord(VideoRateAveraging)); SetDlogItem(mylog, FixID, ord(FixIntegrationScale)); SetDlogItem(mylog, ShowID, ord(ShowIntegratedValues)); end; until (item = ok) or (item = cancel); DisposeDialog(mylog); if FramesToAverage < 2 then FramesToAverage := 2; if IntegrationMin < 0 then IntegrationMin := 0; if IntegrationMax > 32767 then IntegrationMax := 32767; if VideoRateAveraging and (item <> cancel) then begin if (FrameGrabber <> ScionLG3) and (FrameGrabber <> ScionAG5) then begin VideoRateAveraging := false; PutError('Video rate averaging or summation requires a Scion LG-3 or a Scion AG-5.'); DoAveragingOptions := false; exit(DoAveragingOptions); end; if (FrameGrabber = ScionLG3) and (FramesToAverage > MaxLG3Frames) then begin FramesToAverage := MaxLG3Frames; DoAveragingOptions := false; PutError(concat('This ', long2str(MaxLG3Frames div 2), 'MB LG-3 can capture a maximum of ', long2str(MaxLG3Frames), ' frames at video rates.')); exit(DoAveragingOptions); end; if (FrameGrabber = ScionAG5) and (FramesToAverage > 127) then begin FramesToAverage := 127; DoAveragingOptions := false; PutError(concat('The AG-5 can average or sum a maximum of 127 frames at video rates.')); exit(DoAveragingOptions); end; end; if IntegrateOnChip and (item <> cancel) then if (FrameGrabber <> ScionLG3) and (FrameGrabber <> ScionAG5) and (FrameGrabber <> ScionVG5f) then begin IntegrateOnChip := false; PutError('On-chip integration requires a Scion frame grabber.'); DoAveragingOptions := false; exit(DoAveragingOptions); end; DoAveragingOptions := item <> cancel; end; function OddEven: boolean; {Looks at the the Field Status bit of the Status Register, which has the same address as Control Register 1. This bit is high during the odd field and low during the even field.} begin if band(ControlReg^, $10) = $10 then OddEven := true else OddEven := false; end; procedure WaitForOdd; var timeout: LongInt; begin TimeOut := TickCount + 30; {1/2sec. timeout} while OddEven do if TickCount > TimeOut then Exit(WaitForOdd); TimeOut := TickCount + 30; {1/2sec. timeout} while not OddEven do if TickCount > TimeOut then Exit(WaitForOdd); end; procedure IntegrateOn; {Sets bit 3 (Open Drain Output) of Control Register 1 high which pulls pin 11 of the 15 pin connector low, causing the Cohu camera to start integrating.} begin ControlReg^ := $08; end; procedure IntegrateOff; {Sets bit 3 of Control Register 1 low which open circuits pin 11, causing the Cohu camera to stop integrating.} begin ControlReg^ := $00; end; procedure DoOnChipIntegration; {Requires a Scion LG-3, a Cohu 4910 series camera, and a cable available from Scion.} var i,StartTicks:LongInt; str:str255; begin WaitForOdd; IntegrateOn; StartTicks := TickCount; for i := 1 to FramesToAverage - 1 do begin WaitForOdd; if (i mod 30) = 0 then ShowAnimatedWatch; if CommandPeriod then leave; end; IntegrateOff; GetFrame; RealToString((TickCount - StartTicks) / 60.0, 1, 2, str); ShowFrameRate(concat(Long2str(FramesToAverage), ' frames', cr, str, ' seconds', cr), StartTicks, FramesToAverage); with info^ do CopyOffscreen(fgPixMap, osPort^.portPixMap, RoiRect, RoiRect); UpdatePicWindow; KillRoi; if BlankFieldInfo <> nil then CorrectShading; if info^.fit<>uncalibrated then RemoveDensityCalibration; end; procedure DoHardwareAveraging; {Do averaging or integration at video rates using the Scion Ag-5.} var StartTicks,ActualMin,ActualMax:LongInt; str1,str2:str255; frame,i:integer; roi:rect; begin roi:=info^.RoiRect; KillRoi; if FramesToAverage > 127 then FramesToAverage := 127; ExternalTrigger := false; AG5GrabMode := GrabNormal; GetFrame; StartTicks := TickCount; AG5GrabMode := GrabSum; for frame := 1 to FramesToAverage - 1 do begin GetFrame; end; RealToString((TickCount - StartTicks) / 60.0, 1, 2, str2); if not SumFrames then begin ConstantReg^ := FramesToAverage; AG5GrabMode := GrabDivide; GetFrame; AG5GrabMode := GrabNormal; str1 := ''; end else begin ActualMin := Ord4(ScaleLowReg^); ActualMax := Ord4(ScaleHighReg^); if FixIntegrationScale then begin ScaleLowReg^ := integer(IntegrationMin); ScaleHighReg^ := integer(IntegrationMax); end; AG5GrabMode := GrabScale; GetFrame; AG5GrabMode := GrabNormal; if FixIntegrationScale then str1 := concat('min=', long2str(IntegrationMin), ' (', long2str(ActualMin), ')', cr, 'max=', long2str(IntegrationMax), ' (', long2str(ActualMax), ')', cr) else str1 := concat('min=', long2str(ActualMin), cr, 'max=', long2str(ActualMax), cr) end; ShowFrameRate(concat(Long2str(FramesToAverage), ' frames', cr, str1, str2, ' seconds', cr), StartTicks, FramesToAverage); with info^ do CopyOffscreen(fgPixMap, osPort^.portPixMap, roi, roi); UpdatePicWindow; if not EqualRect(roi, info^.PicRect) then RestoreRoi; if BlankFieldInfo <> nil then CorrectShading; if ShowIntegratedValues then with info^ do begin fit := StraightLine; nCoefficients := 2; coefficient[2] := (ActualMax - ActualMin) / 253.0; coefficient[1] := ActualMin - coefficient[2]; ZeroClip := false; UpdateTitleBar; if macro then GenerateValues; end else if SumFrames and (info^.fit<>uncalibrated) then RemoveDensityCalibration; end; {DoAG5HardwareAveraging} procedure AverageFrames; type IntPtr = ^integer; SumLineType = array[0..2047] of integer; sptr = ^SumLineType; var AutoSelectAll: boolean; SelectionSize, FrameBufferSize, offset, StartTicks: LongInt; SumBase, src, srcbase, dst, OffscreenBase: ptr; str1, str2: str255; xLines, xPixelsPerLine, BytesPerLine, frame, line, pixel: integer; aline, BlankLine: LineType; GrabRect: rect; hstart, vstart, wwidth, wheight: integer; j, FramesAveraged: integer; SrcRowBytes, DstRowBytes, i, value, MinV, MaxV, range, ActualMin, ActualMax: LongInt; iptr: IntPtr; FrameLine: LinePtr; SumLine: sptr; SaveBlankFieldInfo: InfoPtr; myMMUMode: signedbyte; begin with info^ do if PictureType <> FrameGrabberType then begin PutError('You must have an active Camera window (created using Start Capturing) in order to average frames.'); AbortMacro; exit(AverageFrames) end; if NotRectangular or NotinBounds then begin AbortMacro; exit(AverageFrames); end; if (not OptionKeyWasDown) and (not macro) then begin if not DoAveragingOptions then exit(AverageFrames); end; SaveBlankFieldInfo := BlankFieldInfo; BlankFieldInfo := nil; {We don't want to do shading correction now} StopDigitizing; BlankFieldInfo := SaveBlankFieldInfo; OptionKeyWasDown := false; if (FrameGrabber <> ScionLG3) and (FrameGrabber <> ScionAG5) then VideoRateAveraging := false; if (FrameGrabber <> ScionLG3) and (FrameGrabber <> ScionAG5) and (FrameGrabber <> ScionVG5f) then IntegrateOnChip := false; ShowWatch; ShowTriggerMessage; AutoSelectAll := not Info^.RoiShowing; if AutoSelectAll then SelectAll(false); WhatToUndo := NothingToUndo; ContinuousHistogram := false; ResetFrameGrabber; if IntegrateOnChip then begin DoOnChipIntegration; exit(AverageFrames); end; if VideoRateAveraging and (FrameGrabber=ScionAg5) then begin DoHardwareAveraging; exit(AverageFrames); end; DrawLabels('Frame:', 'Total:', ''); with info^.RoiRect do SelectionSize := (ord4(right) - left) * (bottom - top); FrameBufferSize := SelectionSize * 2; if FrameBufferSize > BigBufSize then begin NumToString((FrameBufferSize div 2) div 1024, str1); str1 := concat('It must be enlarged to at least ', str1, 'K bytes.'); PutError(concat('The Undo/Clipboard buffer is too small to average the frames. ', str1)); if AutoSelectAll or (BlankFieldInfo <> nil) then KillRoi else ShowRoi; exit(AverageFrames) end; WhatsOnClip := NothingOnClip; SumBase := BigBuf; with info^, info^.RoiRect do begin offset := left + ord4(top) * BytesPerRow; OffscreenBase := ptr(ord4(PicBaseAddr) + offset); offset := left + ord4(top) * fgRowBytes; srcbase := ptr(ord4(ptr(fgSlotBase)) + offset); SrcRowBytes := fgRowBytes; xLines := bottom - top; xPixelsPerLine := right - left; BytesPerLine := xPixelsPerLine * 2; end; {with} for i := 0 to BytesPerLine - 1 do BlankLine[i] := WhiteIndex; dst := SumBase; for line := 1 to xLines do begin {zero buffer} BlockMove(@BlankLine, dst, BytesPerLine); dst := ptr(ord4(dst) + BytesPerLine); end; info^.title := 'Camera'; UpdateTitleBar; StartTicks := TickCount; if VideoRateAveraging then begin if FramesToAverage > MaxLG3Frames then FramesToAverage := MaxLG3Frames; ExternalTrigger := false; BufferReg^ := 0; GetFrame; StartTicks := TickCount - 2; for frame := 1 to FramesToAverage - 1 do begin BufferReg^ := Frame; GetFrame; end; BufferReg^ := 0; RealToString((TickCount - StartTicks) / 60.0, 1, 2, str1); ShowFrameRate(concat(Long2str(FramesToAverage), ' frames', crStr, str1, ' seconds', crStr), StartTicks, FramesToAverage); end; {if VideoRateAveraging} for frame := 0 to FramesToAverage - 1 do begin Show2Values(frame + 1, FramesToAverage); if VideoRateAveraging then BufferReg^ := Frame else begin GetFrame; if FrameGrabber = QTvdig then with info^ do CopyOffScreen(fgPixMap, osPort^.portPixMap, roiRect, roiRect); end; src := srcbase; dst := SumBase; myMMUMode := 1; SwapMMUMode(myMMUMode); for line := 1 to xLines do begin AddLineToSum(src, dst, xPixelsPerLine); src := ptr(ord4(src) + SrcRowBytes); dst := ptr(ord4(dst) + BytesPerLine); end; SwapMMUMode(myMMUMode); if CommandPeriod then begin beep; if AutoSelectAll then KillRoi else ShowRoi; exit(AverageFrames); end; end; {for} src := SumBase; dst := OffscreenBase; DstRowBytes := info^.BytesPerRow; if SumFrames then begin MinV := 2000000000; MaxV := 0; iptr := IntPtr(src); for i := 1 to SelectionSize do begin value := iptr^; if value > MaxV then MaxV := value; if value < MinV then MinV := value; iptr := IntPtr(ord4(iptr) + 2); end; ActualMin := MinV; ActualMax := MaxV; if FixIntegrationScale then begin MinV := IntegrationMin; MaxV := IntegrationMax; end; range := MaxV - MinV; if range <> 0 then for line := 1 to xLines do begin SumLine := sptr(src); FrameLine := LinePtr(dst); for j := 0 to xPixelsPerLine - 1 do begin value := ord4(SumLine^[j] - MinV) * 253 div range + 1; if value < 0 then value := 0; if value > 255 then value := 255; FrameLine^[j] := value; end; src := ptr(ord4(src) + BytesPerLine); dst := ptr(ord4(dst) + DstRowBytes); end else beep; end else for line := 1 to xLines do begin SumLine := sptr(src); FrameLine := LinePtr(dst); for j := 0 to xPixelsPerLine - 1 do FrameLine^[j] := SumLine^[j] div FramesToAverage; src := ptr(ord4(src) + BytesPerLine); dst := ptr(ord4(dst) + DstRowBytes); end; if not VideoRateAveraging then begin if SumFrames then begin if FixIntegrationScale then str1 := concat('min=', long2str(MinV), ' (', long2str(ActualMin), ')', crStr, 'max=', long2str(MaxV), ' (', long2str(ActualMax), ')', crStr) else str1 := concat('min=', long2str(MinV), crStr, 'max=', long2str(MaxV), crStr) end else str1 := ''; RealToString((TickCount - StartTicks) / 60.0, 1, 2, str2); ShowFrameRate(concat(Long2str(FramesToAverage), ' frames', crStr, str1, str2, ' seconds', crStr), StartTicks, FramesToAverage); end; UpdatePicWindow; if AutoSelectAll then KillRoi else ShowRoi; if BlankFieldInfo <> nil then CorrectShading; if ShowIntegratedValues then with info^ do begin fit := StraightLine; nCoefficients := 2; coefficient[2] := (MaxV - MinV) / 253.0; coefficient[1] := MinV - coefficient[2]; nKnownValues := 0; ZeroClip := false; UpdateTitleBar; if macro then GenerateValues; end else if SumFrames and (info^.fit<>uncalibrated) then RemoveDensityCalibration; end; function GetFGPixel (h, v: integer): integer; var offset: LongInt; p: ptr; begin if FrameGrabber = QTvdig then begin GetFGPixel := 0; exit(GetFGPixel); end; with Info^ do begin if (h < 0) or (v < 0) or (h >= fgWidth) or (v >= fgHeight) then begin GetFGPixel := WhiteIndex; exit(GetFGPixel); end; offset := ord4(v) * fgRowBytes + h; if offset >= ord4(fgHeight) * fgRowBytes then begin GetFGPixel := WhiteIndex; exit(GetFGPixel); end; p := ptr(ord4(ptr(fgSlotBase)) + offset); GetFGPixel := BAND(p^, 255); end; end; procedure WaitForTrigger; begin StopDigitizing; ShowWatch; case FrameGrabber of QuickCapture: begin ControlReg^ := BitAnd($82, 255); {Wait for external trigger and capture one frame} repeat until (BitAnd(ControlReg^, $80) = $00) or Button; {Wait for it to complete} end; ScionLG3, ScionAg5, ScionVG5f: begin ControlReg^ := $90; {Wait for external trigger and capture one frame} repeat until (BitAnd(ControlReg^, $80) = $80) or Button; {Wait for it to complete} end; otherwise repeat until Button; end; end; procedure DoVideoSettingsDialog; {Displays QuickTime video digitizer options dialog box} const grayID = 6; color8ID = 7; color24ID = 8; fullID = 10; oneHalfID = 11; oneQuarterID = 12; ntscID = 14; palID = 15; secamID =16; builtinID = 17; sVideoID = 18; var mylog: DialogPtr; item, ignore: integer; saveScale: integer; saveBuiltin, sVideo: boolean; wasDigitizing, WindowClosed, vdigError: boolean; saveStandard: VideoDigitizerStandard; saveMode: VideoDigitizerMode; procedure SetCaptureModeButtons; begin SetDlogItem(mylog, grayID, ord(DigitizerMode = digitizeGrayscale)); SetDlogItem(mylog, color8ID, ord(DigitizerMode = digitizeColor)); SetDlogItem(mylog, color24ID, ord(DigitizerMode = digitizeRGB)); end; procedure SetSizeButtons; begin SetDlogItem(mylog, fullID, ord(fgScale = 1)); SetDlogItem(mylog, oneHalfID, ord(fgScale = 2)); SetDlogItem(mylog, oneQuarterID, ord(fgScale = 4)); end; procedure SetStandardButtons; begin SetDlogItem(mylog, ntscID, ord((DigitizerStandard = defaultStd) or (DigitizerStandard = NTSCStd))); SetDlogItem(mylog, palID, ord(DigitizerStandard = palStd)); SetDlogItem(mylog, secamID, ord(DigitizerStandard = secamStd)); end; begin saveScale := fgScale; saveBuiltIn := UseBuiltinDigitizer; saveMode := DigitizerMode; saveStandard := DigitizerStandard; sVideo := VideoChannel = 1; InitCursor; mylog := GetNewDialog(320, nil, pointer(-1)); SetCaptureModeButtons; SetSizeButtons; SetStandardButtons; SetDlogItem(mylog, builtinID, ord(UseBuiltinDigitizer)); SetDlogItem(mylog, sVideoID, ord(sVideo)); repeat ModalDialog(nil, item); if item = grayID then begin DigitizerMode := digitizeGrayscale; SetCaptureModeButtons; end; if item = color8ID then begin DigitizerMode := digitizeColor; SetCaptureModeButtons; end; if item = color24ID then begin DigitizerMode := digitizeRGB; SetCaptureModeButtons; end; if item = fullID then begin fgScale := 1; SetSizeButtons; end; if item = oneHalfID then begin fgScale := 2; SetSizeButtons; end; if item = oneQuarterID then begin fgScale := 4; SetSizeButtons; end; if item = ntscID then begin DigitizerStandard := ntscStd; SetStandardButtons; end; if item = palID then begin DigitizerStandard := palStd; SetStandardButtons; end; if item = secamID then begin DigitizerStandard := secamStd; SetStandardButtons; end; if item = builtinID then begin UseBuiltinDigitizer := not UseBuiltinDigitizer; SetDlogItem(mylog, builtinID, ord(UseBuiltinDigitizer)); end; if item = sVideoID then begin sVideo := not sVideo; SetDlogItem(mylog, sVideoID, ord(sVideo)); end; until (item = ok) or (item = cancel); DisposeDialog(mylog); if item = cancel then begin fgScale := saveScale; UseBuiltinDigitizer := saveBuiltIn; DigitizerMode := saveMode; DigitizerStandard := saveStandard; exit(DoVideoSettingsDialog); end; if sVideo then VideoChannel := 1 else VideoChannel := 0; wasDigitizing := digitizing; StopDigitizing; WindowClosed := false; CloseVdig; if (fgScale <> saveScale) or (UseBuiltinDigitizer <> saveBuiltIn) or (DigitizerStandard <> saveStandard) then begin SelectCameraWindow; with info^ do if PictureType = FrameGrabberType then begin changes := false; ignore := CloseAWindow(wptr); WindowClosed := true; end; end; if FrameGrabber = NoFrameGrabber then LookForVDig(vdigError); if wasDigitizing or WindowClosed then StartDigitizing; end; procedure SetOffset (var offset, gain: integer); begin if offset < 0 then offset := 0; if offset > 255 then offset := 255; if offset > gain then offset := gain; DacLow := offset; DacHigh := DacLow + (255 - gain); end; procedure SetGain (var offset, gain: integer); begin if gain < 0 then gain := 0; if gain > 255 then gain := 255; if gain < DacLow then gain := DacLow; DacHigh := DacLow + (255 - gain); end; procedure ShowChannel; begin SetDlogItem(VideoControl, FirstChannelID, ord(VideoChannel = 0)); SetDlogItem(VideoControl, FirstChannelID + 1, ord(VideoChannel = 1)); SetDlogItem(VideoControl, FirstChannelID + 2, ord(VideoChannel = 2)); SetDlogItem(VideoControl, FirstChannelID + 3, ord(VideoChannel = 3)); end; procedure UpdateVideoControl; begin if VideoControl <> nil then SetDlogItem(VideoControl, TriggerID, ord(ExternalTrigger)); end; procedure ShowOffsetAndGain (offset, gain: integer); var str: str255; begin RealToString(offset, 3, 0, str); if str[1] = ' ' then str[1] := '0'; if str[2] = ' ' then str[2] := '0'; SetDString(VideoControl, OffsetID, str); RealToString(gain, 3, 0, str); if str[1] = ' ' then str[1] := '0'; if str[2] = ' ' then str[2] := '0'; SetDString(VideoControl, GainID, str); end; procedure ShowVideoControl; var gain: integer; begin InitCursor; VideoControl := GetNewDialog(130, nil, pointer(-1)); ShowChannel; SetDlogItem(VideoControl, InvertID, ord(InvertVideo)); SetDlogItem(VideoControl, HighlightID, ord(HighlightSaturatedPixels)); SetDlogItem(VideoControl, TriggerID, ord(ExternalTrigger)); SetDlogItem(VideoControl, SyncID, ord(SyncMode = SeparateSync)); gain := 255 - (DacHigh - DacLow); ShowOffsetAndGain(DacLow, gain); end; function NoScion:boolean; var NotFound:boolean; begin NotFound:=(FrameGrabber <> ScionLG3) and (FrameGrabber<>ScionAg5) and (FrameGrabber<>ScionVG5f); if NotFound then PutError('Programmable offset and gain are only supported on Scion frame grabbers.'); NoScion:=NotFound; end; procedure DoVideoControl (item: integer); var i: integer; OutOfRange, WasDigitizing: boolean; offset, gain, inc, count: integer; procedure SetVideoItem (item, value: integer); begin if VideoControl <> nil then SetDlogItem(VideoControl, item, value); end; begin InitCursor; gain := 255 - (DacHigh - DacLow); if (item >= FirstChannelID) and (item <= (FirstChannelID + 3)) then begin VideoChannel := item - FirstChannelID; if VideoControl <> nil then ShowChannel; if digitizing then ResetFrameGrabber; end; if item = InvertID then begin InvertVideo := not InvertVideo; SetVideoItem(InvertID, ord(InvertVideo)); if digitizing then ResetFrameGrabber; end; if item = HighlightID then begin HighlightSaturatedPixels := not HighlightSaturatedPixels; SetVideoItem(HighlightID, ord(HighlightSaturatedPixels)); if digitizing then begin if HighlightSaturatedPixels then HighlightPixels else LoadLUT(info^.ctable); end; end; if item = TriggerID then begin ExternalTrigger := not ExternalTrigger; case FrameGrabber of QuickCapture, ScionLG3, ScionAG5, ScionVG5f: begin WasDigitizing := digitizing; StopDigitizing; if ExternalTrigger and WasDigitizing then StartDigitizing; end; otherwise ExternalTrigger := false; end; SetVideoItem(TriggerID, ord(ExternalTrigger)); end; if item = SyncID then begin if SyncMode <> SeparateSync then SyncMode := SeparateSync else SyncMode := NormalSync; case FrameGrabber of ScionLG3, ScionAG5, ScionVG5f: if digitizing then ResetFrameGrabber; QuickCapture: begin PutError('Sync is not under program control on the QuickCapure card.'); SyncMode := NormalSync; AbortMacro; end; otherwise ; end; SetVideoItem(SyncID, ord(SyncMode = SeparateSync)); end; if (item >= OffsetUpID) and (item <= GainDownID) then begin if NoScion then exit(DoVideoControl); offset := DacLow; inc := 1; count := 0; repeat count := count + 1; if count > 2 then inc := 2; if count > 4 then inc := 5; if count > 8 then inc := 10; case item of OffsetUpID: begin offset := offset + inc; SetOffset(offset, gain); end; OffsetDownID: begin offset := offset - inc; SetOffset(offset, gain); end; GainUpID: begin gain := gain + inc; SetGain(offset, gain); end; GainDownID: begin gain := gain - inc; SetGain(offset, gain); end; end; {case} ShowOffsetAndGain(DacLow, gain); if Digitizing and (count > 1) then begin DacLowReg^ := DacLow; DacHighReg^ := DacHigh; CaptureAndDisplayFrame; if ContinuousHistogram then begin ShowContinuousHistogram; DrawHistogram end end else wait(5); until not button; end; if item = ResetID then begin if NoScion then exit(DoVideoControl); DacLow := DefaultDacLow; DacHigh := DefaultDacHigh; gain := 255 - (DacHigh - DacLow); ParamText(long2str(DacLow), long2str(gain), '', ''); ShowOffsetAndGain(DacLow, gain); end; if FramesToAverage < 2 then FramesToAverage := 2; if (FrameGrabber = ScionLG3) or (FrameGrabber=ScionAG5) or (FrameGrabber=ScionVG5f) then begin DacLowReg^ := DacLow; DacHighReg^ := DacHigh; end; end; procedure ShowVideoDialog; var vdigError: boolean; begin if FrameGrabber = noFrameGrabber then begin LookForVDig(vdigError); if vdigError then begin doVideoSettingsDialog; exit(ShowVideoDialog); end; end; if FrameGrabber = QTvdig then doVideoSettingsDialog else begin if VideoControl = nil then ShowVideoControl else SelectWindow(VideoControl); end; end; end.