简介
很显然,就是继续在之前的基础上添加着新功能。
物体跟踪
原理介绍
主要使用的opencv集成的函数:calcOpticalFlowPyrLK。
具体可以参考这篇文档:opencv实现跟踪鼠标选取的目标:http://blog.csdn.net/u011630458/article/details/45950319
具体代码
1、在setting中,加入了物体跟踪的选项。同时加入对应操作函数。
firstListView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
..............
}else if(arg2 == 2){
initmyobjectTrackingPopupWindowView();
}
..............
}
}
private void initmyobjectTrackingPopupWindowView() {
myobjectTrackingListView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,long arg3) {
if(arg2==0){
myVariable.myobjectTracking = 1;
myVariable.s.height= myVariable.screenHeight;
myVariable.s.width= myVariable.screenWidth * 16 / 9;
resolutionChange();
Toast toast=Toast.makeText(getApplicationContext(), "", Toast.LENGTH_SHORT);
ImageView iv = new ImageView(getApplicationContext());
iv.setImageDrawable(getResources().getDrawable(R.drawable.toast_show_object_addr));
toast.setView(iv);
toast.show();
}else if(arg2 == 1){
myVariable.myobjectTracking = 0;
myVariable.myobjectTracking_x = 0;
myVariable.myobjectTracking_y = 0;
}
........
});
}
}
物体跟踪操作也是一个opupWindow,布局和setting一样。进入该功能之后,可以选择是或者否来使能和关闭该功能,通过myobjectTracking来
表示功能是否使能,myobjectTracking_x,和myobjectTracking_y 来表示被跟踪对象的中心点坐标。需要注意下,为了保证点击touch操作和预览
图像坐标对应起来,所以在打开物体跟踪之后,会强行重新设置一遍camera的分辨率。
接着给预览界面注册了Touch操作,当被按下之后,通过timerAdd来判断是否是被长按了,如果是被长按,则表示当前被长按的中心左边就是需要被
跟踪的位置,更新坐标位置到myobjectTracking_x、myobjectTracking_y 。
public boolean onTouch(View arg0, MotionEvent arg1) {
// TODO Auto-generated method stub
if(arg1.getAction() == MotionEvent.ACTION_DOWN) {
myVariable.timerEnable = 1;
myVariable.timerAdd = 0;
}
if(arg1.getAction() == MotionEvent.ACTION_UP){
myVariable.timerEnable = 0;
if(myVariable.timerAdd > 5){
myVariable.myobjectTracking_x = (int)(arg1.getRawX() + (myVariable.screenWidth / 20));
myVariable.myobjectTracking_y = (int)(arg1.getRawY());
myVariable.myobjectTrackingFlag = 1;
}else{
myVariable.mOpenCvCameraView.focusOnTouch(arg1);
}
}
return true;
}
最后在预览画面更新函数中进行真正的图像跟踪处理:
@Override
public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
// TODO Auto-generated method stub
if((myVariable.myobjectTracking == 1) && ((myVariable.myobjectTracking_x > 0) || myVariable.myobjectTracking_y > 0)){
myobject.libmyobjectTracking(myVariable.mRgba.getNativeObjAddr(),
myVariable.myobjectTracking_x, myVariable.myobjectTracking_y, myVariable.myobjectTrackingFlag);
myVariable.myobjectTrackingFlag = 0;
}
}
最后的函数libmyobjectTracking,就是在之前提到的那篇文章中代码移植过来,通过ndk调用即可。
效果演示
效果截图如下:
(图一) (图二)
抖动检测
原理介绍
主要用的是opencv集成的phaseCorrelate函数,用来检查移动的方向和速度。
具体可以看文档:opencv实现移动速度和方向探测 http://blog.csdn.net/u011630458/article/details/46323319
具体代码
和之前的物体跟踪类似,首先也是在setting中加入功能选择,抖动检测;接着是可以选择是否打开该功能。
private void initTremblePopupWindowView() {
myTrembleListView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,long arg3) {
if(arg2==0){
myVariable.myTremble = 1;
myVariable.myTremble_flag = 1;
}else if(arg2 == 1){
myVariable.myTremble = 0;
}
}
});
}
通过myTremble和myTremble_flag来表示抖动检测功能开启了。接着也是在预览更新函数中进行具体的抖动检测操作。
@Override
public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
// TODO Auto-generated method stub
.............
if(myVariable.myTremble == 1){
myobject.libmyTremble(myVariable.mRgba.getNativeObjAddr(), myVariable.myTremble_flag);
myVariable.myTremble_flag = 0;
}
............
}
这里的libmyTremble也是将之前文档中的代码,通过ndk移植过来的。需要注意下,实际测试中,该计算很花时间,在实际运行中,如果分辨率稍大,就会效果很差。
效果演示
效果截图如下:
(图三) (图四)
图库更新
具体代码
在拍完图片之后,发现打开系统自带的图库中,并没有被新出来。所以对拍照之后,让系统进行了从新扫描目录。
首先看下ndk下,具体的拍照图片保存。
JNIEXPORT void Java_com_example_camera_1opencv_1android_PreviceGray_takePicture(JNIEnv* env, jclass obj, jlong imageGray){
static int i = 0;
string file_mo = "_opencv_for_android.jpg";
string android_file = "mnt/sdcard/mycamera/";
string filename;
i++;
char buf[10];
sprintf(buf, "%d", i);
string b = buf;
filename = android_file + b + file_mo;
Mat mat = Mat(*((Mat*)imageGray));
Mat mat_1(mat), mat_2;
transpose(mat ,mat_1);
flip(mat_1, mat_2, 1);
imwrite(filename,mat_2);
}
这里可以看到保存出来的图片,在/sdcard/mycamera目录下,并且图片名字都是_opencv_for_android.jpg为结尾。
接着在保存完图片之后,让重新扫描目录:
private void fileScan(String file, Context context){
MediaScannerConnection.scanFile(context,
new String[] {file}, null,
new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
Log.i("TAG", "Finished scanning " + path);
}
});
}
public void folderScan(String path, Context context){
File file = new File(path);
if(file.exists() && file.isDirectory()){
File[] array = file.listFiles();
for(int i=0;i<array.length;i++){
File f = array[i];
if(f.isFile()){//FILE TYPE
String name = f.getName();
if(name.endsWith("opencv_for_android.jpg")){
fileScan(f.getAbsolutePath(),context);
}
}
}
}
}
效果演示
效果截图如下:
(图一)
模仿HDR
原理讲解
就是分别连续拍摄过曝和欠曝两张图片,然后进行合成。
具体可以参考文档:opencv实现图片HDR功能 http://10.120.10.100:9002/Opencv_wt_image_android_38
具体代码
1、在setting中,加上HDR选项,选择是否开启HDR功能。
private void initFirstPopupWindowView(View v) {
firstListView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,long arg3) {
...............
else if(arg2 == 4){
initHDRPopupWindowView();
}
...........
});
}
}
private void initHDRPopupWindowView() {
myHDRListView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,long arg3) {
if(arg2==0){
myVariable.myHDR = 1;
myVariable.myTremble = 0;
myVariable.myobjectTracking = 0;
myVariable.myChromaFlash = 0;
}else if(arg2 == 1){
myVariable.myHDR = 0;
}
}
});
}
可以看到myHDR来表示HDR功能打开或者关闭,同时如果HDR功能被打开,则其他的如物体跟踪等功能就被强行关闭掉了。
2、修改了拍照按钮操作流程。
@Override
public void onClick(View v) {
.............
else if(v.getId() == 4){
if(myVariable.myHDR == 1){
myVariable.pictureFlag = 2;
myVariable.myHDR_num = 17;
}else{
myVariable.pictureFlag = 1;
}
}
可以看到,HDR模式下,按下拍照之后,会连续拍摄两张照片,同时两张照片的间隔时间为myHDR_num。
3、接着在预览更新函数中,进行HDR的具体操作。
@Override
public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
if(myVariable.pictureFlag > 0){
...........
else if(myVariable.myHDR == 1){
myVariable.test.mainHDR(myVariable, MainActivity.this);
}
...........
}
}
public void mainHDR(MyVariable myVariable, Context context){
if(myVariable.myHDR_num == 17){
if(myVariable.pictureFlag == 2){
myVariable.mOpenCvCameraView.setExposure(6);
}else if(myVariable.pictureFlag == 1){
myVariable.mOpenCvCameraView.setExposure(-6);
}
}else if(myVariable.myHDR_num == 0){
PreviceGray.takeHDRPicture(myVariable.mRgba.getNativeObjAddr(), myVariable.pictureFlag);
myVariable.myHDR_num = 18;
myVariable.pictureFlag = myVariable.pictureFlag -1;
if(myVariable.pictureFlag == 0){
myVariable.mOpenCvCameraView.setExposure(0);
myVariable.test.folderScan(myVariable.pic_sdcard, context);
}
}
if(myVariable.myHDR_num > -1){
myVariable.myHDR_num -= 1;
}
}
这里可以看到首先设置camera曝光为过曝,拍摄一张图片,接着设置为欠曝,继续拍摄一张图片,最后在takeHDRPicture函数中进行合成。
takeHDRPicture就是将前面那篇文档中的代码,ndk下移植过来的。
模仿ChromaFlash
和HDR类似,区别上也就是HDR是使用的过曝和欠曝图片进行合成,而这个功能用来合成的图片为:打开闪光灯和关闭闪光灯拍摄的图片。
public void mainChromaFlash(MyVariable myVariable, Context context){
if(myVariable.myChromaFlash_num == 17){
if(myVariable.pictureFlag == 2){
myVariable.mOpenCvCameraView.setFlashMode(context, 4);
myVariable.myFlashLight = 1;
}else if(myVariable.pictureFlag == 1){
myVariable.mOpenCvCameraView.setFlashMode(context, 1);
myVariable.myFlashLight = 0;
}
}else if(myVariable.myChromaFlash_num == 0){
PreviceGray.takeChromaFlashPicture(myVariable.mRgba.getNativeObjAddr(), myVariable.pictureFlag);
myVariable.myChromaFlash_num = 28;
myVariable.pictureFlag = myVariable.pictureFlag -1;
if(myVariable.pictureFlag == 0){
myVariable.test.folderScan(myVariable.pic_sdcard, context);
}
}
if(myVariable.myChromaFlash_num > -1){
myVariable.myChromaFlash_num -= 1;
}
}
和HDR的操作基本类似,区别上也就是将设置camera曝光改为了设置camera的flash打开或者关闭。
具体演示下载:http://download.csdn.net/detail/u011630458/9261617