我的第一个Imx6ULL应用《百度图像识别》

Imx6ULL填坑计划

此次用到的所有资料我都放到了奶牛快传里,下载的话速度极快!
https://c-t.work/s/fe0b4a22171342

我买这个板子已经很久了,跟着野火正点原子的教程踉踉跄跄学了一段儿,对很多基础知识也是一知半解,最终也算是搞了下字符驱动开发,并且做了自己的第一次尝试:

【linux学习vlog】周末两天爆肝入门linux嵌入式

然后呢最近终于费了九牛二虎之力搞成了自己第一个最完善的应用:基于百度图像与语音的一个小作品:

【野火linux】我的第一个linux+QT应用


接下来就总结一下我的制作过程,由于我没有该视频的文档,所以我都是跟着视频敲代码,一点一点撸出来的!!
参考讯为的图像识别项目教程: https://www.bilibili.com/video/BV157411c7sc/

制作总结

我的做法与讯为的不同点:
讯为使用的摄像头带驱动,我买的免驱的USB摄像头,这样更简单。
讯为调用摄像头采用的是Opencv,我感觉没必要,我直接用的QT的camera组件。
然后讯为在同步板子和电脑上交叉编译库的时候,用的是设计根文件系统,而我直接通过NFS怼进去的,这样更简单(野火构建根本文件系统的教程一言难尽,依赖文件太多,下载太慢。)

  1. linux板环境准备

QT交叉编译环境的搭建 (按照野火的文档手册39.1节来就可以,前提是你要把野火需要下载的东西都搞定,且编译通过)
PC端QT环境的搭建,最终完成的效果是生成一个最基本的QT程序,能在PC上编译运行,然后交叉编译以后能板子上正常运行,这时候最基本的准备就完成了。

这里的坑就是:

*安装 arm-linux-gnueabihf-gcc v8.3.0*
野火文档上面的编译脚本是有问题的,一是他的排版问题,导致你sh命令总会出错,你可以自己拷贝下来以后自己排查一下修改一下,我编译高版本的8.3的GCC的时候就已经出问题了,一是sh脚本根本无法运行,二是下载失败。其实这个还是比较简单的,因为sh脚本并不复杂可以看得懂,就是把编译器下载下来,然后放到/opt目录下即可。
我已经准备好了在网盘里:arm-linux-gnueabihf-gcc v8.3.0
然后按照野火的教程走,导出环境变量,并验证版本。
剩下的交叉编译触摸驱动tslib以及声卡alsa(这两个是交叉编译进QT工程里面的)  
交叉编译QT也是一样的,使用我检验过的即可。
可以按照我做好的sh脚本来执行,直接就OK了。(野火的排版有问题,复制下来是不行的)
然后就按照野火教程安装QT Creator  这里是没问题的
然后把交叉编译的第一个APP nfs扔到板子里,能正常跑,OK到这里基本的准备条件就完成了,就可以在QT的海洋里遨游了。
  1. 百度应用的创建与准备
    接下来是百度端的应用创建,这个我比较熟悉,因为之前就玩过树莓派的图像识别、人脸识别、以及语音识别。 如图:创建语音应用和图像识别应用
    我的第一个Imx6ULL应用《百度图像识别》_第1张图片
主要是用到百度的三元组
AppID
API Key
Secret Key
  1. 依赖库的交叉编译
 接下来其他的就暂时脱离QT了,这是对 整个图像识别和百度语音识别做准备的:
编译openssl
cd openssl-1.0.2f/
setarch i386 ./config no-asm shared --prefix=/usr/local/openssl/
CC= arm-linux-gnueabihf-gcc
AR= arm-linux-gnueabihf-ar $(ARFLAGS) r
RANLIB= arm-linux-gnueabihf-ranlib
NM= arm-linux-gnueabihf-nm
 make
sudo make install

编译curl
./configure --prefix=/usr/local/curl/ --host=arm-linux-gnueabihf CC=arm-linux-gnueabihf-gcc CXX=arm-linux-gnueabihf-g++ --with-ssl=/usr/local/openssl
make
sudo make install

