分类 Code 下的文章

正常回调函数使用的是普通函数或者静态函数,而成员函数因为会在参数列表最前面插入一个 this 指针,所以导致直接使用会报错。成员函数想要被调用需要使用特殊的操作方法。

- 阅读剩余部分 -

1. 发送信号

在发送的头文件中标明需要发送的信号

    Q_OBJECT    //必须使用宏Q_OBJECT
signals:                    //使用signals声明信号函数,访问级别为protected
    void testSignal(int v);     //信号只能声明不能定义

在源文件中,函数内部可以通过 emit 来发送这个信号

emit testSignal(i);     //通过emit关键字发射信号

2. 接收信号的槽

在接收头文件中标明槽函数

    Q_OBJECT
protected slots:
    void mySlot(int v)
    {
        qDebug() << "Value: " << v;
    }

3. 绑定信号和槽

在类似于 mainwindow 这样的上层文件中,需要拿到包含信号的实例和包含槽的实例,然后把信号和对应的槽通过 connect 绑定在一起。

    TestSignal t;
    RxClass r;

    //信号函数与槽函数需要一致,并且不出现参数名
    QObject::connect(&t, SIGNAL(testSignal(int)), &r, SLOT(mySlot(int)));

参考: https://blog.csdn.net/small_prince_/article/details/96106202

1. 先 git clone tensorflow 的仓库,可以在 github 也可以在 gitee, gitee 会比 github 慢一天左右。但是下载速度快多了。

git clone https://github.com/tensorflow/tensorflow.git
git clone https://gitee.com/mirrors/tensorflow.git

2. 确定环境里面有 g++, gcc, ar

3. 下载需要的依赖

./tensorflow/lite/tools/make/download_dependencies.sh

下载的依赖文件在 ./tensorflow/lite/tools/make/downloads 文件夹下面

4. 修改 Makefile

vim ./tensorflow/lite/tools/make/Makefile

把里面的

CXX := $(CC_PREFIX)${TARGET_TOOLCHAIN_PREFIX}g++
CC := $(CC_PREFIX)${TARGET_TOOLCHAIN_PREFIX}gcc
AR := $(CC_PREFIX)${TARGET_TOOLCHAIN_PREFIX}ar

这三行,修改为对应的 g++, gcc, ar

4. 编译为库

./tensorflow/lite/tools/make/build_aarch64_lib.sh

生成的静态库文件在 tensorflow/lite/tools/make/gen/aarch64_armv8-a/lib/libtensorflow-lite.a

参考: https://tensorflow.google.cn/lite/guide/build_arm64?hl=zh-cn

5. 抽取 tflite 的头文件,并打包

cd tensorflow/tensorflow
find ./lite -name "*.h" | tar -cf headers.tar -T -

这个 headers.tar 里面包含了头文件和一些不需要的东西。 注意:有些头文件在 tensorflow/tensorflow/lite/tools/make/downloads 这个下载的包里面。比如说 flatbuffers,要把他们专门复制到相应的头文件夹下面。 include 头文件夹下面的组织形式

[xxx@localhost include]$ tree -L 3
.
├── downloads
│   └── include
│       └── flatbuffers
└── tensorflow
    └── lite
        ├── allocation.h
        ├── arena_planner.h
        ├── builtin_op_data.h
        ├── builtin_ops.h
        ├── c
        ├── context.h
        ├── context_util.h
        ├── core
        ├── delegates
        ├── error_reporter.h
        ├── examples
        ├── experimental
        ├── external_cpu_backend_context.h
        ├── graph_info.h
        ├── interpreter_builder.h
        ├── interpreter.h
        ├── java
        ├── kernels
        ├── memory_planner.h
        ├── micro
        ├── minimal_logging.h
        ├── model_builder.h
        ├── model.h
        ├── mutable_op_resolver.h
        ├── nnapi
        ├── op_resolver.h
        ├── optional_debug_tools.h
        ├── profiling
        ├── python
        ├── schema
        ├── simple_memory_arena.h
        ├── stderr_reporter.h
        ├── string_type.h
        ├── string_util.h
        ├── testing
        ├── tflite_with_xnnpack_optional.h
        ├── toco
        ├── tools
        ├── type_to_tflitetype.h
        ├── util.h
        └── version.h

