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 Memory, QuickDraw, Packages, Menus, Events, Fonts, Scrap, ToolUtils, OSUtils,Resources, Errors, Palettes, QuickTimeComponents, GestaltEqu, globals, Utilities, Graphics, File1, Analysis; function DoAveragingOptions: boolean; procedure AverageFrames; procedure GetFrame; procedure CaptureAndDisplayFrame; procedure HighlightPixels; procedure ShowTriggerMessage; procedure StartDigitizing; procedure StopDigitizing; procedure SetVideoChannel; 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; {Begin Scion} procedure StartFrame; procedure StopFrame; procedure PrintVideo; {End Scion} 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 vdigInfo: DigitizerInfo); var err: ComponentResult; inFlags, outFlags: LongInt; begin 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 SetupVdig; var mPtr: MatrixRecordPtr; vdErr: ComponentResult; vdigInfo: DigitizerInfo; DummyMatrixRecord, bitDepth: LongInt; err: OSErr; flags: GWorldFlags; SaveGDevice: GDHandle; gwRect: rect; begin SetRect(gwRect, 0, 0, fgWidth, fgHeight); bitDepth := 8; if VDGetDigitizerInfo(vdig, vdigInfo) = noErr then begin GetGrabDepth(bitDepth, vdigInfo); SetVideoStandard(vdigInfo); end; 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; DummyMatrixRecord := LongInt(nil); mPtr := MatrixRecordPtr(ptr(DummyMatrixRecord)); vdErr := VDSetPlayThruDestination(vdig, fgPixMap, gwRect, MatrixRecord(mPtr^), nil); if vdErr <> noErr then begin CloseVdig; PutError(StringOf('Video digitizer error ', vdErr)); end; end; procedure LookForVDig; {Look for a QuickTime video digitizer component} var result: LongInt; videoDesc: ComponentDescription; srcRrect: rect; vdErr: ComponentResult; vdigID: Component; begin if Gestalt(gestaltQuickTime, result) <> noErr then begin ShowMessage('No QuickTime'); exit(LookForVDig); end; 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'); exit(LookForVDig); end; 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; SetupVdig; 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; {Begin Scion} if not (VideoRateBlank and VideoRateBlankValid) then begin {End Scion} 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); {Begin Scion} end; {End Scion} str := title; if SpatiallyCalibrated then str := concat(str, chr($13)); {Black Diamond} if fit <> uncalibrated then str := concat(str, ''); {Begin Scion} if not (VideoRateBlank and VideoRateBlankValid and ControlKeyDown) then str := concat(str, '(Corrected)'); if wptr <> nil then SetWTitle(wptr, str); {if wptr <> nil then SetWTitle(wptr, concat(str, ' (Corrected)'));} {End Scion} end; end; {Begin Scion} procedure StartFrame; begin if CurrentBufferIsZero then BufferReg^ := 0 else BufferReg^ := 1; if ExternalTrigger then ControlReg^ := $90 {Start frame capture} else ControlReg^ := $80; {Start frame capture} 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; {End Scion} procedure StopDigitizing; begin if digitizing then with info^ do begin ShowFrameRate('', fgStartTicks, fgFrameCount); CopyOffscreen(fgPixMap, osPort^.portPixMap, PicRect, PicRect); if vdig <> nil then UpdatePicWindow; SetMenuItemText(SpecialMenuH, StartItem, 'Start Capturing'); Digitizing := false; ContinuousHistogram := false; {Begin Scion} if DoubleBuffering then begin StopFrame; BufferReg^ := 0; CurrentBufferIsZero := true; DoubleBuffering := false; with fgPort^ do with PortPixMap^^ do BaseAddr := ptr(fgSuperSlotBase0) end; {End Scion} with info^ do if PictureType = FrameGrabberType then begin title := 'Camera'; UpdateTitleBar; if HighlightSaturatedPixels then LoadLUT(ctable); end; if (ScreenDepth<>8) and HighlightSaturatedPixels then UpdatePicWindow; {Begin Scion} if ((BlankFieldInfo <> nil) and not OptionKeyDown) or ((BlankFieldInfo <> nil) and VideoRateBlank and VideoRateBlankValid) then {if (BlankFieldInfo <> nil) and not OptionKeyDown then} {End Scion} 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 then vdigErr := VDGrabOneFrame(vdig); end; end; {case} fgFrameCount := fgFrameCount + 1; 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; {BeginScion} if DoubleBuffering then begin StopFrame; StartFrame; end else {End Scion} GetFrame; 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; begin if FrameGrabber = NoFrameGrabber then LookForVDig; 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 FrameGrabber = NoFrameGrabber then begin PutError('Capturing requires a Data Translation, Scion or QuickTime compatible frame grabber.'); AbortMacro; 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; {Begin Scion} if PCIFramegrabber and not ExternalTrigger then begin DoubleBuffering := true; CurrentBufferIsZero := true; StartFrame; end; {End Scion} 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 1024, str1); NumToString(BigBufSize div 1024, str2); str2 := concat(str1, 'K bytes are required, but only ', str2, 'K bytes are available.'); PutError(concat('There is not enough memory to do the requested frame averaging. ', str2)); 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; {Begin Scion} if DoubleBuffering then if CurrentBufferIsZero then p := ptr(ord4(ptr(fgSuperSlotBase1)) + offset) else p := ptr(ord4(ptr(fgSuperSlotBase0)) + offset) else {End Scion} 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; var mylog: DialogPtr; item, ignore: integer; saveScale: integer; saveBuiltin: boolean; wasDigitizing, WindowClosed: 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; InitCursor; mylog := GetNewDialog(320, nil, pointer(-1)); SetCaptureModeButtons; SetSizeButtons; SetStandardButtons; SetDlogItem(mylog, builtinID, ord(UseBuiltinDigitizer)); 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; until (item = ok) or (item = cancel); DisposeDialog(mylog); if item = cancel then begin fgScale := saveScale; UseBuiltinDigitizer := saveBuiltIn; DigitizerMode := saveMode; DigitizerStandard := saveStandard; exit(DoVideoSettingsDialog); end; 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; 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)); {Begin Scion} SetDlogItem(VideoControl, VideoRateMathID, ord(VideoRateMath)); SetDlogItem(VideoControl, VideoRateBlankID, ord(VideoRateBlank)); SetDlogItem(VideoControl, VideoPassID, ord(VideoPass)); {End Scion} 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; {Begin Scion} if item = VideoRateMathID then begin VideoRateMath := not VideoRateMath; case FrameGrabber of ScionAG5: begin if VideoRateMath then begin if VideoRateMathValid then begin AG5LutMode := true; end else begin PutMessage('Video rate math will begin after Video Math is executed.'); AG5LutMode := false; end; if VideoRateBlank then VideoRateBlank := false; end else AG5LutMode := false; end; otherwise begin PutMessage('Video rate math is only supported on the Scion AG-5.'); VideoRateMath := false; end; end; SetVideoItem(VideoRateMathID, ord(VideoRateMath)); SetVideoItem(VideoRateBlankID, ord(VideoRateBlank)); end; if item = VideoRateBlankID then begin VideoRateBlank := not VideoRateBlank; case FrameGrabber of ScionAG5: begin if VideoRateBlank then begin if VideoRateBlankValid then begin AG5LutMode := true; end else begin PutMessage('Video rate blank field correction will begin after Save Blank Field is executed.'); AG5LutMode := false; end; if VideoRateMath then VideoRateMath := false; end else AG5LutMode := false; end; otherwise begin PutMessage('Video rate blank field correction is only supported on the Scion AG-5.'); VideoRateBlank := false; end; end; SetVideoItem(VideoRateMathID, ord(VideoRateMath)); SetVideoItem(VideoRateBlankID, ord(VideoRateBlank)); end; if item = VideoPassID then begin VideoPass := not VideoPass; case FrameGrabber of ScionVG5f: begin ResetScionVG5t; end; otherwise begin PutMessage('Video pass through requires a Scion VG-5.'); VideoPass := false; end; end; SetVideoItem(VideoPassID, ord(VideoPass)); end; {End Scion} 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); if FrameGrabber=ScionLG3 then begin {Begin Scion} if PCIFrameGrabber then begin DacLow := DefaultLG3PCIDacLow; DacHigh := DefaultLG3PCIDacHigh; end else begin {End Scion} DacLow := DefaultLG3DacLow; DacHigh := DefaultLG3DacHigh; {Begin Scion} end; {End Scion} end else if FrameGrabber = ScionAG5 then begin DacLow := DefaultAG5DacLow; DacHigh := DefaultAG5DacHigh; end else begin DacLow := DefaultVG5DacLow; DacHigh := DefaultVG5DacHigh; end; 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; begin if FrameGrabber = noFrameGrabber then LookForVDig; if FrameGrabber = QTvdig then doVideoSettingsDialog else begin if VideoControl = nil then ShowVideoControl else SelectWindow(VideoControl); end; end; {Begin Scion} procedure PrintVideo; var SaveGDevice: GDHandle; kind: integer; sRect, dRect: Rect; wasRoi: boolean; ticks: longint; begin if TVBoard = NoTVBoard then begin PutMessage('Printing to video requires a Scion TV-3 video display board.'); exit(PrintVideo); end; if (TVBoard = ScionVG5t) and VideoPass then begin PutMessage('Video pass through must be disabled before printing to video.'); exit(PrintVideo); end; wasRoi := false; with info^ do begin kind := WindowPeek(wptr)^.WindowKind; if kind <> PicKind then begin PutMessage('You must have an active Picture window to print to video.'); exit(PrintVideo); end; if RoiType = NoRoi then begin if (SrcRect.right - SrcRect.left > tvWidth) or (SrcRect.bottom - SrcRect.top > tvHeight) then begin PutMessage('Picture is too large to print to video. Try selecting a region of interest.'); exit(PrintVideo); end; sRect := SrcRect; dRect := sRect; OffsetRect(dRect, -dRect.left, -dRect.top); OffsetRect(dRect, (tvWidth - (dRect.right - dRect.left)) div 2, (tvHeight - (dRect.bottom - dRect.top)) div 2); end; if RoiType <> NoRoi then begin if RoiType <> RectRoi then begin PutMessage('Only rectangular regions of interest may be printed to video.'); exit(PrintVideo); end; if (RoiRect.right - RoiRect.left > tvWidth) or (RoiRect.bottom - RoiRect.top > tvHeight) then begin PutMessage('Region of interest is too large to print to video.'); exit(PrintVideo); end; sRect := RoiRect; dRect := sRect; OffsetRect(dRect, -dRect.left, -dRect.top); OffsetRect(dRect, (tvWidth - (dRect.right - dRect.left)) div 2, (tvHeight - (dRect.bottom - dRect.top)) div 2); SaveRoi; KillRoi; wasRoi := true; end; if not OptionKeyWasDown then ResetTVBoard; SaveGDevice := GetGDevice; SetGDevice(osGDevice); hlock(handle(tvPort^.portPixMap)); hlock(handle(osPort^.portPixMap)); CopyBits(BitMapHandle(osPort^.portPixMap)^^, BitMapHandle(tvPort^.portPixMap)^^, sRect, dRect, SrcCopy, nil); hunlock(handle(tvPort^.portPixMap)); hunlock(handle(osPort^.portPixMap)); SetGDevice(SaveGDevice); if (TVBoard = ScionVG5t) then begin { wait for 6 ticks } ticks := TickCount; while ticks+6 > TickCount do ; { set bit 3 of CR2, along with bit 7 (Video Enable) } TVControlReg^ := $88; { wait for 15 ticks (1/4 second) } ticks := TickCount; while ticks+15 > TickCount do ; { clear bit 3 of CR2, but keep bit 7 set } TVControlReg^ := $80; end; if wasRoi then RestoreRoi; end; end; {End Scion} end.