原文地址http://www.cnblogs.com/jsxyhelu/p/8286475.html
一、綜述
如何采集圖片?在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();
if(resultCode == -1 && receiverRequestCode == 1){
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);
startActivity(intent,1,resultReceiver);
//獲得回傳的絕對地址(注意這句話一定要寫在CHECK_EXCEPTION中)
strFetchImage=savedImageFile.toString();
}
最終采集到的圖片地址保存在strFetchImage 中
e、撰寫處理代碼。由于我這里主要進行的是影像處理操作,所以必須結合OpenCV相關函式進行
//影像處理操作
voidMainWindow::on_btn_process_pressed()
{
b_canSave=false;
if(strFetchImage!="")
{
ui->lbMain->setScaledContents(false);
Matsrc=https://bbs.csdn.net/topics/imread(strFetchImage.toStdString());
Matsrc2;
Matrotated;
////////////////////////////主要演算法/////////////////////////////
cv::resize(src,src2,cv::Size(720,1000));//標準大小
Matsrc_gray;
Matsrc_all=src2.clone();
Matthreshold_output;
vector<vector<Point>>contours,contours2;
vector<Vec4i>hierarchy;
//預處理
cvtColor(src2,src_gray,CV_BGR2GRAY);
blur(src_gray,src_gray,Size(3,3));//模糊,去除毛刺
threshold(src_gray,threshold_output,100,255,THRESH_OTSU);
//添加提示
ui->lb_info->setText("開始尋找輪廓!");
//尋找輪廓
//第一個引數是輸入影像2值化的
//第二個引數是記憶體存盤器,FindContours找到的輪廓放到記憶體里面。
//第三個引數是層級,**[Next,Previous,First_Child,Parent]**的vector
//第四個引數是型別,采用樹結構
//第五個引數是節點擬合模式,這里是全部尋找
findContours(threshold_output,contours,hierarchy,CV_RETR_TREE,CHAIN_APPROX_NONE,Point(0,0));
//添加提示
if(contours.size()<=10)
{
ui->lb_info->setText("輪廓篩選錯誤,回圈退出!請重新采集資料。");
return;
}
else
{
ui->lb_info->setText("開始尋找輪廓!開始篩選輪廓!");
}
//輪廓篩選
intc=0,ic=0,area=0;
intparentIdx=-1;
for(inti=0;i<contours.size();i++)
{
//hierarchy[i][2]!=-1表示不是最外面的輪廓
if(hierarchy[i][2]!=-1&&ic==0)
{
parentIdx=i;
ic++;
}
elseif(hierarchy[i][2]!=-1)
{
ic++;
}
//最外面的清0
elseif(hierarchy[i][2]==-1)
{
ic=0;
parentIdx=-1;
}
//找到定位點資訊
if(ic>=2)
{
contours2.push_back(contours[parentIdx]);
ic=0;
parentIdx=-1;
}
}
//添加提示
if(contours2.size()<3)
{
ui->lb_info->setText("定位點選擇錯誤,回圈退出!請重新采集資料。");
return;
}
else
{
ui->lb_info->setText("開始尋找輪廓!開始篩選輪廓!定位點選擇正確!");
}
//填充定位點,我們約定,必須要能夠同時識別出4個點來
for(inti=0;i<contours2.size();i++)
drawContours(src_all,contours2,i,CV_RGB(0,255,0),-1);
//識別出來了關鍵區域,但是數量不對,顯示當前識別結果,退出回圈
if(contours2.size()!=4)
{
QPixmapqpixmap=Mat2QImage(src_all);
ui->lbMain->setPixmap(qpixmap);
ui->lb_info->setText("定位點數量不為4!請重新采集資料。");
return;
}
else
{
//否則,進一步分割
Pointpoint[4];
for(inti=0;i<contours2.size();i++)
{
//篩選輪廓,
doubled=contourArea(contours2[i]);
if(d>720*1000/4)
{
ui->lb_info->setText("采集中有錯誤輪廓,請重新采集資料");
QPixmapqpixmap=Mat2QImage(src_all);
ui->lbMain->setPixmap(qpixmap);
return;
}
//定位重點,并重新排序
Pointptmp=Center_cal(contours2,i);
if(ptmp.x<720/4&&ptmp.y<1000/4)
{
point[0]=ptmp;
}
elseif(ptmp.x<720/4&&ptmp.y>1000/4)
{
point[2]=ptmp;
}
elseif(ptmp.x>720/4&&ptmp.y<1000/4)
{
point[1]=ptmp;
}
else
{
point[3]=ptmp;
}
}
//列印出來
for(inti=0;i<3;i++)
{
charcbuf[100];
sprintf(cbuf,"%d",i+1);
putText(src_all,cbuf,point[i],FONT_HERSHEY_PLAIN,5,Scalar(0,0,0),5);
ui->lb_info->setText("結果識別正確,可以保存");
}
//透視變換
cv::Point2fsrc_vertices[4];
src_vertices[0]=point[0];
src_vertices[1]=point[1];
src_vertices[2]=point[2];
src_vertices[3]=point[3];
Point2fdst_vertices[4];
dst_vertices[0]=Point(0,0);
dst_vertices[1]=Point(720,0);
dst_vertices[2]=Point(0,1000);
dst_vertices[3]=Point(720,1000);
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、添加資料保存的相關功能。
感謝閱讀至此,希望有所幫助!
uj5u.com熱心網友回復:
uj5u.com熱心網友回復:
需要下載QT的antriod的開發包吧,我記得轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/76858.html
標籤:圖形處理/算法
上一篇:航空姿態儀表