20 directories, 26 files

参考: https://blog.csdn.net/shui123546yi/article/details/105410781

6. 把前面编译好的静态库也复制到 lib 文件夹下面。

7. 编写 cmake 文件

#注意:如果工程有依赖库的话,ADD_EXECUTABLE指令要放在LINK_DIRECTORIES指令之后,
#       不然会报错:Linking C executable main
#                   /usr/bin/ld: cannot find -lhello
#                   collect2: ld 返回 1

#1) 设置 cmake 的最低版本
cmake_minimum_required(VERSION 3.10)

#2) 设置 project 名称
project(tflite_test)

#3) 设置代码源文件列表
set(SRC_LIST main.cpp model.cpp)

#4) 增加头文件搜索路径,解决编译期间找不到头文件的问题
#COMMAND: INCLUDE_DIRECTORIES([AFTER|BEFORE] [SYSTEM] dire1 dire2 ...)
#定义:向工程添加多个特定的头文件搜索路径,路径之间用空格分开,
#       如果路径中包含空格,可以使用双引号括起来
#       默认是追加到当前的头文件搜索路径之后,你可以用2种方式控制搜索路径的添加>方式
#       1)CMAKE_INCLUDE_DIRECTORIES_BEFORE 通过SET设置其为on,使用前置模式
#       2)通过AFTER或BEFORE参数,控制追加还是置前
include_directories("/usr/include/x86_64-linux-gnu")
include_directories("./include")
include_directories(".")
include_directories("./include/downloads/include")

#5) 增加库文件: 解决链接期间找不到调用外部接口的问题
#main.cpp:(.text+0x5): undefined reference to `HelloFunc()'
#collect2: error: ld returned 1 exit status

#6) 增加库文件搜索路径:解决链接期间找不到库文件的问题
#COMMAND: LINK_DIRECTORIES(dir1 dir2 ...)
#定义:添加非标准的共享库搜索路径
#/usr/bin/ld: cannot find -lhello
#collect2: error: ld returned 1 exit status
#好像相对路径会找不到库文件
link_directories("/usr/lib/x86_64-linux-gnu")
link_directories("./lib")

#7) 生成二进制文件
add_executable(${PROJECT_NAME} ${SRC_LIST})

#8) 链接库
#COMMAND: TARGET_LINK_LIBRARIES(target  library1
#                                <debug | optimized> library2
#                                ...)
#定义:用来为target添加需要链接的共享库
#TARGET_LINK_LIBRARIES(${PROJECT_NAME} hello) #链接动态库指令
#TARGET_LINK_LIBRARIES(${PROJECT_NAME} libhello.a)  #链接静态库指令
target_link_libraries(${PROJECT_NAME} PRIVATE tensorflow-lite pthread ${CMAKE_DL_LIBS})

注意:如果提示没有 undefined reference to dlopen ,undefined reference to pthread_create 别忘了在链接库里面添加 pthread ${CMAKE_DL_LIBS}

参考:

https://github.com/jiangxinyang227/nlp_tflite/blob/master/cpp_tflite/src/inference.cpp https://www.cnblogs.com/jiangxinyang/p/13215724.html https://github.com/tensorflow/tensorflow/tree/master/tensorflow https://tensorflow.google.cn/lite/microcontrollers/get_started https://www.cnblogs.com/vitoyeah/p/10273299.html https://github.com/gdyshi/model_deployment/blob/master/tflite/C%2B%2B/model.cc https://github.com/gdyshi/model_deployment/blob/master/tflite/C%2B%2B/example.cc https://github.com/gdyshi/model_deployment https://blog.csdn.net/chongtong/article/details/90379347 https://blog.csdn.net/chongtong/column/info/39386 https://blog.csdn.net/chongtong/article/details/95355814

1. shell 单行注释使用 “#” 就可以了,多行注释:

:<<EOF

EOF

这个 EOF 可以换成其他,都可以,只要上下能够对应就可以。

