先下载delphi opencv套件: https://github.com/Laex/Delphi-OpenCV
打开opencv_classes工程, 增加如下 两个函数导出,用于mat->IplImage, IplImage->mat的转换, 因为delphi opencv这个套件里面的ocvView显示用的是IplImage。
ICLASS_API IplImage __stdcall ImageFromMat(Mat* mat){
IplImage lvRet=IplImage(*mat);
return lvRet;
}
ICLASS_API IplImage* __stdcall CloneImageFromMat(Mat* mat){
IplImage* lvRet= cvCloneImage(&IplImage(*mat));
return lvRet;
}
这两个函数分别是从Mat转出IplImage和从Mat转出一个IplImage副本, 两者的区别在于, 副本是需要手动销毁的。
再重新编译。
在delphi里面开一个unit, 加上这两个函数的导入:
/// <summary>
/// 从MAT转换一份IplImage过来, 使用后无需销毁
/// </summary>
function ImageFromMat(const mat: TOpenCVClass): TIplImage; stdcall;
external opencv_classes_lib name '_ImageFromMat@4';
/// <summary>
/// 从MAT复制一份IplImage过来, 使用后需要手动cvReleaseImage销毁。
/// </summary>
function CloneImageFromMat(const mat: TOpenCVClass): pIplImage; stdcall;
external opencv_classes_lib name '_CloneImageFromMat@4';
开一个project, 新建一个form, form data如下:
object Form1: TForm1
Left = 0
Top = 0
Caption = 'Form1'
ClientHeight = 314
ClientWidth = 536
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -13
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 120
TextHeight = 16
object Button1: TButton
Left = 416
Top = 25
Width = 75
Height = 25
Caption = 'Button1'
TabOrder = 0
OnClick = Button1Click
end
object ocvView1: TocvView
Left = 8
Top = 16
Width = 385
Height = 241
Frames = <>
end
object Button2: TButton
Left = 416
Top = 56
Width = 75
Height = 25
Caption = 'Button2'
TabOrder = 2
OnClick = Button2Click
end
object Button3: TButton
Left = 416
Top = 96
Width = 75
Height = 25
Caption = 'Button3'
TabOrder = 3
OnClick = Button3Click
end
object Button4: TButton
Left = 416
Top = 136
Width = 75
Height = 25
Caption = 'Button4'
TabOrder = 4
OnClick = Button4Click
end
end
对应的代码:
unit UMainForm;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, GR32_Image,
ocv.highgui_c,
ocv.core_c,
ocv.core.types_c,
ocv.comp.types,
ocv.imgproc_c,
ocv.cls.imgproc, uSafeClass,
ocv.cls.highgui, ocv.cls.core,
ocv.imgproc.types_c, Vcl.StdCtrls, ocv.comp.View, Vcl.ExtCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
ocvView1: TocvView;
Button2: TButton;
Button3: TButton;
Button4: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses uCvImgObj;
procedure TForm1.Button1Click(Sender: TObject);
var
lvV:IocvImage;
begin
lvV:=TocvImage.Create(cvLoadImage('resources\1.jpg')) as IocvImage;
ocvView1.DrawImage(lvV);
end;
procedure TForm1.Button2Click(Sender: TObject);
var lvMat:IMat;
lvCvImgObj:ICvImg;
lvV:IocvImage;
lvP:pIplImage;
lvTmp:TIplImage;
begin
//lvMat会自动释放
lvMat:=imread('resources\1.jpg');
lvTmp:=ImageFromMat(lvMat._InternalData);
//lvP也会自动释放,因为它们共享图像矩阵,这些内存由mat管理了。
lvP:=@lvTmp;
lvV:=TocvImageEx.CreateClone(lvP) as IocvImage; //clone一份希望IocvImage用,然后TocvImageEx销毁的时候自己销毁它
ocvView1.DrawImage(lvV); //因为ocvView有一份独立的IplImage副本,所以能在wmpaint的时候正常显示图像
end;
procedure TForm1.Button3Click(Sender: TObject);
var lvMat:IMat;
lvCvImgObj:ICvImg;
lvV:IocvImage;
lvP:pIplImage;
lvTmp:TIplImage;
begin
//lvMat会自动释放
lvMat:=imread('resources\1.jpg');
lvTmp:=ImageFromMat(lvMat._InternalData);
//lvP也会自动释放,因为它们共享图像矩阵,这些内存由mat管理了。
lvP:=@lvTmp;
//cvShowImage('aaa',lvP); //正常显示
lvV:=TocvImageEx.Create(lvP,rtNone) as IocvImage; //不能用这个,因为TocvImage销毁的时候会自动调用cvReleaseImage销毁IplImage对象,会引起AV,因为这个IplImage所对应的不需要销毁
ocvView1.DrawImage(lvV); //因为ocvView能够显示图像是在wmpaint的时候不断刷新图像,而这时候lvP指向的图像内存早就被mat释放掉了,所以看不到图像
end;
procedure TForm1.Button4Click(Sender: TObject);
var lvMat:IMat;
lvCvImgObj:ICvImg;
lvV:IocvImage;
begin
//lvMat会自动释放
lvMat:=imread('resources\1.jpg');
//lvP从Mat复制一份IplImage过来,使用后需要自己销毁
lvV:=TocvImageEx.Create(CloneImageFromMat(lvMat._InternalData),rtAll) as IocvImage; //TocvImageEx销毁的时候自己销毁它
ocvView1.DrawImage(lvV); //因为ocvView有一份独立的IplImage副本,所以能在wmpaint的时候正常显示图像
end;
end.
其中, button1Click显示了怎么通用从文件读入图像并显示
button2click演示了通过dll调用,从mat转出IplImage并用iocvImage的createClone方式制作副本显示到ocvView1上
button3click演示了为什么不能正常显示图像的原因, 但lvTmp在这个过程中是能正常使用的, 比如用途图像处理或图像保存等。
button4click演示了通过dll调用从mat转出一个IplImage副本,并用ocvView1显示出来。