一、综述

    如何采集图片?在windows环境下,我们可以使用dshow,在linux下,也有ffmpeg等基础类库,再不济,opencv自带的videocapture也是提供了基础的支撑。那么在andoird下,使用的肯定是Android自带的相关函数了。由于Android是基于java语言的,如果我们想要调用Android 的相关函数,那么必须通过JNI的方法。
    这里有可以分为两种,一种是直接在java中实现比较完整的函数,在qt中,只需要调用这个函数就可以;另一种就是使用qt自带的jni机制,比如下面这样,打开摄像头,并且采集图片。我们首先介绍第二种方法,让大家最快进入情况。
 
二、通过JNI打开摄像头
a、填加头文件和命名空间,定义公共变量和宏:
#include <QtAndroid>
#include <QDebug>
#include <QAndroidJniEnvironment>
#include <QAndroidActivityResultReceiver>
#include <QDateTime>
#include <QFile>
using namespace cv;
using namespace QtAndroid;
 
QString strFetchImage = "";
QString selectedFileName = "";
 
#define CHECK_EXCEPTION() \
if(env->ExceptionCheck())\
{\
qDebug() << "exception occured";\
env->ExceptionClear();\
}
 
其中需要注意的是,CHECK_EXCEPTION是用来检查Android系统是否有异常的。这一点在使用JNI的时候非常重要和必要。
 
b、填加回调类,主要就是在一系列异常判断后,获得imagepath。该类集成自ResultReceiver:
class ResultReceiver: public QAndroidActivityResultReceiver
{
    public: ResultReceiver(QString imagePath, QLabel *view) : m_imagePath(imagePath), m_imageView(view){}
    void handleActivityResult(int receiverRequestCode,int resultCode,const QAndroidJniObject & data){
     qDebug() << "handleActivityResult, requestCode - " << receiverRequestCode<< " resultCode - " << resultCode<< " data - " << data.toString();
){
    qDebug() << "captured image to - " << m_imagePath;
    qDebug() << "captured image exist - " << QFile::exists(m_imagePath);
    m_imageView->setPixmap(QPixmap(m_imagePath));}
    }
    QString m_imagePath;
    QLabel *m_imageView;
};
 
C、填加控件触发事件。一般来说我们选择pressed事件
d、编写拍照代码
//打开摄像头,采集图片
voidMainWindow::on_btn_capture_pressed()
{
ui->lbMain->setScaledContents(true);//显示的图像自动缩放
b_canSave=false; //图片没有采集完成,目前不可以保存
//引用JNI
QAndroidJniEnvironmentenv;
//创建用于打开摄像头的content
QAndroidJniObjectaction=QAndroidJniObject::fromString("android.media.action.IMAGE_CAPTURE");QAndroidJniObject (intent("android/content/Intent","(Ljava/lang/String;)V",action.object<jstring>());
//设定img路径
QStringdate=QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss");
QAndroidJniObjectfileName=QAndroidJniObject::fromString(date+".jpg");
QAndroidJniObjectsavedDir=QAndroidJniObject::callStaticObjectMethod("android/os/Environment","getExternalStorageDirectory","()Ljava/io/File;");
//使用CHECK_EXCEPTION处理异常
CHECK_EXCEPTION()
qDebug()<<"savedDir-"<<savedDir.toString();
QAndroidJniObjectsavedImageFile("java/io/File","(Ljava/io/File;Ljava/lang/String;)V",savedDir.object<jobject>(),fileName.object<jstring>());
CHECK_EXCEPTION()
qDebug()<<"savedImageFile-"<<savedImageFile.toString();
QAndroidJniObjectsavedImageUri=QAndroidJniObject::callStaticObjectMethod("android/net/Uri","fromFile","(Ljava/io/File;)Landroid/net/Uri;",
savedImageFile.object<jobject>());
CHECK_EXCEPTION()
 
//将输出路径传递过来
QAndroidJniObjectmediaStoreExtraOutput=QAndroidJniObject::getStaticObjectField("android/provider/MediaStore","EXTRA_OUTPUT","Ljava/lang/String;");
CHECK_EXCEPTION()
qDebug()<<"MediaStore.EXTRA_OUTPUT-"<<mediaStoreExtraOutput.toString();
intent.callObjectMethod(
"putExtra","(Ljava/lang/String;Landroid/os/Parcelable;)Landroid/content/Intent;",mediaStoreExtraOutput.object<jstring>(),
savedImageUri.object<jobject>());
 
//获得采集图片的绝对路径,并且显示出来
ResultReceiver*resultReceiver=newResultReceiver(savedImageFile.toString(),ui->lbMain);
,resultReceiver);
//获得返回的绝对地址(注意这句话一定要写在CHECK_EXCEPTION中)
strFetchImage=savedImageFile.toString();
}
最终采集到的图片地址保存在strFetchImage 中
 
