如何在Visual Studio中新建MB-System的I/O模块

本文实现了在windows平台下使用Microsoft Visual Studio Community 2022 (64 )构建MB-system的I/O模块项目,用于将国产声呐数据添加到MB-system的数据支持中去。

1:为啥要搞个Visual Studio的项目?

因为可以调试啊!!

起因是这样的,因为项目需要,针对某个国产的新型声呐传感器硬件开发处理软件,由于国产声呐数据的存储格式的特殊性,现有的商业多波束声呐处理软件是无法直接读取的,包括CARIS、Geocap、Trition、Echoview等都试过了,最终还是继续使用开源的MB-system。

MB-system是国内声呐研究常用的平台,标准C语言实现,代码可直接用于工程软件开发,在github上百星,让人吃惊的是这个项目目前2024年了,持续更新的频率还挺高,活力项目。

网址:https://github.com/dwcaress/MB-System

          https://www.mbari.org/technology/mb-system/

但令人dan疼的是,github上的MB-system软件建构仍然是CMake的。。。(虽然比更早的GNU Autotools)要通用点,但目前只用CMake构建这么大一个项目,太原始了。所以MB-system目前仍然只能在Linux系统上运行,且项目开发写代码主要靠文本编辑器与控制台输出,这让习惯了使用Visual Studio、VS code、Qt等平台开发的人员很难受。

有人尝试过MB-Sytem代码调试: MB-Sytem代码调试_mbsystem-CSDN博客

全靠控制台输出啊,MB-Sytem源码感觉有三分一的代码都是fprintf控制台输出。

能否使用makefile文件反向生成vc项目在windows下使用?简单尝试了一下发现很难,因为MB-system源码需要修改的地方太多。

最终决定只将MB-system中的MBio模块单独构建VC项目,用于开发新的国产声呐数据I/O模块,实践证明还是挺顺利的。

还是感慨与佩服老教授使用文本编辑器写MB-system标准c代码的水平,一把过。我不行。

2:使用MB-system中的MBio模块新建Visual Studio项目

用到的源码主要在MB-System-master\src\mbio文件夹下,但并不是全部,排除MB-system支持的数据类型,只保留官方说明文档的例子mbr_wasspenl,文件不算多。

调试用的文件在MB-System-master\src\utilities文件夹下,选择mbinfo.cc与mblist.cc两个就够了,包含main()函数用于调试。

打开Microsoft Visual Studio Community 2022 (64 )新建标准C++的空项目,手动添加下图中的文件。

项目配置很少,在“项目属性”--“C/C++”--”预处理器定义”中添加“_CRT_SECURE_NO_WARNINGS”。屏蔽一些警告报错。

修改代码:

首先修改mb_format.h与mb_format.c文件中涉及多源数据格式支持的内容,都注释掉,只保留了官方文档中的wasspenl样例。mb_format.h中注释掉的包括:

/* format registration function prototypes */

//int mbr_register_sbsiomrg(int verbose, void *mbio_ptr, int *error);

….

//int mbr_info_sbsiomrg(int verbose, int *system, int *beams_bath_max, int *beams_amp_max, int *pixels_ss_max, char *format_name,

//                      char *system_name, char *format_description, int *numfile, int *filetype, int *variable_beams,

//                      int *traveltime, int *beam_flagging, int *platform_source, int *nav_source, int *sensordepth_source,

//                      int *heading_source, int *attitude_source, int *svp_source, double *beamwidth_xtrack,

//                      double *beamwidth_ltrack, int *error);

….

mb_format.c中注释掉的包括:

  /* look for a corresponding format */

//  if (*format == MBF_SBSIOMRG) {

……

  /* look for a corresponding format */

//  if (*format == MBF_SBSIOMRG) {

……

然后修改一些linux下才有的头文件,使之兼容windows,比如:

#ifdef __linux__

#include <unistd.h>

#include <dirent.h>

#endif

#ifdef _WIN64

#include <direct.h>

#include <io.h>

#endif

其中有个linux下负责命令行调用参数检测的头文件getopt.h,这个windows上有替代文件。

VS2019使用getopt及getopt_long_vs添加getopt-CSDN博客

VS2019使用getopt及getopt_long_vs添加getopt-CSDN博客

下载getopt.h与getopt.c两个文件添加到项目中,然后将#include <getopt.h>修改为#include “getopt.h”。

