unit Camera; {Routines used by the NIH Image for supporting the Data Translation} {QuickCapture card, the Scion Image 1000, and the Scion LG-3.} interface uses QuickDraw, Palettes, PrintTraps, globals, Utilities, Graphics, File1, Analysis; procedure AverageFrames; procedure GetFrame; procedure CaptureAndDisplayFrame; procedure HighlightPixels; procedure ShowTriggerMessage; procedure StartDigitizing; procedure StopDigitizing; procedure SetVideoChannel; function GetFGPixel (h, v: integer): integer; procedure CopyOffscreen (src, dst: PixMapHandle; sRect, dRect: rect); procedure GetScionFrame (DisplayPoint: point); procedure WaitForTrigger; procedure ShowChannel; procedure ShowVideoControl; procedure UpdateVideoControl; procedure DoVideoControl (item: integer); implementation type IntPtr = ^integer; var SavePicBaseAddr: ptr; StopFlagLoc: IntPtr; procedure CorrectShadingOfLine (PicPtr, BFPtr: ptr; width, BFMean: integer); {} {VAR} { PicLine,BFLine:LinePtr;} { i,value:integer;} {BEGIN} { PicLine:=LinePtr(PicPtr);} { BFLine:=LinePtr(BFPtr);} { FOR i:=0 TO width-1 DO BEGIN} { value:=PicLine^[i];} { value:=255-value;} { value:=(LongInt(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;} { } {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} {END;} procedure CorrectShading; var i: integer; offset: LongInt; p1, p2: ptr; str: str255; begin with info^ do begin if ImageSize <> BlankFieldInfo^.ImageSize then begin beep; exit(CorrectShading); end; ShowWatch; 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 i mod 96 = 0 then UpdatePicWindow; end; UpdatePicWindow; str := title; if SpatiallyCalibrated then str := concat(str, chr($13)); {Black Diamond} if DensityCalibrated then str := concat(str, ''); if wptr <> nil then SetWTitle(wptr, concat(str, '(Corrected)')); end; end; procedure CopyOffscreen (src, dst: PixMapHandle; sRect, dRect: rect); var SaveGDevice: GDHandle; begin SaveGDevice := GetGDevice; SetGDevice(osGDevice); hlock(handle(src)); hlock(handle(dst)); CopyBits(BitMapHandle(src)^^, BitMapHandle(dst)^^, sRect, dRect, SrcCopy, nil); hunlock(handle(src)); hunlock(handle(dst)); SetGDevice(SaveGDevice); end; procedure StopDigitizing; begin if digitizing then with info^ do begin ShowFrameRate('', fgStartTicks, fgFrameCount); CopyOffscreen(fgPort^.portPixMap, osPort^.portPixMap, PicRect, PicRect); SetItem(SpecialMenuH, StartItem, 'Start Capturing'); Digitizing := false; ContinuousHistogram := false; with info^ do if PictureType = FrameGrabberType then begin title := 'Camera'; UpdateTitleBar; if HighlightSaturatedPixels then LoadLUT(ctable); end; if (BlankFieldInfo <> nil) and not OptionKeyDown then CorrectShading; end; end; procedure GetFrame; var ticks, timeout: LongInt; begin if FrameGrabber = ScionLG3 then begin if ExternalTrigger then begin {Wait for trigger} ControlReg^ := $90; repeat if button then ExternalTrigger := false; until (BitAnd(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 BitAnd(ControlReg^, $80) = 0 do begin {Wait for it to complete} if TickCount > TimeOut then begin ControlReg^ := 0; leave end; end; ControlReg^ := 0; end; end else begin {QuickCapture} if ExternalTrigger then begin {Wait for trigger} ControlReg^ := BitAnd($82, 255); repeat if button then ExternalTrigger := false; until (ControlReg^ >= 0) or not ExternalTrigger; if Digitizing then StopDigitizing; UpdateVideoControl; end {if External Trigger} else begin TimeOut := TickCount + 30; {1/2sec. timeout} ControlReg^ := BitAnd($80, 255); {Start frame capture} while ControlReg^ < 0 do begin {Wait for it to complete} if TickCount > TimeOut then leave end; end; end; {QuickCapture} fgFrameCount := fgFrameCount + 1; end; procedure CaptureAndDisplayFrame; var tPort: GrafPtr; begin with info^ do begin if (PictureType <> FrameGrabberType) or (PixelsPerLine <> fgWidth) or (nlines <> fgHeight) then begin Digitizing := false; exit(CaptureAndDisplayFrame); end; GetFrame; getPort(tPort); SetPort(wptr); hlock(handle(fgPort^.portPixMap)); hlock(handle(CGrafPort(wptr^).PortPixMap)); CopyBits(BitMapHandle(fgPort^.portPixMap)^^, BitMapHandle(CGrafPort(wptr^).PortPixMap)^^, SrcRect, wrect, gCopyMode, nil); hunlock(handle(fgPort^.portPixMap)); hunlock(handle(CGrafPort(wptr^).PortPixMap)); SetPort(tPort); end; end; procedure SetReg (index, value: integer); const RegOffset = $f5fe0; var reg: ptr; begin reg := ptr(fgSlotBase + RegOffset + index * 4); reg^ := value; end; procedure ResetScion (GrabRect: rect; DisplayPoint: point); const ilutOffset = $f0000; LineStartsRamOffset = $f4000; type LineStartsArray = packed array[0..8191] of UnsignedByte; LineStartsType = ^LineStartsArray; var ScreenRowBytesx2: LongInt; LutPtr: ptr; LineStarts: LineStartsType; EvenStart, OddStart: LongInt; width, height, IndexOdd, IndexEven, index, i: integer; hstart, vstart: integer; begin ScreenRowBytesx2 := ScreenRowBytes * 2; LoadInputLUT(Ptr(fgSlotBase + ilutOffset)); with GrabRect, DisplayPoint do begin hstart := BitAnd(left, $fffc); vstart := BitAnd(top, $fffe); width := right - left; height := bottom - top; StopFlagLoc := IntPtr(LongInt(ScreenBase) + h + ScreenRowBytes * (v + height - 2) + 4); EvenStart := LongInt(ScreenBase) + h + ScreenRowBytes * v; OddStart := EvenStart + ScreenRowBytes; IndexOdd := 0; IndexEven := (height div 2) * 16; end; LineStarts := LineStartsType(fgSlotBase + LineStartsRamOffset); for i := 1 to height div 2 do begin LineStarts^[IndexOdd] := BSR(BitAnd(OddStart, $ff000000), 24); LineStarts^[IndexOdd + 4] := BSR(BitAnd(OddStart, $ff0000), 16); LineStarts^[IndexOdd + 8] := BSR(BitAnd(OddStart, $ff00), 8); LineStarts^[IndexOdd + 12] := BitAnd(OddStart, $fc); LineStarts^[IndexEven] := BSR(BitAnd(EvenStart, $ff000000), 24); LineStarts^[IndexEven + 4] := BSR(BitAnd(EvenStart, $ff0000), 16); LineStarts^[IndexEven + 8] := BSR(BitAnd(EvenStart, $ff00), 8); LineStarts^[IndexEven + 12] := BitAnd(EvenStart, $fc); IndexOdd := IndexOdd + 16; IndexEven := IndexEven + 16; OddStart := OddStart + ScreenRowBytesx2; EvenStart := EvenStart + ScreenRowBytesx2; end; Index := height * 16; LineStarts^[Index] := 0; LineStarts^[Index + 4] := 0; LineStarts^[Index + 8] := 0; LineStarts^[Index + 12] := 1; SetReg(1, 0); SetReg(2, 162 - (width div 4)); SetReg(3, 0); SetReg(4, 225 - (hstart div 4)); SetReg(5, 255 - (width div 4)); SetReg(6, 241 - (vstart div 2)); SetReg(7, 255 - (height div 2)); end; procedure GetScionFrame (DisplayPoint: point); {Captures a single Scion frame to screen memory.} type IntPtr = ^integer; var FlagLoc: IntPtr; StartTime: LongInt; myMMUMode: signedbyte; begin with DisplayPoint do FlagLoc := IntPtr(LongInt(ScreenBase) + h + ScreenRowBytes * v + 4); StartTime := TickCount; myMMUMode := 1; SwapMMUMode(myMMUMode); FlagLoc^ := $00ff; SetReg(1, BitOr(128, VideoChannel * 4)); {Grab Enable} while FlagLoc^ = $00ff do if TickCount > (StartTime + 5) then begin SetReg(1, 0); {Stop Grabbing} SwapMMUMode(myMMUMode); exit(GetScionFrame) end; StopFlagLoc^ := $00ff; while StopFlagLoc^ = $00ff do begin end; SetReg(1, 0); {Stop Grabbing} SwapMMUMode(myMMUMode); end; function GetScreenPixel (h, v: integer): integer; var offset: LongInt; p: ptr; begin offset := LongInt(v) * ScreenRowBytes + h; p := ptr(ord4(ScreenBase) + offset); GetScreenPixel := BAND(p^, 255); end; procedure CopyScionFrameOffscreen (DisplayPoint: point; wwidth, wheight: integer); var src, dst: ptr; line: integer; begin with Info^ do begin with DisplayPoint do src := ptr(LongInt(ScreenBase) + h + ScreenRowBytes * v); dst := ptr(LongInt(PicBaseAddr)); for line := 1 to wheight do begin BlockMove(src, dst, wwidth); src := ptr(ord4(src) + ScreenRowBytes); dst := ptr(ord4(dst) + BytesPerRow); end; end; end; procedure DoMiniEventLoop (FullScreenMode: boolean); var loc: point; event: EventRecord; begin FlushEvents(EveryEvent, 0); if not FullScreenMode then DrawLabels('X:', 'Y:', 'Value:'); repeat GetMouse(loc); LocalToGlobal(loc); if not FullScreenMode then with loc do Show3Values(h, v, GetScreenPixel(h, v)); until WaitNextEvent(mDownMask + KeyDownMask, Event, 0, nil); end; procedure SelectCameraWindow (grabber: PicType); {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 grabber = TempInfo^.PictureType 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 CaptureUsingScion; var GrabRect, ScreenSrcRect: rect; DisplayPoint: point; FullScreenMode: boolean; wwidth, wheight: integer; tPort: GrafPtr; SaveBackgroundColor, hstart, vstart: integer; ignore: integer; mloc: point; MainDevice: GDHandle; SrcPixMap: PixMapHandle; myMMUMode: signedbyte; FlagLoc: IntPtr; StartTime: LongInt; grabbing: boolean; begin FullScreenMode := OptionKeyDown and (ScreenWidth = 640); if FullScreenMode or (ScreenWidth > 640) then begin wwidth := MaxScionWidth; wheight := 480 end else begin wwidth := 552; if wwidth > MaxScionWidth then wwidth := MaxScionWidth; wheight := 436; end; SelectCameraWindow(ScionType); with Info^ do if PictureType = ScionType then with wrect do if (wwidth <> right) or (wheight <> bottom) then begin changes := false; ignore := CloseAWindow(wptr); end; with info^ do if PictureType <> ScionType then begin if not NewPicWindow('Camera(Scion)', wwidth, wheight) then begin beep; exit(CaptureUsingScion) end; end; KillRoi; with info^ do begin PictureType := ScionType; changes := true; UpdateTitleBar; end; hstart := (640 - wwidth) div 2; vstart := (480 - wheight) div 2; SetRect(GrabRect, hstart, vstart, hstart + wwidth, vstart + wheight); if FullScreenMode then with DisplayPoint do begin h := BitAnd((640 - wwidth) div 2, $fffc); v := 0; end else with DisplayPoint do begin h := PicLeftBase; v := PicTopBase; end; ResetScion(GrabRect, DisplayPoint); if FullScreenMode then begin GetPort(tPort); SaveBackgroundColor := BackgroundIndex; SetBackgroundColor(BlackIndex); EraseScreen; end; if info^.magnification <> 1.0 then Unzoom; with DisplayPoint do FlagLoc := IntPtr(LongInt(ScreenBase) + h + ScreenRowBytes * v + 4); StartTime := TickCount; grabbing := true; myMMUMode := 1; SwapMMUMode(myMMUMode); FlagLoc^ := $00ff; SetReg(1, BitOr(128, VideoChannel * 4)); {Grab Enable} while FlagLoc^ = $00ff do if TickCount > (StartTime + 5) then begin SetReg(1, 0); {Stop Grabbing} FlagLoc^ := $0000; SwapMMUMode(myMMUMode); grabbing := false; end; if grabbing then begin SwapMMUMode(myMMUMode); DoMiniEventLoop(FullScreenMode); myMMUMode := 1; SwapMMUMode(myMMUMode); StopFlagLoc^ := $00ff; while StopFlagLoc^ = $00ff do begin end; SetReg(1, 0); {Stop Grabbing} SwapMMUMode(myMMUMode); HideCursor; GetScionFrame(DisplayPoint); end; MainDevice := GetMainDevice; SrcPixMap := MainDevice^^.gdPMap; with DisplayPoint, ScreenSrcRect do begin left := h; top := v; right := left + wwidth; bottom := top + wheight; end; with info^ do begin CopyOffscreen(SrcPixMap, osPort^.portPixMap, ScreenSrcRect, PicRect); ShowCursor; if FullScreenMode then begin RestoreScreen; SetBackgroundColor(SaveBackgroundColor); SetPort(tPort); end; title := 'Camera'; UpdateTitleBar; end; {with} if (BlankFieldInfo <> nil) and not OptionKeyDown then CorrectShading; FlushEvents(EveryEvent, 0); 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 = QuickCapture) or (FrameGrabber = ScionLG3)) then ShowMessage(concat('EXTERNAL TRIGGER MODE', cr, '(Press mouse button to exit)')); end; procedure StartDigitizing; var i, width, height: integer; trect: rect; NewWindow: boolean; begin if FrameGrabber = Scion then begin if HighlightSaturatedPixels then HighlightPixels; CaptureUsingScion; if HighlightSaturatedPixels then LoadLUT(info^.ctable); 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 FrameGrabber = NoFrameGrabber then begin PutMessage('Capturing requires a Data Translation or SCION frame grabber card.'); exit(StartDigitizing) end; if info^.PictureType <> FrameGrabberType then SelectCameraWindow(FrameGrabberType); 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); 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; SetItem(SpecialMenuH, StartItem, 'Stop Capturing'); changes := true; BinaryPic := false; UpdateTitleBar; if HighlightSaturatedPixels then HighlightPixels; end; {with info} fgFrameCount := 0; fgStartTicks := TickCount; ContinuousHistogram := false; ShowTriggerMessage; end; procedure AddLineToSum (src, dst: ptr; width: LongInt); {$IFC false} 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; {$ENDC} 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} function DoAveragingOptions: boolean; const FramesID = 8; VideoRateID = 9; SumID = 10; ShowID = 11; FixID = 12; MinID = 13; MaxID = 14; 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); SetDialogItem(mylog, SumID, ord(SumFrames)); SetDialogItem(mylog, VideoRateID, ord(VideoRateAveraging)); SetDialogItem(mylog, ShowID, ord(ShowIntegratedValues)); SetDialogItem(mylog, FixID, ord(FixIntegrationScale)); SetDNum(MyLog, MinID, IntegrationMin); SetDNum(MyLog, MaxID, IntegrationMax); SelIText(MyLog, FramesID, 0, 32767); repeat ModalDialog(nil, item); if item = FramesID then FramesToAverage := GetDNum(MyLog, FramesID); if item = SumID then begin SumFrames := not SumFrames; SetDialogItem(mylog, SumID, ord(SumFrames)); end; if item = VideoRateID then begin VideoRateAveraging := not VideoRateAveraging; SetDialogItem(mylog, VideoRateID, ord(VideoRateAveraging)); end; if item = ShowID then begin ShowIntegratedValues := not ShowIntegratedValues; SetDialogItem(mylog, ShowID, ord(ShowIntegratedValues)); if ShowIntegratedValues then SumFrames := true; SetDialogItem(mylog, SumID, ord(SumFrames)); end; if item = FixID then begin FixIntegrationScale := not FixIntegrationScale; SetDialogItem(mylog, FixID, ord(FixIntegrationScale)); if FixIntegrationScale then SumFrames := true; SetDialogItem(mylog, SumID, ord(SumFrames)); end; if (item = MinID) or (item = MaxID) then begin if item = MinID then IntegrationMin := GetDNum(MyLog, MinID) else IntegrationMax := GetDNum(MyLog, MaxID); SumFrames := true; SetDialogItem(mylog, SumID, ord(SumFrames)); FixIntegrationScale := true; SetDialogItem(mylog, FixID, ord(FixIntegrationScale)); end; until (item = ok) or (item = cancel); DisposDialog(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 then begin VideoRateAveraging := false; PutMessage('Video rate capture requires a Scion LG-3.'); DoAveragingOptions := false; exit(DoAveragingOptions); end; if FramesToAverage > MaxLG3Frames then begin FramesToAverage := MaxLG3Frames; DoAveragingOptions := false; PutMessage(concat('This ', long2str(MaxLG3Frames div 2), 'MB LG-3 can capture a maximum of ', long2str(MaxLG3Frames), ' frames at video rates.')); exit(DoAveragingOptions); end; end; DoAveragingOptions := item <> cancel; end; 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; DisplayPoint: point; 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) and (PictureType <> ScionType) then begin PutMessage('You must have an active Camera window(created using Start Capturing) in order to average frames.'); macro := false; exit(AverageFrames) end; if NotRectangular or NotinBounds then begin macro := false; 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; DrawLabels('Frame:', 'Total:', ''); ShowTriggerMessage; ShowWatch; AutoSelectAll := not Info^.RoiShowing; if AutoSelectAll then SelectAll(false); with info^.RoiRect do SelectionSize := (LongInt(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.'); PutMessage(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; WhatToUndo := NothingToUndo; WhatsOnClip := NothingOnClip; SumBase := BigBuf; case FrameGrabber of QuickCapture: begin ContinuousHistogram := false; ResetQuickCapture end; ScionLG3: begin ContinuousHistogram := false; ResetScionLG3 end; Scion: begin with info^.wrect do begin wwidth := right; wheight := bottom; end; hstart := (640 - wwidth) div 2; vstart := (480 - wheight) div 2; SetRect(GrabRect, hstart, vstart, hstart + wwidth, vstart + wheight); with DisplayPoint do begin h := PicLeftBase; v := PicTopBase; end; ResetScion(GrabRect, DisplayPoint); HideCursor; end; end; {case} with info^, info^.RoiRect do begin offset := left + LongInt(top) * BytesPerRow; OffscreenBase := ptr(ord4(PicBaseAddr) + offset); if FrameGrabber = Scion then with DisplayPoint do begin BringToFront(wptr); offset := left + h + (v + top) * ScreenRowBytes; srcbase := ptr(ord4(ScreenBase) + offset); SrcRowBytes := ScreenRowBytes; end else begin offset := left + LongInt(top) * fgRowBytes; srcbase := ptr(ord4(ptr(fgSlotBase)) + offset); SrcRowBytes := fgRowBytes; end; 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 FrameGrabber <> ScionLG3 then VideoRateAveraging := false; 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', cr, str1, ' seconds', cr), StartTicks, FramesToAverage); end; for frame := 0 to FramesToAverage - 1 do begin Show2Values(frame + 1, FramesToAverage); if VideoRateAveraging then BufferReg^ := Frame else begin if FrameGrabber = Scion then GetScionFrame(DisplayPoint) else GetFrame; 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 FrameGrabber <> Scion then UpdateScreen(info^.RoiRect); 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 := LongInt(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), ')', cr, 'max=', long2str(MaxV), ' (', long2str(ActualMax), ')', cr) else str1 := concat('min=', long2str(MinV), cr, 'max=', long2str(MaxV), cr) end else str1 := ''; RealToString((TickCount - StartTicks) / 60.0, 1, 2, str2); ShowFrameRate(concat(Long2str(FramesToAverage), ' frames', cr, str1, str2, ' seconds', cr), StartTicks, FramesToAverage); end; UpdatePicWindow; if AutoSelectAll then KillRoi else ShowRoi; if BlankFieldInfo <> nil then CorrectShading; if ShowIntegratedValues then with info^ do begin DensityCalibrated := true; fit := StraightLine; nCoefficients := 2; coefficient[2] := (MaxV - MinV) / 253.0; coefficient[1] := MinV - coefficient[2]; ZeroClip := false; UpdateTitleBar; if macro then GenerateValues; end end; function GetFGPixel (h, v: integer): integer; var offset: LongInt; p: ptr; begin with Info^ do begin if (h < 0) or (v < 0) or (h >= fgWidth) or (v >= fgHeight) then begin GetFGPixel := WhiteIndex; exit(GetFGPixel); end; offset := LongInt(v) * fgRowBytes + h; if offset >= LongInt(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 (ControlReg^ >= 0) or Button; {Wait for it to complete} end; ScionLG3: 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 SetOffset (var offset, gain: integer); begin if offset < 0 then offset := 0; if offset > 255 then offset := 255; if offset > gain then offset := gain; LG3DacLow := offset; LG3DacHigh := LG3DacLow + (255 - gain); end; procedure SetGain (var offset, gain: integer); begin if gain < 0 then gain := 0; if gain > 255 then gain := 255; if gain < LG3DacLow then gain := LG3DacLow; LG3DacHigh := LG3DacLow + (255 - gain); end; procedure ShowChannel; begin SetDialogItem(VideoControl, FirstChannelID, ord(VideoChannel = 0)); SetDialogItem(VideoControl, FirstChannelID + 1, ord(VideoChannel = 1)); SetDialogItem(VideoControl, FirstChannelID + 2, ord(VideoChannel = 2)); SetDialogItem(VideoControl, FirstChannelID + 3, ord(VideoChannel = 3)); end; procedure UpdateVideoControl; begin if VideoControl <> nil then SetDialogItem(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; SetDialogItem(VideoControl, InvertID, ord(InvertVideo)); SetDialogItem(VideoControl, HighlightID, ord(HighlightSaturatedPixels)); SetDialogItem(VideoControl, OscillatingID, ord(OscillatingMovies)); SetDialogItem(VideoControl, TriggerID, ord(ExternalTrigger)); SetDialogItem(VideoControl, BlindID, ord(BlindMovieCapture)); SetDialogItem(VideoControl, SyncID, ord(SyncMode = SeparateSync)); gain := 255 - (LG3DacHigh - LG3DacLow); ShowOffsetAndGain(LG3DacLow, gain); end; procedure DoVideoControl (item: integer); var i: integer; OutOfRange, WasDigitizing: boolean; offset, gain, inc, count: integer; procedure CheckFrameGrabber; begin if FrameGrabber <> ScionLG3 then begin PutMessage('Programmable offset and gain are only supported on the Scion LG-3.'); exit(DoVideoControl); end; end; procedure SetVideoItem (item, value: integer); begin if VideoControl <> nil then SetDialogItem(VideoControl, item, value); end; begin InitCursor; gain := 255 - (LG3DacHigh - LG3DacLow); 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 = OscillatingID then begin OscillatingMovies := not OscillatingMovies; SetVideoItem(OscillatingID, ord(OscillatingMovies)); end; if item = TriggerID then begin ExternalTrigger := not ExternalTrigger; case FrameGrabber of QuickCapture, ScionLG3: begin WasDigitizing := digitizing; StopDigitizing; if ExternalTrigger and WasDigitizing then StartDigitizing; end; otherwise ExternalTrigger := false; end; SetVideoItem(TriggerID, ord(ExternalTrigger)); end; if item = BlindID then begin BlindMovieCapture := not BlindMovieCapture; SetVideoItem(BlindID, ord(BlindMovieCapture)); end; if item = SyncID then begin if SyncMode <> SeparateSync then SyncMode := SeparateSync else SyncMode := NormalSync; case FrameGrabber of ScionLG3: if digitizing then ResetFrameGrabber; QuickCapture: begin PutMessage('Sync is not under program control on the QuickCapure card.'); SyncMode := NormalSync; macro := false; end; otherwise ; end; SetVideoItem(SyncID, ord(SyncMode = SeparateSync)); end; if (item >= OffsetUpID) and (item <= GainDownID) then begin CheckFrameGrabber; offset := LG3DacLow; 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(LG3DacLow, gain); if Digitizing and (count > 1) then begin DacLowReg^ := LG3DacLow; DacHighReg^ := LG3DacHigh; CaptureAndDisplayFrame; if ContinuousHistogram then begin ShowContinuousHistogram; DrawHistogram end end else wait(5); until not button; end; if item = ResetID then begin CheckFrameGrabber; LG3DacLow := DefaultLG3DacLow; LG3DacHigh := DefaultLG3DacHigh; gain := 255 - (LG3DacHigh - LG3DacLow); ParamText(long2str(LG3DacLow), long2str(gain), '', ''); ShowOffsetAndGain(LG3DacLow, gain); end; if FramesToAverage < 2 then FramesToAverage := 2; if (FrameGrabber = Scion) and (ExternalTrigger or BlindMovieCapture) then begin PutMessage('External triggering and blind movie capture are not supported with the SCION frame grabber card.'); ExternalTrigger := false; BlindMovieCapture := false; end; if FrameGrabber = ScionLG3 then begin DacLowReg^ := LG3DacLow; DacHighReg^ := LG3DacHigh; end; end; end.