参考:https://blog.csdn.net/lansesl2008/article/details/20558369 https://blog.csdn.net/tenfyguo/article/details/5753548

2. 检查文件是否存在:

if [ -f trials ]; then 
      rm trials
fi

参考: https://www.jb51.net/article/186273.htm

3. 退出脚本

exit 1

参考: https://blog.csdn.net/qq_35769944/article/details/81943543

4. 变量养成使用 {} 包起来的习惯

参考: https://www.runoob.com/linux/linux-shell-variable.html

5. 需要 python 脚本的时候,直接使用即可。

python3 test.py

参考: https://blog.csdn.net/zwt0909/article/details/52368559

6. -eq 更多用于数值的比较,字符串比较使用 ==

参考: https://www.jb51.net/article/56559.htm

7. 与逻辑: && 或者 -a,或逻辑: || 或者 -o

参考: https://blog.csdn.net/iamlihongwei/article/details/59114828 https://www.cnblogs.com/aaronLinux/p/8340281.html

8. 判断命令行参数缺失

if [ -z $1 ];then
      echo "You should input one parameter"
fi

参考: https://blog.csdn.net/geoffreychan/article/details/77823505

9. ssh 远程执行命令

ssh需要直接用密码执行命令需要在本地安装 sshpass

sudo apt install sshpass
ip="192.168.1.2"
user="xyz"
pswd="123456"

sshpass -p ${pswd} ssh ${user}@${ip} "cd /home ; ls"

在远程执行的命令需要用双引号包含起来,不同命令需要用分号隔开。

或者类似下面也可以

#!/bin/bash
ssh user@remoteNode > /dev/null 2>&1 << remotessh
cd /home
touch abcdefg.txt
exit
remotessh
echo done!

<< remotessh 和 remotessh 之间的内容在远程执行,别忘了用 exit 退出 ssh。重定向在于不显示远程输出。

参考: https://blog.csdn.net/jinking01/article/details/84386769 https://www.cnblogs.com/kaishirenshi/p/7921308.html

10. 自动输入密码 需要先安装 expect,然后使用 expect 命令

expect <<EXPECT_EOF
spawn sudo smbpasswd -a xyz
expect "New SMB password:"
send "123456\r"
expect "Retype new SMB password:"
send "123456\r"
expect eof
EXPECT_EOF

或者:

expect -c "
       spawn sudo smbpasswd -a xyz
       expect {
              \"New SMB password:\" {set timeout 300; send \"123456\r\";}
          \"Retype new SMB password:\" {send \"123456\r\"}
    }
#expect eof"

expect eof 是和 spawn 配对使用的。 在 bash 中直接用 expect,有两种用法,1. expect <<EXPECT_EOF EXPECT_EOF 这样配对使用; 2. expect -c " " 这样双引号之间使用。 {send "yes\r"; exp_continue;} 这样的用法,exp_continue 表示这个 expect 的 内容和 send 内容可以重复多次使用。

参考: https://www.cnblogs.com/old-path-white-cloud/p/11678517.html https://www.cnblogs.com/sharktech/p/7454767.html https://blog.csdn.net/zhongbeida_xue/article/details/78679549

https://blog.csdn.net/weixin_34354173/article/details/91895917 https://blog.csdn.net/zhangjikuan/article/details/51105166 https://www.cnblogs.com/lixigang/articles/4849527.html https://www.cnblogs.com/autopenguin/p/5918717.html

https://www.cnblogs.com/taosim/articles/3785817.html https://www.linuxidc.com/Linux/2017-02/140365.htm https://developer.aliyun.com/article/512290 https://blog.csdn.net/dongqing27/article/details/83108877

11. yes 命令可以一直输入 yes,直到被 kill 掉。

mkdir test
touch test/test.txt

yes | rm -rf ./test

kill -9 $(pidof yes)

类似于上面这种写法。 参考: https://blog.csdn.net/yasi_xi/article/details/8562002 https://www.linuxcool.com/yes https://man.linuxde.net/yes https://www.cnblogs.com/jins-note/p/9636969.html

