在Delphi中使用Android版OpenCV操作JList时遇访问违例求助
问题解决:Android OpenCV轮廓遍历访问冲突错误
错误根源
- List初始化方式错误:手动初始化固定容量的ArrayList,OpenCV的
findContours需要接收空的、可动态扩容的List对象,强制转换为JList也可能导致类型不匹配。 - 轮廓元素类型处理错误:
LContoursList中的每个元素是JMatOfPoint类型,直接调用toString()无法正确获取信息,甚至引发内存访问异常。 - 未正确释放资源:创建的Mat、Bitmap等对象未手动释放,可能导致内存溢出引发访问冲突。
修复后的代码
var LSrcMat: JMat; LDstMat: JMat; LHierarchyMat: JMat; LJBitmap: JBitmap; LThreshold: Double; LContoursList: TJArrayList; // 改用TJArrayList而非JList trash, maxval: Double; i, type_: Integer; LContour: JMatOfPoint; LPoints: TJavaArray<Integer>; begin FOpenCVInProgress := True; LContoursList := TJArrayList.JavaClass.init; // 初始化空的ArrayList 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; LJBitmap := TJBitmap.JavaClass.createBitmap(Trunc(FCamBitmap.Width), Trunc(FCamBitmap.Height), TJBitmap_Config.JavaClass.ARGB_8888); try TJandroid_Utils.JavaClass.bitmapToMat(BitmapToJBitmap(FCamBitmap), LSrcMat); TJImgproc.JavaClass.cvtColor(LSrcMat, LDstMat, TJImgproc.JavaClass.COLOR_RGB2GRAY); LThreshold := TJImgproc.JavaClass.threshold(LDstMat, LDstMat, trash, maxval, type_); TJImgproc.JavaClass.Canny(LDstMat, LDstMat, LThreshold, LThreshold * 2); // 传入正确的ArrayList给findContours TJImgproc.JavaClass.findContours(LDstMat, LContoursList, LHierarchyMat, TJImgproc.JavaClass.RETR_EXTERNAL, TJImgproc.JavaClass.CHAIN_APPROX_SIMPLE ); TJImgproc.JavaClass.cvtColor(LDstMat, LDstMat, TJImgproc.JavaClass.COLOR_GRAY2RGB); TJImgproc.JavaClass.drawContours(LDstMat, LContoursList, -1, TJScalar.JavaClass.init(255,255,0) , 3); TJandroid_Utils.JavaClass.MatToBitmap(LDstMat, LJBitmap); FCamBitmap := JBitmapToBitmap(LJBitmap); // 正确遍历轮廓列表 Memo1.Lines.Clear; for i := 0 to LContoursList.size - 1 do begin // 将List元素转换为MatOfPoint LContour := JMatOfPoint(LContoursList.get(i)); // 获取轮廓的点数据数组 LPoints := LContour.toArray; try Memo1.Lines.Add(Format('轮廓%d:包含%d个点', [i, LPoints.length div 2])); // 可选:输出前几个点的坐标 if LPoints.length >= 2 then Memo1.Lines.Add(Format('第一个点坐标:(%d, %d)', [LPoints.Items[0], LPoints.Items[1]])); finally LPoints.free; // 释放Java数组资源 end; LContour.release; // 释放轮廓Mat资源 end; finally // 释放所有Mat资源 LSrcMat.release; LDstMat.release; LHierarchyMat.release; LJBitmap.recycle; // 释放Bitmap资源 end; finally LContoursList.clear; LContoursList.free; FOpenCVInProgress := False; end; end;
关键修复点
- List类型修正:改用
TJArrayList而非JList,直接初始化空列表,避免类型转换和容量限制问题。 - 轮廓元素处理:明确将列表元素转换为
JMatOfPoint,通过toArray()获取点数据,避免直接调用toString()导致的异常。 - 资源释放:添加
try...finally块释放所有Mat、Bitmap和Java数组资源,防止内存泄漏引发访问冲突。 - 遍历逻辑优化:格式化输出轮廓的点数量和坐标,替代无意义的toString输出。
内容的提问来源于stack exchange,提问作者sax
相关产品推荐
相关产品推荐

