如何将Xamarin.android与OpenCV集成
我正在尝试将Xamarin.android与visual Studio中的OpenCV连接。文档非常差。有人能为我提供一些步骤吗?在Xamarin.android上使用OpenCV的方法不止一种: 1使用OpenCV4Android的绑定:OpenCV4Android是使用JNI的OpenCV(C++)for Android(Java)的包装器。通过绑定,我们在Java和C#之间有了一个接口(更多信息见) 它是在中实现的,在那里使用的是OpenCV 3.1.0。 您可以按照安装说明和“减小.dll大小”生成dll并引用它,也可以在Visual Studio解决方案中插入文件夹“/src/OpenCV.Binding”的Visual Studio项目,并将项目引用添加到此新项目 如果您想使用较新版本,可以下载较新版本的OpenCV4Android(opencv SourceForge中名为opencv-version-android-sdk.zip的文件,例如:链接上的OpenCV4Android 4.1.0),并将上一个项目中的文件夹“/src/opencv.Binding/Jars”的内容替换为文件夹“/sdk/native/libs”和提取的OpenCV4Android的“/sdk/native/3rdparty/libs” 这个项目还有一个关键点:它可以简化安装和使用,但我没有使用它,所以我不能说它是否有效 由于此方法是OpenCV4Android的绑定,而不是纯OpenCV,您将使用OpenCV4Android()的文档。同样值得一提的是,这样我们有三层编程语言(C#-Java-C++),因此方法调用会导致性能损失(JNI是一个负担).因此,建议您尽量少打电话如何将Xamarin.android与OpenCV集成,opencv,xamarin.android,Opencv,Xamarin.android,我正在尝试将Xamarin.android与visual Studio中的OpenCV连接。文档非常差。有人能为我提供一些步骤吗?在Xamarin.android上使用OpenCV的方法不止一种: 1使用OpenCV4Android的绑定:OpenCV4Android是使用JNI的OpenCV(C++)for Android(Java)的包装器。通过绑定,我们在Java和C#之间有了一个接口(更多信息见) 它是在中实现的,在那里使用的是OpenCV 3.1.0。 您可以按照安装说明和“减小.dl
<强> 2 < /St>>使用OpenCV C++的包装器:用这种方法,我们将使用C++共享库(.so),并调用它的方法(C)()。 要做到这一点,我们需要编写OpenCV方法的PInvoke,它有很多,这意味着要花很多时间。因此,我们将使用已有的方法
我们有OpenCvSharp,它是OpenCV到.NET的包装,显然工作得很好。问题:它与ARM不兼容,所以不能在智能手机上运行。 然而,一个好的灵魂使它适合在ARM设备上运行: 如何快速使用:在解决方案中插入文件夹“/src/OpenCvSharp”的项目并引用它。将“/src/OpenCvSharp.Android/Native”的内容复制到项目的文件夹“lib”或“libs”。然后将“.so”文件配置为“始终复制”到输出目录,并将其构建操作配置为“AndroidNativeLibrary”(如果您的项目是应用程序)或“嵌入式本机库”(如果您的项目是Android库) 另一种方法是安装NuGet(),这会稍微容易一些,但也需要将“.so”文件复制到“lib”或“libs”并进行配置 这个包装器使用OpenCV 3.2.0。我正在研究一种在这个项目上更新OpenCV版本的方法,但是现在,它可以工作了 这种方法的最大优点是性能(在比较两种实现时,我的应用程序提高了约30%),但一个缺点是没有现成的Android.Bitmap-OpenCV.Mat转换方法。我通过调整OpenCV4Android的转换方法实现了它们:// Method adapted from the original OpenCV convert at https://github.com/opencv/opencv/blob/b39cd06249213220e802bb64260727711d9fc98c/modules/java/generator/src/cpp/utils.cpp
///<summary>
///This function converts an image in the OpenCV Mat representation to the Android Bitmap.
///The input Mat object has to be of the types 'CV_8UC1' (gray-scale), 'CV_8UC3' (RGB) or 'CV_8UC4' (RGBA).
///The output Bitmap object has to be of the same size as the input Mat and of the types 'ARGB_8888' or 'RGB_565'.
///This function throws an exception if the conversion fails.
///</summary>
///<param name="srcImage">srcImage is a valid input Mat object of types 'CV_8UC1', 'CV_8UC3' or 'CV_8UC4'</param>
///<param name="dstImage">dstImage is a valid Bitmap object of the same size as the Mat and of type 'ARGB_8888' or 'RGB_565'</param>
///<param name="needPremultiplyAlpha">premultiplyAlpha is a flag, that determines, whether the Mat needs to be converted to alpha premultiplied format (like Android keeps 'ARGB_8888' bitmaps); the flag is ignored for 'RGB_565' bitmaps.</param>
public static void MatToBitmap(Mat srcImage, Bitmap dstImage, bool needPremultiplyAlpha = false)
{
var bitmapInfo = dstImage.GetBitmapInfo();
var bitmapPixels = dstImage.LockPixels();
if (bitmapInfo.Format != Format.Rgba8888 && bitmapInfo.Format != Format.Rgb565)
throw new Exception("Invalid Bitmap Format: It is of format " + bitmapInfo.Format.ToString() + " and is expected Rgba8888 or Rgb565");
if (srcImage.Dims() != 2)
throw new Exception("The source image has " + srcImage.Dims() + " dimensions, while it is expected 2");
if (srcImage.Cols != bitmapInfo.Width || srcImage.Rows != bitmapInfo.Height)
throw new Exception("The source image and the output Bitmap don't have the same amount of rows and columns");
if (srcImage.Type() != MatType.CV_8UC1 && srcImage.Type() != MatType.CV_8UC3 && srcImage.Type() != MatType.CV_8UC4)
throw new Exception("The source image has the type " + srcImage.Type().ToString() + ", while it is expected CV_8UC1, CV_8UC3 or CV_8UC4");
if (bitmapPixels == null)
throw new Exception("Can't lock the output bitmap");
if (bitmapInfo.Format == Format.Rgba8888)
{
Mat tmp = new Mat((int)bitmapInfo.Height, (int)bitmapInfo.Width, MatType.CV_8UC4, bitmapPixels);
if (srcImage.Type() == MatType.CV_8UC1)
{
Android.Util.Log.Info("MatToBitmap", "CV_8UC1 -> RGBA_8888");
Cv2.CvtColor(srcImage, tmp, ColorConversionCodes.GRAY2RGBA);
}
else if (srcImage.Type() == MatType.CV_8UC3)
{
Android.Util.Log.Info("MatToBitmap", "CV_8UC3 -> RGBA_8888");
Cv2.CvtColor(srcImage, tmp, ColorConversionCodes.RGB2RGBA);
}
else if (srcImage.Type() == MatType.CV_8UC4)
{
Android.Util.Log.Info("MatToBitmap", "CV_8UC4 -> RGBA_8888");
if (needPremultiplyAlpha)
Cv2.CvtColor(srcImage, tmp, ColorConversionCodes.RGBA2mRGBA);
else
srcImage.CopyTo(tmp);
}
}
else
{
// info.format == ANDROID_BITMAP_FORMAT_RGB_565
Mat tmp = new Mat((int)bitmapInfo.Height, (int)bitmapInfo.Width, MatType.CV_8UC2, bitmapPixels);
if (srcImage.Type() == MatType.CV_8UC1)
{
Android.Util.Log.Info("MatToBitmap", "CV_8UC1 -> RGB_565");
Cv2.CvtColor(srcImage, tmp, ColorConversionCodes.GRAY2BGR565);
}
else if (srcImage.Type() == MatType.CV_8UC3)
{
Android.Util.Log.Info("MatToBitmap", "CV_8UC3 -> RGB_565");
Cv2.CvtColor(srcImage, tmp, ColorConversionCodes.RGB2BGR565);
}
else if (srcImage.Type() == MatType.CV_8UC4)
{
Android.Util.Log.Info("MatToBitmap", "CV_8UC4 -> RGB_565");
Cv2.CvtColor(srcImage, tmp, ColorConversionCodes.RGBA2BGR565);
}
}
dstImage.UnlockPixels();
return;
}
// Method adapted from the original OpenCV convert at https://github.com/opencv/opencv/blob/b39cd06249213220e802bb64260727711d9fc98c/modules/java/generator/src/cpp/utils.cpp
///<summary>
///This function converts an Android Bitmap image to the OpenCV Mat.
///'ARGB_8888' and 'RGB_565' input Bitmap formats are supported.
///The output Mat is always created of the same size as the input Bitmap and of the 'CV_8UC4' type,it keeps the image in RGBA format.
///This function throws an exception if the conversion fails.
///</summary>
///<param name="srcImage">srcImage is a valid input Bitmap object of the type 'ARGB_8888' or 'RGB_565'</param>
///<param name="dstImage">dstImage is a valid output Mat object, it will be reallocated if needed, so it may be empty.</param>
///<param name="needUnPremultiplyAlpha">unPremultiplyAlpha is a flag, that determines, whether the bitmap needs to be converted from alpha premultiplied format (like Android keeps 'ARGB_8888' ones) to regular one; this flag is ignored for 'RGB_565' bitmaps.</param>
public static void BitmapToMat(Bitmap srcImage, Mat dstImage, bool needUnPremultiplyAlpha = false)
{
var bitmapInfo = srcImage.GetBitmapInfo();
var bitmapPixels = srcImage.LockPixels();
if (bitmapInfo.Format != Format.Rgba8888 && bitmapInfo.Format != Format.Rgb565)
throw new Exception("Invalid Bitmap Format: It is of format " + bitmapInfo.Format.ToString() + " and is expected Rgba8888 or Rgb565");
if (bitmapPixels == null)
throw new Exception("Can't lock the source bitmap");
dstImage.Create((int)bitmapInfo.Height, (int)bitmapInfo.Width, MatType.CV_8UC4);
if (bitmapInfo.Format == Format.Rgba8888)
{
Android.Util.Log.Info("nBitmapToMat", "RGBA_8888 -> CV_8UC4");
Mat tmp = new Mat((int)bitmapInfo.Height, (int)bitmapInfo.Width, MatType.CV_8UC4, bitmapPixels);
if (needUnPremultiplyAlpha)
Cv2.CvtColor(tmp, dstImage, ColorConversionCodes.mRGBA2RGBA);
else
tmp.CopyTo(dstImage);
}
else
{
// info.format == ANDROID_BITMAP_FORMAT_RGB_565
Android.Util.Log.Info("nBitmapToMat", "RGB_565 -> CV_8UC4");
Mat tmp = new Mat((int)bitmapInfo.Height, (int)bitmapInfo.Width, MatType.CV_8UC2, bitmapPixels);
Cv2.CvtColor(tmp, dstImage, ColorConversionCodes.BGR5652RGBA);
}
srcImage.UnlockPixels();
return;
}
//从原始OpenCV转换而来的方法https://github.com/opencv/opencv/blob/b39cd06249213220e802bb64260727711d9fc98c/modules/java/generator/src/cpp/utils.cpp
///
///此函数用于将OpenCV Mat表示中的图像转换为Android位图。
///输入Mat对象的类型必须为“CV_8UC1”(灰度)、“CV_8UC3”(RGB)或“CV_8UC4”(RGBA)。
///输出位图对象的大小必须与输入Mat相同,并且类型必须为“ARGB_8888”或“RGB_565”。
///如果转换失败,此函数将引发异常。
///
///srcImage是“CV_8UC1”、“CV_8UC3”或“CV_8UC4”类型的有效输入Mat对象
///dstImage是与Mat大小相同且类型为“ARGB_8888”或“RGB_565”的有效位图对象
///premultiplyAlpha是一个标志,用于确定Mat是否需要转换为alpha预乘格式(如Android保留“ARGB_8888”位图);对于“RGB_565”位图,该标志将被忽略。
公共静态void MatToBitmap(Mat srcImage、位图dstmimage、bool needPremultiplyAlpha=false)
{
var bitmapInfo=dstImage.GetBitmapInfo();
var bitmapPixels=dstImage.LockPixels();
if(bitmapInfo.Format!=Format.rgba888&&bitmapInfo.Format!=Format.Rgb565)
抛出新异常(“无效位图格式:格式为“+bitmapInfo.Format.ToString()+”,应为RGBA888或Rgb565”);
如果(srcImage.Dims()!=2)
抛出新异常(“源映像具有“+srcImage.Dims()+”维度,而预期为2”);
if(srcImage.Cols!=bitmapInfo.Width | | srcImage.Rows!=bitmapInfo.Height)
抛出新异常(“源图像和输出位图的行数和列数不相同”);
if(srcImage.Type()!=MatType.CV_8UC1和&srcImage.Type()!=MatType.CV_8UC3和&srcImage.Type()!=MatType.CV_8UC4)
抛出新异常(“源映像的类型为“+srcImage.type().ToString()+”,而预期为CV_8UC1、CV_8UC3或CV_8UC4”);
如果(bitmapPixels==null)
抛出新异常(“无法锁定输出位图”);
if(bitmapInfo.Format==Format.Rgba8888)
{
Mat tmp=新Mat((int)bitmapInfo.Height,(int)bitmapInfo.Width,MatType.CV_8UC4,bitmapPixels);
if(srcImage.Type()==MatType.CV_8UC1)
{
Android.Util.Log.Info(“MatToBitmap”、“CV_8UC1->RGBA_8888”);
Cv2.CvtColor(srcImage、tmp、ColorConversionCodes.GRAY2RGBA);
}
else if(srcImage.Type()==MatType.CV_8UC3)
{
Android.Util.Log.Info(“MatToBitmap”、“CV_8UC3->RGBA_8888”);
Cv2.CvtColor(srcImage、tmp、ColorConversionCodes.RGB2RGBA);
}
else if(srcImage.Type()==Mat