12. patch 需要先安装 patch 包。

首先先把文件复制出来,修改,然后用 diff 生成 patch 文件

cp /etc/samba/smb.conf ./
vim smb.conf
diff -c /etc/samba/smb.conf smb.conf > smb_conf.patch

diff -c 选项是详细信息。

patch /etc/samba/smb.conf smb_conf.patch

参考: https://www.cnblogs.com/cute/archive/2011/04/29/2033011.html

13. 使用 scp 发送数据到远程

sshpass -p ${pswd} scp ~/bin/smb_conf.patch ${user}@${ip}:/home/${user}

参考: https://www.runoob.com/linux/linux-comm-scp.html

14. sudo 自动输入密码

echo "admin" | sudo -S service tomcat7 stop

参考: https://blog.csdn.net/wangbole/article/details/17579463

15. 代码块的结束符 EOF 之类的一定要顶格写,不要有空格,否则会报错,类似下面这样:

chmod_file()
{
    echo "chmod file"
    # ssh remote and exec command
    sshpass -p ${pswd} ssh ${user}@${ip} <<EOF

    chmod 400 ./.ssh/id_rsa
    chmod 644 ./.ssh/id_rsa.pub

    exit
EOF
}

16. 简单的 yes no免输入交互

echo "y" | rm /mnt/speech/.ssh/id_rsa*

17. 数组

array_name=(value1 value2 ... valuen)
array_name=()
array_name[0]=value0
array_name[1]=value1
array_name[2]=value2

echo "第一个元素为: ${array_name[0]}"

echo "数组的元素为: ${array_name[*]}"
echo "数组的元素为: ${array_name[@]}"

echo "数组元素个数为: ${#array_name[*]}"
echo "数组元素个数为: ${#array_name[@]}"

参考: https://www.runoob.com/linux/linux-shell-array.html

18. shell for 循环遍历数组

a=("Fdf" "df" "fd")
for str in ${a[@]};do
echo $str
done

参考: https://blog.csdn.net/weiwjacsdn/article/details/80368666

19. 函数参数使用 $1, $2 这样的。

参考: https://www.runoob.com/linux/linux-shell-func.html

20. 字符串按照空格拆分为数组

STR="123 A1 A2"
ARR=($STR)
echo "${ARR[0]}:${ARR[1]}:${ARR[2]}

参考: https://blog.csdn.net/weixin_44687868/article/details/108379011

21. 数组作为参数传递,也必须使用 ${xyz[*]} 这样形式的。

参考: https://blog.csdn.net/mydriverc2/article/details/78931628

22. 数组作为参数通过命令行传递,两种方法,一种是直接多个参数,还有一种是使用 " 双引号把数组框起来。

参考: https://www.runoob.com/linux/linux-shell-passing-arguments.html