用到调用外部第三方I/O库读取某些特殊格式文件,如XDR、SURF等,相关的代码段注释掉就行了,因为用不到,我这里给加上了麻烦点。投影相关的Proj我给去掉了,写IO我用不到投影转换,全部经纬度。Proj4库加上也不复杂。

剩余的的代码修改就很简单了,标准C的代码支持Windows容易。

控制台入口main函数使用mbinfo.cc或mblist.cc中的入口就行了,二选一,用一个main函数,剩下的一个可以先注释掉。成功生成解决方案后就可以命令行调用了,比如mbinfo的命令行参数:mbinfo -F 286 -I "D:\\work2024\\声纳图像\\多波束目标数据\\240\\广西北海_空D\\Target_19.hrms" -V 3

运行结果见下图:

Mbinfo函数调用了关键的mb_*_alloc()、mb_*_extract()函数。至此, 便可以在windows下用Vs工具写c代码加断点调试了。

剩下的工作就是对照官方文档写I/O函数。

3:使用HuMBsystem写I/O模块

下面介绍在MBsystem中添加新的声呐数据I/O支持代码。

先读MB-system的官方文档《Developer's Guide to Coding an MBSystem I/O Module》。官方文档中的范例新建一个I/O模块处理WASSP多波束声纳数据。

实际编程中更详细的函数接口说明在MB-system的源码目录下:MB-System-master\src\mbio\README.md。查询这个文档搞清楚关键mb_*_extract()函数的输出参数定义更重要。

网上也有人做过相同的工作,也很有启发:如何在MB-System中新建I/O模块:

如何在MB-System中新建I/O模块_mbsystem-CSDN博客

   

下面是自己的工作,同样按照官方文档的章节对应,作为备忘。

STEP 1 设立声纳系统名称、数据格式及ID

声纳系统的名称MB_SYS_HUHRMS

数据格式的名称限定8个字符:MBF_HUHRMS86 286

数据格式拥有唯一的ID,例如:#define MBF_HUHRMS86 286;

STEP 2 使用源码的模板构建新模块

     1.拷贝mbsys_templatesystem.h,重命名为:mbsys_huhrms.h;

   拷贝mbsys_templatesystem.c,重命名为:mbsys_huhrms.c;

   拷贝mbr_tempform.c,重命名为:mbr_huhrms86.c;

     2.在以上文件中进行全局替换:

   templatesystem-> huhrms

   TEMPLATESYSTEM-> HUHRMS

   tempform-> huhrms86

   TEMPFORM-> HUHRMS86

   我们将在以上三个文件中处理未知格式声纳文件。

STEP 3 定义存储新声纳数据结构体

      1.在mbsys_benthos.h中添加记录声纳数据的结构体: 这个结构体主要根据自己如何读取与存储声呐数据方便来决定,不用太考虑官方模板给的形式。因为最终MBsystem提取声呐数据有专门的函数接口mb_*_extract(),通过MBsystem定义的传参提取数据,而不是这里自己定义的结构体。

      2.虽然MBIO的结构体的通用项:int kind、double time_d、int time_i[7],MBIO模块中的函数mb_get_time()、mb_get_date()等与此相关联,但只要保证mb_*_extract()之类的函数输出参数正确即可,不必完全按照模板写,实际调用不到的。

      3. 虽然定义了多种数据类型:

MB_DATA_DATA--Survey data

    MB_DATA_NAV--Navigation data

MB_DATA_COMMENT--Comment string

  但目的也只是为了代码的整齐性,实际按照模板的例子对每种数据类型单独写数据IO是非常麻烦的,关键是mb_*_extract()之类的函数输出参数是不区分这几种类型的!所以建议不用区分,我把所有IO都写在MB_DATA_DATA类型里。然后在mbr_info_huhrms86()函数中将所有数据源都指向MB_DATA_DATA类型:

         *nav_source = MB_DATA_DATA; // nav:导航

         *sensordepth_source = MB_DATA_DATA;

         *heading_source = MB_DATA_DATA;

   *attitude_source = MB_DATA_DATA; //attitude:姿态

STEP 4 (a) mbr_xxx.c的初始化工作

     1.初始化:

    Mbr_register_xxx()、mbr_info_xxx()、mbr_dem_xxx()直接关联mb_read_init()及mb_write_init(); Mbr_dem_xxx()直接关联mb_close();

      2.mbr_registem_xxx()注册管理指针,使得mbr_xxx.c及mbsys_xxx.c中的各模块能由MBIO中更高级的I/O模块调用;

      3.mbr_xxx.c中主要处理数据的函数为:mbr_rt_xxx()(读)、mbr_wt_xxx()(写);