编译jsoncpp (我这里虽然编译成功了,但是在QT里总是调用失败,解决方法见下文)
mkdir arm_jsoncpp
cp -r include/ arm_jsoncpp/
cp src/lib_json/* arm_jsoncpp/
arm-linux-gnueabihf-g++ -c *.cpp -I./include -fPIC
mkdir lib
 ar cr ./lib/libjsoncpp.a *.o
 编译动态库
 arm-linux-gnueabihf-g++ -shared -fPIC *.cpp -I./include -o ./lib/libjsoncpp.so 
××解决jsoncpp问题××
我百度查了查  jsoncpp即使不进行动态编译,一样可以调用,直接把cjson需要用到的文件扔QT工程里面就行了。直接在QT里引用外部文件把整个json文件夹饮用即可!
参考链接: https://www.cnblogs.com/zengjfgit/p/4959965.html

  1. 根文件系统的整理与拷贝
 然后就是以上依赖库的环境变量引导,把上面的文件在PC上放到指定位置进行交叉编译生成QT可执行文件,nfs扔到板子上运行,会提示找不到依赖库。
此时把依赖库文件,放到imx6ull板子的指定路径,并且编辑环境变量。再次运行就不报错了。
将文件放到开发板的对应位置以及lib文件夹
root@npi:/mnt# cp -r curl /usr/local/
root@npi:/mnt# cp -r openssl /usr/local/
root@npi:/mnt# cp -r curl/lib/* /lib/
root@npi:/mnt# cp -r openssl/lib/* /lib/

vi ./etc/init.d/rcS  如下图
讯为的教程使用的是 设计根文件系统,而我是直接NFS传进去,其实原理是一样的,无论怎么样,只要能让QT应用在板子的指定位置找到指定的依赖文件即可。

注:如果使用的是野火的debian系统找不到rcS文件,那么就用系统变量的配制方法:
vi .bashrc
在文末添加如下内容
export PATH=$PATH:/usr/local/openssl/bin
export PATH=$PATH:/usr/local/curl/bin
编辑完成以后 更新一下,然后查看是否OK
source ~/.bashrc
echo $PATH

我的第一个Imx6ULL应用《百度图像识别》_第2张图片

  1. QTAPP的编写

百度APP初始化部分:

#include "json/include/json/json.h"  //由于我没编译成功jsoncpp的依赖库,所以用这种本地依赖的方法来作

#include "ocr.h"
#include "speech.h"
// 设置语音合成 APPID/AK/SK
std::string speech_app_id = "21275374";
std::string speech_api_key = "5ZGKQxLfmVamG2GnP9zsXGKX";
std::string speech_secret_key = "ZW5Aoopu2K88DOQtgcZBQGjmTnDH8ncQ";
aip::Speech client_speech(speech_app_id, speech_api_key, speech_secret_key);

// 设置文字识别APPID/AK/SK
std::string app_id = "21267850";
std::string api_key = "mXTgSiRIQ07OYFGqB3aSlY2t";
std::string secret_key = "LWoGPMUaqKzLfUPihDUnphEMNX148uR2";

aip::Ocr client(app_id, api_key, secret_key);

车牌识别部分:

std::string GetPlateNumber(std::string PicturePath)
{
    Json::Value result;

    std::string image;
    aip::get_file_content(PicturePath.c_str(), &image);

    // 调用车牌识别
    result = client.license_plate(image, aip::null);

    // 如果有可选参数
    std::map options;
    options["multi_detect"] = "true";
    // 带参数调用车牌识别
    result = client.license_plate(image, options);
    if(result["error_code"].isNull())  //无报错
    {
      return ("车牌号"+result["words_result"][0]["number"].asString()+"欢迎光临");
    }else
    {
    return ("error");
    }
}

语音合成(文字转语音部分):

int tts(std::string text,std::string FileName)
{
    std::ofstream ofile;
    std::string file_ret;
    std::map options;
    options["spd"] = "4";
    options["per"] = "5";

    // 合成成功的二进制数据写入文件中
    ofile.open(FileName, std::ios::out | std::ios::binary);

    // 不带可选参数调用
    //Json::Value result = client_speech.text2audio("百度语音合成测试", aip::null, file_ret);

    // 带可选参数调用, 参数参考参数列表中的可选参数
     Json::Value result = client_speech.text2audio(text, options, file_ret);

    // 如果file_ret为不为空则说明合成成功,返回mp3文件内容回结果
    if (!file_ret.empty())
    {
        ofile << file_ret;
        return 0;
    } else {
        // 服务端合成错误
        std::cout << result.toStyledString();
        return 1;
    }
    return 2;
}

拍照按钮事件的执行:

void Camera::processCapturedImage(int requestId, const QImage& img)
{
    Q_UNUSED(requestId);
    QImage scaledImage = img.scaled(ui->viewfinder->size(),
                                    Qt::KeepAspectRatio,
                                    Qt::SmoothTransformation);
    ui->lastImagePreviewLabel->setPixmap(QPixmap::fromImage(scaledImage));
    const QPixmap *pixmap=ui->lastImagePreviewLabel->pixmap();
    pixmap->save("./a.jpg");  //存储到指定位置
    std::string out;
    std::int8_t sp_out;
    out =  GetPlateNumber("./a.jpg");
    ui->statusbar->showMessage(out.c_str());
    //语音合成
    sp_out = tts(out,"./a.mp3");
    if(sp_out == 0)
    {
    //播放   开启新线程执行系统命令
    QProcess *process = new QProcess();
    process->start("gplay-1.0 a.mp3");
   // system("gplay-1.0 a.mp3");
    }else
    {
     ui->statusbar->showMessage("语音合成失败");
    }
    QMessageBox::warning(this, tr("OK"), out.c_str());
// Display captured image for 4 seconds.  这里会在linux板子上面卡住
// displayCapturedImage();
// QTimer::singleShot(4000, this, &Camera::displayViewfinder);
}

这一切搞完,就OK了,完美运行!我太难了!四处碰壁。
总之,最终完成了,还是很开心的。好好学习、天天向上!

你可能感兴趣的:(嵌入式,IMX6ULL,linux,linux,图像识别,嵌入式)