Delphi-OpenCV/source/component/ocv.comp.View.pas
Laentir Valetov f2982fb3f3 Delphi 10 Seattle
Signed-off-by: Laentir Valetov <laex@bk.ru>
2015-09-19 22:49:45 +03:00

477 lines
12 KiB
ObjectPascal

// ****************************************************************
// Delphi-OpenCV Demo
// Copyright (C) 2013 Project Delphi-OpenCV
// ****************************************************************
// Contributor:
// Laentir Valetov
// email:laex@bk.ru
// ****************************************************************
// You may retrieve the latest version of this file at the GitHub,
// located at git://github.com/Laex/Delphi-OpenCV.git
// ****************************************************************
// The contents of this file are used with permission, subject to
// the Mozilla Public License Version 1.1 (the "License"); you may
// not use this file except in compliance with the License. You may
// obtain a copy of the License at
// http://www.mozilla.org/MPL/MPL-1_1Final.html
//
// Software distributed under the License is distributed on an
// "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
// implied. See the License for the specific language governing
// rights and limitations under the License.
// ****************************************************************
{$IFNDEF CLR}
{$I OpenCV.inc}
unit ocv.comp.View;
{$ENDIF}
interface
uses
{$IFDEF HAS_UNITSCOPE}
{$IFDEF MSWINDOWS}
Winapi.Windows, Winapi.Messages,
{$ENDIF MSWINDOWS}
System.SysUtils,
System.Classes,
Vcl.Controls,
Vcl.Graphics,
System.SyncObjs,
{$ELSE}
{$IFDEF MSWINDOWS}
Windows,
{$ENDIF MSWINDOWS}
{$IFNDEF FPC}Messages, {$ENDIF FPC}
SysUtils,
Classes,
Controls,
Graphics,
SyncObjs,
{$ENDIF}
ocv.comp.Types,
ocv.core.types_c;
type
TocvViewFrames = class(TOwnedCollection)
end;
TocvPersistentRect = class(TPersistent)
private
FRect: TRect;
FOnChange: TNotifyEvent;
function GetRect: TRect;
procedure SetRect(const Value: TRect);
procedure SetRectBottom(const Value: integer);
procedure SetRectLeft(const Value: integer);
procedure SetRectRight(const Value: integer);
procedure SetRectTop(const Value: integer);
protected
procedure AssignTo(Dest: TPersistent); override;
public
property AsRect: TRect read GetRect Write SetRect;
constructor Create; virtual;
published
property Left: integer read FRect.Left write SetRectLeft;
property Top: integer read FRect.Top write SetRectTop;
property Right: integer read FRect.Right write SetRectRight;
property Bottom: integer read FRect.Bottom write SetRectBottom;
property OnChange: TNotifyEvent read FOnChange write FOnChange;
end;
TocvViewFrame = class(TCollectionItem, IocvDataReceiver)
private
FocvVideoSource: IocvDataSource;
FImage: IocvImage;
FLock: TCriticalSection;
FDrawRect: TocvPersistentRect;
FEnabled: Boolean;
procedure SetOpenCVVideoSource(const Value: IocvDataSource);
function GetImage: IocvImage;
function Lock: Boolean;
procedure Unlock;
protected
{ IInterface }
function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
function _AddRef: integer; stdcall;
function _Release: integer; stdcall;
procedure TakeImage(const IplImage: IocvImage);
procedure SetVideoSource(const Value: TObject);
public
constructor Create(Collection: TCollection); override;
destructor Destroy; override;
property Image: IocvImage read GetImage;
published
property VideoSource: IocvDataSource Read FocvVideoSource write SetOpenCVVideoSource;
property DrawRect: TocvPersistentRect read FDrawRect write FDrawRect;
property Enabled: Boolean read FEnabled Write FEnabled default false;
end;
TocvView = class(TWinControl, IocvDataReceiver)
private
FocvVideoSource: IocvDataSource;
FImage: IocvImage;
FOnAfterPaint: TOnOcvAfterViewPaint;
FOnBeforePaint: TOnOcvNotify;
FCanvas: TCanvas;
FStretch: Boolean;
FProportional: Boolean;
FCenter: Boolean;
FFrames: TocvViewFrames;
procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND;
procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
procedure SetOpenCVVideoSource(const Value: IocvDataSource);
function isSourceEnabled: Boolean;
function PaintRect: TRect;
protected
procedure SetVideoSource(const Value: TObject);
procedure TakeImage(const IplImage: IocvImage);
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure DrawImage(const IplImage: IocvImage);
property Canvas: TCanvas read FCanvas;
property Image: IocvImage read FImage;
published
property VideoSource: IocvDataSource Read FocvVideoSource write SetOpenCVVideoSource;
property Proportional: Boolean read FProportional write FProportional default false;
property Stretch: Boolean read FStretch write FStretch default True;
property Center: Boolean read FCenter write FCenter default false;
property Frames: TocvViewFrames Read FFrames Write FFrames;
property Align;
property OnAfterPaint: TOnOcvAfterViewPaint read FOnAfterPaint write FOnAfterPaint;
property OnBeforePaint: TOnOcvNotify read FOnBeforePaint write FOnBeforePaint;
property OnEnter;
property OnExit;
property OnKeyDown;
property OnKeyPress;
property OnKeyUp;
property OnMouseDown;
property OnMouseUp;
property OnMouseMove;
property OnMouseEnter;
property OnMouseLeave;
property OnMouseWheel;
property OnMouseWheelUp;
property OnMouseWheelDown;
end;
implementation
uses
ocv.utils;
{ TOpenCVView }
constructor TocvView.Create(AOwner: TComponent);
begin
inherited;
FCanvas := TControlCanvas.Create;
TControlCanvas(FCanvas).Control := Self;
Stretch := True;
Proportional := false;
Center := false;
FFrames := TocvViewFrames.Create(Self, TocvViewFrame);
end;
destructor TocvView.Destroy;
begin
if Assigned(FocvVideoSource) then
FocvVideoSource.RemoveReceiver(Self);
FCanvas.Free;
FFrames.Free;
inherited;
end;
procedure TocvView.SetOpenCVVideoSource(const Value: IocvDataSource);
begin
if FocvVideoSource <> Value then
begin
if Assigned(FocvVideoSource) then
FocvVideoSource.RemoveReceiver(Self);
FocvVideoSource := Value;
if Assigned(FocvVideoSource) then
FocvVideoSource.AddReceiver(Self);
end;
end;
procedure TocvView.SetVideoSource(const Value: TObject);
begin
VideoSource := Value as TocvDataSource;
end;
procedure TocvView.DrawImage(const IplImage: IocvImage);
begin
FImage := IplImage;
Invalidate;
end;
procedure TocvView.TakeImage(const IplImage: IocvImage);
begin
if not(csDestroying in ComponentState) then
DrawImage(IplImage);
end;
function TocvView.PaintRect: TRect;
var
ViewWidth, ViewHeight, CliWidth, CliHeight: integer;
AspectRatio: Double;
begin
ViewWidth := FImage.IpImage^.Width;
ViewHeight := FImage.IpImage^.Height;
CliWidth := ClientWidth;
CliHeight := ClientHeight;
if (Proportional and ((ViewWidth > CliWidth) or (ViewHeight > CliHeight))) or Stretch then
begin
if Proportional and (ViewWidth > 0) and (ViewHeight > 0) then
begin
AspectRatio := ViewWidth / ViewHeight;
if ViewWidth > ViewHeight then
begin
ViewWidth := CliWidth;
ViewHeight := Trunc(CliWidth / AspectRatio);
if ViewHeight > CliHeight then
begin
ViewHeight := CliHeight;
ViewWidth := Trunc(CliHeight * AspectRatio);
end;
end
else
begin
ViewHeight := CliHeight;
ViewWidth := Trunc(CliHeight * AspectRatio);
if ViewWidth > CliWidth then
begin
ViewWidth := CliWidth;
ViewHeight := Trunc(CliWidth / AspectRatio);
end;
end;
end
else
begin
ViewWidth := CliWidth;
ViewHeight := CliHeight;
end;
end;
with Result do
begin
Left := 0;
Top := 0;
Right := ViewWidth;
Bottom := ViewHeight;
end;
if Center then
OffsetRect(Result, (CliWidth - ViewWidth) div 2, (CliHeight - ViewHeight) div 2);
end;
function TocvView.isSourceEnabled: Boolean;
begin
Result := (Assigned(VideoSource) and (VideoSource.Enabled)) or Assigned(FImage);
end;
procedure TocvView.WMEraseBkgnd(var Message: TWMEraseBkgnd);
begin
if (csDesigning in ComponentState) or (not isSourceEnabled) then
inherited;
end;
procedure TocvView.WMPaint(var Message: TWMPaint);
Var
DC: HDC;
lpPaint: TPaintStruct;
i: integer;
begin
if (csDesigning in ComponentState) or (not isSourceEnabled) then
inherited
else
begin
if Assigned(FImage) then
begin
Canvas.Lock;
DC := BeginPaint(Handle, lpPaint);
try
Canvas.Handle := DC;
try
if Assigned(OnBeforePaint) then
OnBeforePaint(Self, FImage);
if ipDraw(DC, FImage.IpImage, PaintRect) then
begin
for i := 0 to FFrames.Count - 1 do
With (FFrames.Items[i] as TocvViewFrame) do
{$IFDEF DELPHIXE2_UP}
if Enabled and (not DrawRect.AsRect.isEmpty) and Assigned(Image) then
{$ELSE}
if Enabled and IsRectEmpty(DrawRect.AsRect) and Assigned(Image) then
{$ENDIF}
ipDraw(DC, Image.IpImage, DrawRect.AsRect);
if Assigned(OnAfterPaint) then
OnAfterPaint(Self, FImage);
end;
finally
Canvas.Handle := 0;
end;
finally
EndPaint(Handle, lpPaint);
Canvas.Unlock;
end;
end
else
DefaultHandler(Message);
end;
end;
{ TocvViewFrame }
constructor TocvViewFrame.Create(Collection: TCollection);
begin
inherited;
FLock := TCriticalSection.Create;
FDrawRect := TocvPersistentRect.Create;
{$IFDEF DELPHIXE2_UP}
FDrawRect.FRect.Width := 50;
FDrawRect.FRect.Height := 50;
{$ENDIF}
FEnabled := false;
end;
destructor TocvViewFrame.Destroy;
begin
FImage := Nil;
FLock.Free;
FDrawRect.Free;
inherited;
end;
function TocvViewFrame.GetImage: IocvImage;
begin
FLock.Enter;
try
Result := FImage;
finally
Unlock;
end;
end;
function TocvViewFrame.Lock: Boolean;
begin
Result := FLock.TryEnter;
end;
function TocvViewFrame.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
if GetInterface(IID, Obj) then
Result := 0
else
Result := E_NOINTERFACE;
end;
procedure TocvViewFrame.SetOpenCVVideoSource(const Value: IocvDataSource);
begin
if FocvVideoSource <> Value then
begin
if Assigned(FocvVideoSource) then
FocvVideoSource.RemoveReceiver(Self);
FocvVideoSource := Value;
if Assigned(FocvVideoSource) then
FocvVideoSource.AddReceiver(Self);
end;
end;
procedure TocvViewFrame.SetVideoSource(const Value: TObject);
begin
VideoSource := Value as TocvDataSource;
end;
procedure TocvViewFrame.TakeImage(const IplImage: IocvImage);
begin
if Lock then
try
FImage := IplImage;
finally
Unlock;
end;
end;
procedure TocvViewFrame.Unlock;
begin
FLock.Leave;
end;
function TocvViewFrame._AddRef: integer;
begin
Result := -1;
end;
function TocvViewFrame._Release: integer;
begin
Result := -1;
end;
{ TPersistentRect }
procedure TocvPersistentRect.AssignTo(Dest: TPersistent);
begin
if Dest is TocvPersistentRect then
with TocvPersistentRect(Dest) do
begin
AsRect := Self.AsRect;
end
else
inherited AssignTo(Dest);
end;
constructor TocvPersistentRect.Create;
begin
inherited;
FOnChange := nil;
end;
function TocvPersistentRect.GetRect: TRect;
begin
Result := FRect;
end;
procedure TocvPersistentRect.SetRect(const Value: TRect);
begin
FRect.Left := Value.Left;
FRect.Top := Value.Top;
FRect.Right := Value.Right;
FRect.Bottom := Value.Bottom;
if Assigned(FOnChange) then
FOnChange(Self);
end;
procedure TocvPersistentRect.SetRectBottom(const Value: integer);
begin
FRect.Bottom := Value;
if Assigned(FOnChange) then
FOnChange(Self);
end;
procedure TocvPersistentRect.SetRectLeft(const Value: integer);
begin
FRect.Left := Value;
if Assigned(FOnChange) then
FOnChange(Self);
end;
procedure TocvPersistentRect.SetRectRight(const Value: integer);
begin
FRect.Right := Value;
if Assigned(FOnChange) then
FOnChange(Self);
end;
procedure TocvPersistentRect.SetRectTop(const Value: integer);
begin
FRect.Top := Value;
if Assigned(FOnChange) then
FOnChange(Self);
end;
end.