23. 判断是否以 某个字符开头,比如 [ 这样的数组。

if [[ $cases =~ ^\[.* ]]; then
    casesStr=`cat ${target_json} |jq .cases[]| sed 's/\"//g'`
    cases=($casesStr)
else
    cases=($cases)
fi
echo "cases: ==> $cases"

参考: https://www.cnblogs.com/LiuYanYGZ/p/12491673.html

24. 从 json 文件中读取使用 jq 命令,获取数值的时候,如果只是字符串,那么使用 jq .abc 这样,如果是数组,那么使用 jq .abc[]

cases=`cat ${target_json} |jq .cases| sed 's/\"//g'`
casesStr=`cat ${target_json} |jq .cases[]| sed 's/\"//g'`

参考: https://www.cnblogs.com/nul1/p/12228785.html#3%E8%BE%93%E5%87%BA%E6%95%B0%E7%BB%84%E7%9A%84%E5%80%BC

25. find 控制搜索深度 使用 -maxdepth 这个参数, 使用 -type d 表明搜索的是目录。

find  ./  -maxdepth 3 -type d 

参考: https://blog.csdn.net/lmmcu_2012/article/details/52703395

26. sed 可以用来替换字符, s/old/new/g 这样的方式即可。

casesStr=`cat ${target_json} |jq .cases[]| sed 's/\"//g'`

参考: https://www.runoob.com/linux/linux-comm-sed.html

1. pcm 是 ADC 直接采集到的数据。

2. frame,帧,指的是对所有声道进行一次 ADC 转换得到数据。

3. frame size,指的是一帧 包含的字节数。

如果是单声道,8bit adc,那么就是 1 8 / 8 = 1. 如果是8声道,16bit adc,那么就是 8 16 / 8 = 16.

4. rate 采样率,一秒对所有通道进行多少轮的采样,也就是一秒多少帧

5. data rate,这个就是 采样率 * 每帧字节数

6. period,每次处理 AD,DA 转换的间隔是周期。

内核可以缓冲很多周期的数据,每个周期都会生成一个中断和一个副本,用户层可以间隔很长时间再处理一次,一次可以处理多个周期的数据。

7. period size 这个数值指的是一个周期包含多少帧。

如果设置为 32,那么用户每次读写都是 32帧数据,或者0帧数据。

参考: https://larsimmisch.github.io/pyalsaaudio/terminology.html

1. 从 二进制 pcm 文件中读取数据,并转化位想要的矩阵数组

    with open(audioPath, 'rb') as f:
        audioData = np.fromfile(f, dtype = np.uint16)
    audioData.shape = -1, 8

转换的音频数据是 不确定行,8列数组。

2. 把矩阵转置,以单声道数据为行。

    audioData = audioData.T

转换为 8行的二维数组,每一行就是一个声道的数据。

3. 抽取一个通道的数据。

    ch1 = audioData[4]

4. 把这个通道的数据写入二进制文件

    ch1.tofile("./audio/ch1.pcm")

参考: https://blog.51cto.com/feature09/2316652 https://blog.csdn.net/Tourior/article/details/110791039 https://blog.csdn.net/kebu12345678/article/details/54837245 https://numpy.org/doc/stable/reference/generated/numpy.fromfile.html#:~:text=numpy.fromfile.%20%C2%B6.%20numpy.fromfile%28file%2C%20dtype%3Dfloat%2C%20count%3D-1%2C%20sep%3D%27%27%2C%20offset%3D0%29%20%C2%B6.,tofile%20method%20can%20be%20read%20using%20this%20function. https://www.cnblogs.com/peixu/p/7991715.html https://blog.csdn.net/botao_li/article/details/104378469 https://www.cnblogs.com/noluye/p/11224137.html

1. 使用命令 qmlscene 可以直接执行 qml 文件。

2. qml 中 quick 对应的版本

Qt QtQml QtQml.Models QtQuick QtQuick.Controls QtQuick.Layouts QtQuick.Dialogs QtQuick.Particles 4.7.1 1.0
4.7.4 1.1
5.0 2.0 2.0 2.0 5.1 2.1 2.1 2.1 1.0 1.0 1.0 2.0 5.2 2.2 2.1 2.2 1.1 1.1 1.1 2.0 5.3 2.2 2.1 2.3 1.2 1.1 1.2 2.0 5.4 2.2 2.1 2.4 1.3 1.1 1.2 2.0 5.5 2.2 2.2 2.5 1.4 1.2 1.2 2.0 5.6 2.2 2.2 2.5 1.5 1.3 1.2 2.0 5.7 2.2 2.2 2.7 2.0 1.3 1.2 2.0 5.8 2.2 2.2 2.7 2.1 1.3 1.2 2.0 5.9 2.2 2.2 2.7 2.2 1.3 1.2 2.0 5.10 2.2 2.2 2.7 2.3 1.3 1.3 2.0 5.11 2.11 2.11 2.11 2.4 1.11 1.3 2.11 5.12 2.12 2.12 2.12 2.5 1.12 1.3 2.12 5.13 2.13 2.13 2.13 2.13 1.13 1.3 2.13 … … … … … … … …

参考: https://beyondyuanshu.github.io/2019/11/19/qt-qml-quick-andsoon.html

3. 自定义标题栏和实现鼠标拖动

参考: https://blog.csdn.net/laughing_cui/article/details/74025206