I would like help with using OpenCV for Android (Git: https://github.com/CarlosHe/OpenCV-Android-Firemonkey), Contours example.
I don't know how can I use contours list (JList)? I would like to loop through all the contours and output each one in a Memo1.
Here's the code (returns an error "Access violation at address C8E40F40, access address 47F027B5"):
var
LSrcMat: JMat;
LDstMat: JMat;
LHierarchyMat: JMat;
LJBitmap: JBitmap;
LThreshold: Double;
LContoursList: JList;
trash, maxval: Double;
i, type_: Integer;
begin
FOpenCVInProgress := True;
try
trash := StrToFloat(edtTrash.Text);
maxval := StrToFloat(edtMaxVal.Text);
type_ := StrToInt(edtType.Text);
LSrcMat := TJMat.JavaClass.init;
LDstMat := TJMat.JavaClass.init;
LHierarchyMat:= TJMat.JavaClass.init;
LContoursList:= JList(TJArrayList.JavaClass.init(0));
LJBitmap := TJBitmap.JavaClass.createBitmap(Trunc(FCamBitmap.Width), Trunc(FCamBitmap.Height), TJBitmap_Config.JavaClass.ARGB_8888);
TJandroid_Utils.JavaClass.bitmapToMat(BitmapToJBitmap(FCamBitmap), LSrcMat);
TJImgproc.JavaClass.cvtColor(LSrcMat, LDstMat, TJImgproc.JavaClass.COLOR_RGB2GRAY); // change picture to gray
LThreshold := TJImgproc.JavaClass.threshold(LDstMat, LDstMat, trash, maxval, type_); // classify pixels into two different groups
TJImgproc.JavaClass.Canny(LDstMat, LDstMat, LThreshold, LThreshold * 2); // Edge detection
TJImgproc.JavaClass.findContours(LDstMat, LContoursList, LHierarchyMat, TJImgproc.JavaClass.RETR_EXTERNAL, TJImgproc.JavaClass.CHAIN_APPROX_SIMPLE ); // find edge
TJImgproc.JavaClass.cvtColor(LDstMat, LDstMat, TJImgproc.JavaClass.COLOR_GRAY2RGB); // change picture to color
TJImgproc.JavaClass.drawContours(LDstMat, LContoursList, -1, TJScalar.JavaClass.init(255,255,0) , 3); // draw edge
TJandroid_Utils.JavaClass.MatToBitmap(LDstMat, LJBitmap);
FCamBitmap := JBitmapToBitmap(LJBitmap);
// returns an error "Access violation at address C8E40F40, access address 47F027B5"
For i := 0 to LContoursList.size - 1 do
begin
Memo1.Lines.Add(JStringToString((LContoursList.get(i).toString)));
end;
You need JList
instance to pass to findContours
, but to get the JList
instance you cannot typecast it from JArrayList
the way you did.
In Delphi JList
and JArrayList
belong to different interface hierarchies and cannot be directly typecasted. The problem is in following line
LContoursList:= JList(TJArrayList.JavaClass.init(0));
Above forced typecast will convert two incompatible interfaces without giving you any warnings and then when you try to use the LContoursList
it will crash.
If you write the above typecast in safe manner:
LContoursList := TJArrayList.Create as JList;
you will get runtime exception, telling you that JArrayList
does not support JList
interface.
Exception class EIntfCastError with message 'Interface not supported'.
Because underlying Java class supports both interfaces, you can do the typecast differently and expose underlying Java object as JList
using following code:
var
LArr: JArrayList;
LContoursList: JList;
LArr := TJArrayList.Create;
LContoursList:= TJList.Wrap(LArr);
Note: In Delphi if you want to invoke default Java constructor you can merely say TJXXX.Create
instead TJXXX.JavaClass.init
. In your case calling Java constructor with 0 capacity does not make much difference than using default constructor.
Note: Original FMX example run is in background thread. Since you haven't shown how you are running your example, if you are using background thread, you will need to make sure that you synchronize any usage of GUI controls with the main thread.