e、编写处理代码。由于我这里主要进行的是图像处理操作,所以必须结合OpenCV相关函数进行
//图像处理操作
voidMainWindow::on_btn_process_pressed()
{
b_canSave=false;
if(strFetchImage!="")
{
ui->lbMain->setScaledContents(false);
Matsrc=imread(strFetchImage.toStdString());
Matsrc2;
Matrotated;
////////////////////////////主要算法/////////////////////////////
,));//标准大小
Matsrc_gray;
Matsrc_all=src2.clone();
 
Matthreshold_output;
vector<vector<Point>>contours,contours2;
vector<Vec4i>hierarchy;
//预处理
cvtColor(src2,src_gray,CV_BGR2GRAY);
,));//模糊,去除毛刺
,,THRESH_OTSU);
//添加提示
ui->lb_info->setText("开始寻找轮廓!");
//寻找轮廓
//第一个参数是输入图像2值化的
//第二个参数是内存存储器,FindContours找到的轮廓放到内存里面。
//第三个参数是层级,**[Next,Previous,First_Child,Parent]**的vector
//第四个参数是类型,采用树结构
//第五个参数是节点拟合模式,这里是全部寻找
,));
//添加提示
)
{
    ui->lb_info->setText("轮廓筛选错误,循环退出!请重新采集数据。");
    return;
}
else
{
    ui->lb_info->setText("开始寻找轮廓!开始筛选轮廓!");
}
 
//轮廓筛选
,,;
;
;i<contours.size();i++)
{
//hierarchy[i][2]!=-1表示不是最外面的轮廓
]!=-&&)
{
parentIdx=i;
ic++;
}
]!=-)
{
ic++;
}
//最外面的清0
]==-)
{
;
;
}
//找到定位点信息
)
{
contours2.push_back(contours[parentIdx]);
;
;
}
}
 
//添加提示
)
{
ui->lb_info->setText("定位点选择错误,循环退出!请重新采集数据。");
return;
}
else
{
ui->lb_info->setText("开始寻找轮廓!开始筛选轮廓!定位点选择正确!");
}
 
//填充定位点,我们约定,必须要能够同时识别出4个点来
;i<contours2.size();i++)
,,),-);
 
//识别出来了关键区域,但是数量不对,显示当前识别结果,退出循环
)
{
QPixmapqpixmap=Mat2QImage(src_all);
ui->lbMain->setPixmap(qpixmap);
ui->lb_info->setText("定位点数量不为4!请重新采集数据。");
return;
}
else
{
//否则,进一步分割
];
;i<contours2.size();i++)
{
//筛选轮廓,
doubled=contourArea(contours2[i]);
*/)
{
ui->lb_info->setText("采集中有错误轮廓,请重新采集数据");
QPixmapqpixmap=Mat2QImage(src_all);
ui->lbMain->setPixmap(qpixmap);
return;
}
//定位重点,并重新排序
Pointptmp=Center_cal(contours2,i);
 
/&&/)
{
]=ptmp;
}
/&&/)
{
]=ptmp;
}
/&&/)
{
]=ptmp;
}
else
{
]=ptmp;
}
}
 
//打印出来
;;i++)
{
];
);
,,,),);
ui->lb_info->setText("结果识别正确,可以保存");
}
 
//透视变换
];
]=];
]=];
]=];
]=];
];
]=,);
]=,);
]=,);
]=,);
MatwarpMatrix=getPerspectiveTransform(src_vertices,dst_vertices);
//执行透视变化
warpPerspective(src2,rotated,warpMatrix,rotated.size(),INTER_LINEAR,BORDER_CONSTANT);
}
//////////////////////////END主要算法END///////////////////////
//将图片显示到label上
QPixmapqpixmap=Mat2QImage(rotated);
ui->lbMain->setPixmap(qpixmap);
matResult=rotated.clone();
b_canSave=true;
}
}
三、初步结果和继续研究需要解决的问题
按照设计,目前得到这样的结果
下一步注重解决以下问题
1、提高程序稳定性;
2、提高界面流程性和运行速度;
3、重构代码,进一步进行封装;
4、添加数据保存的相关功能。
感谢阅读至此,希望有所帮助!
 

