点击蓝字关注我们
以前我们整体的介绍了利用SurfaceView调用系统的Camera显示图像,并且通过NDK OpenCV的方式进行图像处理,今天这篇我们就是来介绍一下,在SurfaceView中点击显示图像中的区域进行定位,方便我们手动调整图像的。最后完整的代码会在整个系列都做完后上传到GItHub中。
视频演示
视频说明
通过SurfaceView中点击事件其实相对来说很简单,只要重写onTouchEvent事件就可以。
在参数event里面的getRawX和getRawY就可以获取到点击的坐标点。但是看过以前SurfaceView调用camera的朋友应该记得,我们还除了要旋转相机角度,还要对画布的大小对显示的图像进行缩放,所以本章的重点是解决我们点击的图像怎么对应到上面视频中显示出来的红点位置。
实现思路
点击时进行计算处理
在onTouchevent事件中获取到屏幕的宽和高。
通到getRawx和getRawY的坐标计算出在总屏幕中位置比例。
在调用NDK时通过用生成的图片的宽高乘比例计算出点击的位置坐标(会有一点小的误差,但不影响)。
NDK实现中对坐标进行画圈显示出来。
代码实现
程序框架我们就不在重新搭建了,用的还是《Android利用SurfaceView显示Camera图像爬坑记(六) -- 用OpenCV进行Canny边缘检测》那个Demo。
接下来直接开始
01
VaccaeSurfaceView修改
首先我们先定义几个变量,用于计算我们的坐标点,如图:
然后在VaccaeSurfaceView中直接重写onTouchEvent事件,如下:
我们先通过定义DisplayMetrics来获取到屏幕的分辨率,然后要根据点击的位置横坐标除屏幕长度,纵坐标除屏幕高度计算出对应的比例。
然后在原来的图片处理方法nv21ToBitmap
中,根据图像大小重新计算图片中的坐标x,y的点
nv21ToBitmap方法:
private Bitmap nv21ToBitmap(byte[] nv21, int width, int height) {
Bitmap bitmap=null;
try {
YuvImage image=new YuvImage(nv21, ImageFormat.NV21, width, height, null);
ByteArrayOutputStream stream=new ByteArrayOutputStream();
image.compressToJpeg(new Rect(0, 0, width, height), 80, stream);
//将rawImage转换成bitmap
BitmapFactory.Options options=new BitmapFactory.Options();
options.inPreferredConfig=Bitmap.Config.ARGB_8888;
bitmap=BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size(), options);
//加入图像旋转
Matrix m=new Matrix();
m.postRotate(rotatedegree);
bitmap=Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(),
m, true);
//调用JNI方法处理图像
if (istouch) {
touchx=(int) (bitmap.getWidth() * touchxscale);
touchy=(int) (bitmap.getHeight() * touchyscale);
bitmap=VaccaeOpenCVJNI.getCameraframetouchbitbmp(bitmap, touchx, touchy);
}
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}
02
JNI方法实现
我们在VaccaeOpenCVJNI中加入一个新的native方法
然后通过ALT+Enter直接在我们的native-lib.cpp里面自动生成对应的方法,主要就是生成了Mat图像后加入刚才的点坐标进行画半径50的圆并填充。
完整的实现代码
extern "C"
JNIEXPORT jobject JNICALL
Java_dem_vac_surfaceviewdemo_VaccaeOpenCVJNI_getCameraframetouchbitbmp(JNIEnv *env, jclass clazz,
jobject bmp, jint touchx,
jint touchy) {
AndroidBitmapInfo bitmapInfo;
void *pixelscolor;
int ret;
//获取图像信息,如果返回值小于0就是执行失败
if ((ret = AndroidBitmap_getInfo(env, bmp, &bitmapInfo)) < 0) {
LOGI("AndroidBitmap_getInfo failed! error-%d", ret);
return NULL;
}
//判断图像类型是不是RGBA_8888类型
if (bitmapInfo.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
LOGI("BitmapInfoFormat error");
return NULL;
}
//获取图像像素值
if ((ret = AndroidBitmap_lockPixels(env, bmp, &pixelscolor)) < 0) {
LOGI("AndroidBitmap_lockPixels() failed ! error=%d", ret);
return NULL;
}
//生成源图像
cv::Mat src(bitmapInfo.height, bitmapInfo.width, CV_8UC4, pixelscolor);
//点击的点
cv::Point point(touchx, touchy);
cv::circle(src, point, 50, cv::Scalar(255, 0, 0), -1);
//获取原图片的参数
jclass java_bitmap_class = (jclass) env->FindClass("android/graphics/Bitmap");
jmethodID mid = env->GetMethodID(java_bitmap_class, "getConfig",
"()Landroid/graphics/Bitmap$Config;");
jobject bitmap_config = env->CallObjectMethod(bmp, mid);
//将SRC转换为图片
jobject _bitmap = mat2bitmap(env, src, false, bitmap_config);
AndroidBitmap_unlockPixels(env, bmp);
return _bitmap;
}
这样我们的SurfaceView中点击效果在OpenCV中就实现了,下图就是视频中的点击效果显示。
-END-
Vaccae的往期经典
OpenCV
《OpenCV4Android NDK方式进行Canny边缘检测》
《OpenCV4Android NDK方式TesserartOCR实时进行识别》
《OpenCV4Android NDK级联方式实时进行人脸检测》
《OpenCV4Android NDK背景消除建模(新Demo附源码)》
Android
《Android利用SurfaceView结合科大讯飞修改语音实别UI》
《Android关于语音识别的功能实现分析(一)---结构化思维》
《Android关于语音识别的功能实现分析(二)---语义解析》
《Android中RecyclerView嵌套RecyclerView》
.Net C#
《C#开源跨平台机器学习框架ML.NET----二元分类情绪分析》
《C#开源跨平台机器学习框架ML.NET----结合SqlSugar进行多类分类》
数据库及其它
《SQL Server中With As的介绍与应用(三)--递归的实战应用》
《Oracle利用row_number()over()方式解决插入数据时重复键的问题》
请扫码
给个关注
微卡智享