4.读写声呐文件过程中 init()与close()只在打开文件与关闭文件两端运行一次、而mbr_rt_xxx()(读)、mbr_wt_xxx()(写)两函数按照每个Ping进行一次读写,有多少Ping便调用多少次,直到读取结束,所以需要注意:在mbr_info_xxx()函数中为构建的结构体进行初始化赋值,在mbr_rt_xxx()(读)、mbr_wt_xxx()(写)就不要对结构体malloc了,如果非要申请内存,也要在函数退出前释放掉。

每个Ping的读写函数返回值注意坑:例如mbr_huhrms86_rd_data(),只有在文件最后一个Ping读取结束了才能返回status = MB_FAILURE;其它情况不管是读取成功还是中间某个Ping数据存在问题,都要返回status = MB_SUCCESS;因为只要返回MB_FAILURE了系统就停止继续读Ping了。

      5.文件访问方式:

         ①fopen()、fread()、fwrite()、fclose();

         ②(官方推荐)mb_fileio_open()、mb_fileio_read()、mb_fileio_write()、mb_fileio_close()

         但是我推荐还是使用①,因为官方的②只是将函数返回值变得复杂了,方便控制台输出调试用,其它优化是没有的,函数内部还是①的函数包装。。。用断点跟到函数内部看了一眼,还是直接调用①更省事,都可以用VS加断点调试了,还要用比fread()更啰嗦的函数输出专门的控制台调试信息???所以我写的很简单:

      

STEP 4(b)mbr_xxx.c中实现读写函数

一、1、主要的函数为mbr_rt_xxx()和mbr_wr_xxx()

            mbio_ptr:指向通过MBIO定义的读/写文件的mb_io structure

            store_ptr:指向primary data structure(通常在mb_io structure中获得);

      官方文档中,通过mbio_ptr与store_ptr指针对象记录所有的变量,希望用户在函数内部就不要再额外的定义变量与申请内存了,想法很好,但看看simrad等传感器的代码,老外为了方便也不是贯彻的很严格。其实只用mbio_ptr就足够了,还是同样的原因:关键的mbsys_xxx_extract()函数输出参数并不是mbio_ptr对象,而是具体的数据对象,下面详细说明。

STEP 5 在mbsys_xxx.c中构建数据接口

实现mbr_register_xxx()中注册的用于mbio_struct的接口,关键函数:mbsys_xxx_extract(),数据提取。直接贴官方说明最合适:

#### mb\_extract()

    int mb_extract(

         int verbose,

         char *mbio_ptr,

         char *store_ptr,

         int *kind,

         int time_i[7],

         double *time_d,

         double *navlon,

         double *navlat,

         double *speed,

         double *heading,

         int *nbath,

         int *namp,

         int *nss,

         char *beamflag,

         double *bath,

         double *amp,

         double *bathacrosstrack,

         double *bathalongtrack,

         double *ss,

         double *ssacrosstrack,

         double *ssalongtrack,

         char *comment,

         int *error);

The  function mb\_extract extracts sonar data from the structure pointed

to by \*store\_ptr  according  to  the  MBIO  descriptor  pointed  to  by

mbio\_ptr.   The  verbose  value controls the standard error output ver-

bosity of the function.  The form of the data structure  is  determined

by  the sonar system associated with the format of the data being read.

A number of different data record types are  recognized  by  MB-System;

the  kind value indicates which type of record is stored in \*store\_ptr.

Additional data is returned if the data record is survey data  (naviga-

tion, bathymetry, amplitude, and sidescan), navigation data (navigation

only), or comment data (comment only).

The return values are:

* kind:          kind of data record read

    * 1    survey data

    * 2    comment

    * 12   navigation

* time\_i:        time of current ping

    * time\_i[0]: year

    * time\_i[1]: month

    * time\_i[2]: day

    * time\_i[3]: hour

    * time\_i[4]: minute

    * time\_i[5]: second

    * time\_i[6]: microsecond

* time\_d:        time of current ping in seconds since 1/1/70 00:00:00

* navlon:        longitude

* navlat:        latitude

* speed:         ship speed in km/s

* heading:       ship heading in degrees

* distance:      distance along shiptrack since last ping in km

* altitude:      altitude of sonar above seafloor in m

* sonardepth:    depth of sonar in m

* nbath:         number of bathymetry values

* namp:          number of amplitude values

* nss:      number of sidescan values

* beamflag:      array of bathymetry flags

* bath:          array of bathymetry values in meters