(GO_GTD_2)基于OpenCV和QT,建立Android图像处理程序的更多相关文章

  1. (GO_GTD_1)基于OpenCV和QT,建立Android图像处理程序

    一.创建新QT工程 一定要是全英文路径,比如"E:\android_qt_opencv\GO_GTD" 由于我们在安装的时候,选择android的工具链,所以在这里会出现以下选择, ...

  2. (GO_GTD_3)基于OpenCV和QT,建立Android图像处理程序

    一.解决权限问题     图片采集了,处理了,如何保存?最直接的方法是使用imwrite,但是如果现在直接使用的话,比如会出现这样或那样的错误,因为我们现在是在android的环境下进行图像处理,所以 ...

  3. 基于qml创建最简单的图像处理程序(3)-使用opencv&qml进行图像处理

    <基于qml创建最简单的图像处理程序>系列课程及配套代码基于qml创建最简单的图像处理程序(1)-基于qml创建界面http://www.cnblogs.com/jsxyhelu/p/83 ...

  4. Python图像处理丨基于OpenCV和像素处理的图像灰度化处理

    摘要:本篇文章讲解图像灰度化处理的知识,结合OpenCV调用cv2.cvtColor()函数实现图像灰度操作,使用像素处理方法对图像进行灰度化处理. 本文分享自华为云社区<[Python图像处理 ...

  5. 基于qml创建最简单的图像处理程序(1)-基于qml创建界面

    <基于qml创建最简单的图像处理程序>系列课程及配套代码基于qml创建最简单的图像处理程序(1)-基于qml创建界面http://www.cnblogs.com/jsxyhelu/p/83 ...

  6. 基于qml创建最简单的图像处理程序(2)-使用c++&qml进行图像处理

     <基于qml创建最简单的图像处理程序>系列课程及配套代码基于qml创建最简单的图像处理程序(1)-基于qml创建界面http://www.cnblogs.com/jsxyhelu/p/8 ...

  7. 基于opencv和QT的摄像头采集代码( GoQTtemplate3持续更新)

    在Linux操作系统上,编写带界面的图像处理程序,选择opencv+QT是一种很好的选择.GoQTtemplate3是我为编写Linux下图像处理程序实现的框架,希望能够为大家解决Linux环境下桌面 ...

  8. 基于opencv和qt的人脸检测小系统

    摘要:利用opencv读取视频.图片并检测人脸,利用QT显示窗口,功能选择等 环境:Ubuntu18.04.OpenCV3.4.0.QT5.10.1 效果图: 代码如下(比较简单没什么注释): mai ...

  9. 基于opencv的小波变换代码和图像结果

    #include "stdafx.h" #include "WaveTransform.h" #include <math.h> #include ...

随机推荐

  1. iOS有关图片处理的总结 (四)------图片的饱和度,亮度,对照度。

    在做图片处理的时候.会遇到调节图片的饱和度的问题,这里就要用到Core Image这个框架,Core Image是一个非常强大的框架. 它能够让你简单地应用各种滤镜来处理图像,比方改动鲜艳程度, 色泽 ...

  2. cocos2dx中关于Action动作的相关API的具体介绍

     //CCMoveBy  创建一个移动的动作 //參数1:移动到目标坐标所需的时间 //參数2:目标坐标 //支持reverse 能够获取其反向动作 //CCMoveTo  一样的 //CCAct ...

  3. backbone入门学习一

    初识backbone 1.Backbone是什么? Backbone是一个非常轻量级的javaScript库,可以打造为模型(Model)-视图(View)-控制器(Controller)即MVC类结 ...

  4. Java数组的一些使用方法及堆栈存储

    数组 用于存储一组同一数据类型数据的容器 数组会对放入其中的数据自动编号,编号是从0开始的---下标 定义格式 数据类型[] 数组名 = new 数据类型[数组的大小];---可以先声明再初始化 in ...

  5. 《程序设计实践》【PDF】下载

    <程序设计实践>[PDF]下载链接: https://u253469.ctfile.com/fs/253469-231196319 内容简介 本书从排错.测试.性能.可移植性.设计.界面. ...

  6. 虚拟表dual。字符串函数UPPER,LOWER。&变量。INITCAP,LENGTH,SUBSTR

    &自定义变量的用法:

  7. 遍历map的几种方式

    1,平时开发中对map的使用很多,然后发现了很多map可能存在的各种问题:如HashMap 需要放置 1024 个元素,由于没有设置容量初始大小,随着元素不断增加,容量 7 次被迫扩大,resize ...

  8. bzoj 4539: [Hnoi2016]树

    Description 小A想做一棵很大的树,但是他手上的材料有限,只好用点小技巧了.开始,小A只有一棵结点数为N的树,结 点的编号为1,2,-,N,其中结点1为根:我们称这颗树为模板树.小A决定通过 ...

  9. Jmeter+Ant+Jenkins接口自动化测试(二)_测试方案设计及jmeter脚本开发

    前言 根据之前部署好的测试环境,进行接口自动化测试的方案设计及Jmeter脚本开发.测试方案设计过程中采用了数据分离和对象分离等思路,因此直接通过特定的测试用例文档来驱动整个自动化接口测试的执行,相关 ...

  10. Windows,Mac与Linux哪个更适合开发者?

        以前写的,怕引来口水战,干脆不发.这段时间面试了十来人,用Mac的开发水平明显高于Windows的,挺多感想的,于是改改发了吧.      Windows: 对普通用户而言体验最友好,对开发者 ...