* amp:      array of amplitude values in unknown units

* bathacrosstrack:    array of of acrosstrack distances in meters corresponding to bathymetry

* bathalongtrack:     array of of alongtrack distances in meters corresponding to bathymetry

* ss:       array of sidescan values in unknown units

* ssacrosstrack: array of of acrosstrack distances in meters corresponding to sidescan

* ssacrosstrack: array of of alongtrack distances in meters corresponding to sidescan

* comment:  comment string

* error:         error value

A status value indicating success or failure  is  returned;  the  error

value  argument  error  passes  more detailed information about extract

failures.

确保每个输出参数的正确定义,就能保证导入数据的正确,如果读取的原始数据与给出的输出参数定义不一致 ,就需要在函数内部完成转换与计算。例如:

模板中的函数接口根据需要完成,并不一定要写完全部,最终实现的函数接口包括:

STEP 6 将新构建的I/O模块集成与MBIO中:

     1.信息I/O模块构建完成后,应在以下文件中修改信息:mb_format.h、mb_format.c,以将新的模块导入MBIO库中;

     2.声纳名称定义于mb_format.h中,如: #define MB_SYS_HUHRMS 41

     3.声纳数据格式及其ID定义于mb_format.h中,如:#define MBF_HUHRMS86 286

函数mbr_register_xxx()及mbr_info_xxx()在mb_format.h中定义;

int mbr_register_huhrms86(); //akaishi

int mbr_info_huhrms86();//akaishi

     5.新格式的引用必须要在mb_format.c中的mb_format_register()、mb_format_info()、mb_get_format()中进行声明,添加的部分比着其它数据格式复制粘贴即可。(添加的部分也是之前构建vs项目时mb_format.h与mb_format.c文件中注释掉的部分)

至此新添加的I/O支持代码完成,使用mbinfo.cc中的main函数加断点调试吧,Microsoft Visual Studio太好用了。在windows平台上运行正确的话,再拿到linux系统上更新MB-system就没问题了。

更新完的I/O包括五个文件夹:

将以上5个文件拷贝到MBsystem源码安装的linux系统源码下的MB-System-master\src\mbio文件夹下重新构建安装就能生效了。以下介绍linux端的操作。

PS:注意拷贝到linux下的mb_format.h、mb_format.c两个文件中之前注释掉的其它格式注册代码需要先恢复,否则其它格式就失效了。

STEP 7 更新MB-System的编译配置文件

在mbsystem/src/mbio/Makefile.am中声明新模块

    添加:include_HEADERS += mbsys_huhrms.h

        libmbio_la_SOURCES += mbr_huhrms86.c

        libmbio_la_SOURCES += mbsys_huhrms.c 2、重新编译。

    重新编译:

重新编译前需要更新整个项目的makefile.in文件:

     cd MB-System-5.8.1

     make uninstall

     make clean

     libtoolize --force --copy

     aclocal

      如果提示版本太低,需要更新:

     curl -O http://mirrors.kernel.org/gnu/autoconf/autoconf-2.71.tar.gz

      cd到解压路径下:./configure  然后  make  然后 make install  检查版本

     autoheader

     automake --add-missing --include-deps

     autoconf

     autoupdate

     autoreconf --force --install --warnings=all

     此时项目的makefile 与 makefile.in文件都已经自动更新完毕,可以正常重新编译了

    ./configure --enable-mbtrn --enable-mbtnav

     export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH

     LDFLAGS="-Wl,-rpath -Wl,/usr/local/lib" \

       ./configure --enable-mbtrn --enable-mbtnav

     make

     sudo make install

MBsystem支持新格式见下图:

 

最后遇到的坑:

在windows上运行没问题的I/O代码,集成到linux系统后读入数据全是错的,只能使用命令行参数-V 5的方式查看控制台输出,发现了大坑是long类型在linux64占8位,而在windows下占4位。

long 在不同操作系统下所占用的字节数

所以不要单独使用long,要使用long long,或者只用int。

参考资料:

[1]mbcookbook.pdf  https://www.mbari.org/wp-content/uploads/2016/03/mbcookbook.pdf

[2] https://github.com/dwcaress/MB-System

[3]Mb-system的安装:  Mb-system的安装_mbsystem-CSDN博客

[4]如何在MB-System中新建I/O模块:如何在MB-System中新建I/O模块_mbsystem-CSDN博客

[5] MB-Sytem代码调试: MB-Sytem代码调试_mbsystem-CSDN博客

  • 30
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值