matlab coder:.m转成c语言,并实现VS里实例运行,二维数组传递

搞科研的,尤其是搞图像的,大部分都比较熟练matlab,而不太会写c代码。
因此
我们需要
matlab代码转c代码

强调:如果你的程序有较多的matlab库里面没有公开的函数,那么那些函数是没办法转换的。

以下通过实例实现一幅图像的RGB转BRG

1.matlab coder

1)创建函数和用于运行函数的脚本

//main
clear
clc
img_name = '12345.jpg';
my_GBR(img_name);
//function
function [] = my_GBR(inputArg1)

I = imread(inputArg1);
g = I;

I(:,:,1) = g(:,:,2);
I(:,:,2) = g(:,:,3);
I(:,:,3) = g(:,:,1);

end

2.应用coder
这里有一点需要注意,在matlab中很多参数不需要提前开辟存储空间
但是c语言,每一个参数使用之前必须定义以开辟储存空间,尤其是数组
因此matlab代码中,如果你在for循环中用到了矩阵,那么要预先定义矩阵的大小
在这里插入图片描述
选择你要生成c代码的函数
在这里插入图片描述
点击next到输入定义,这里表示清楚输入,我们输入的是一个图像名称的字符串,因此为(1,:)
在这里插入图片描述
选择为函数设置的实例脚本
在这里插入图片描述
然后检查代码
在这里插入图片描述
在这里插入图片描述
其他不用配置,直接点生成就好
在这里插入图片描述
然后我们获得了c代码
在这里插入图片描述
3.创建项目
虽然我们得到了c代码,但是整体处于一盘散沙,没有工程文件,因此我们需要去生成工程文件
两种方法:
1)在vs里面创建工程,然后在工程文件中把c和h添加进去
2)用CMake生成
这里我们选用CMake

1)下载并安装CMake
https://cmake.org/download/
在这里插入图片描述
2)创建CMakeLists.txt
告诉CMake,工程的名字,以及包含的文件
在这里插入图片描述
文件的.c和.h都要包含进去,其实挺多的,我们可以用脚本,提取文件中所有文件的名字
创建一个txt文件,里面输入

@ECHO OFF
tree /F > 111111.txt

然后把.txt文件的后缀改为.bat
在这里插入图片描述
然后双击,生成111111.txt文件
在这里插入图片描述
然后把.h 和.c的文件名提取出来,用空格隔开(把main.h和main.c也包含过来同时把examples中的对应文件放到主目录下方便调试)
在这里插入图片描述
在这里插入图片描述
然后在CMakeLists.txt输入

cmake_minimum_required(VERSION 3.18.0)//需要的CMake版本最低值
project(matlabcoder)//项目的名称
add_executable(demo my_GBR.c my_GBR.h my_GBR_data.c my_GBR_data.h my_GBR_emxAPI.c my_GBR_emxAPI.h my_GBR_emxutil.c my_GBR_emxutil.h my_GBR_initialize.c my_GBR_initialize.h my_GBR_terminate.c my_GBR_terminate.h my_GBR_types.h rtwtypes.h main.c main.h)

打开 CMake程序,选定源文件夹和工程建立后的位置
在这里插入图片描述
在这里插入图片描述
如果上面的步骤成功了,你会看到生成的工程文件
在这里插入图片描述
双击sln文件,打开vs
在这里插入图片描述

2.在VS中调试

1)配置vs
右击demo,设置demo为启动项(如果你打开的界面和二郎的不一样,你可以打开资源管理器)
在这里插入图片描述
在这里插入图片描述
然后点击本地调试器,会看见少了文件
在这里插入图片描述
去matlab文件夹找到对应的.h,然后拷到工程文件夹
在这里插入图片描述
在这里插入图片描述
然后在txt中添加
在这里插入图片描述
之后重新生成。这里缺哪个,就去matlab中找哪个。
如果出现由于matlab库引起的无法解析的外部符号,可以去看我的上一篇博客

3.在VS配置输入
1)找到主函数,进入
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
将我们想要的输入放进来
在这里插入图片描述
我们试着运行一下,可以看到整体是没有问题的。
如果你希望这个输入在main函数中实现,那么你需要把输入作为参数,在函数中传递

例如:你要传递个矩阵(数组),那么你可以这样定义

#define N 5

static void men_RGB(double (*P)[N], int M);

void men_RGB(double (*P)[N], int M)
{
double A = P[2][1];
}

void main
{
double mat_image[][N] = {1,2,3,4,5,1,2,3,4,5,1,2,3,4,5};
//由于我们定义了矩阵的列,所有行数也就确定了,是一个3行5列的数组
int M = sizeof(mat_image)/sizeof(mat_image[0]);
men_RGB(mat_image, M);
}

这里用指针传递数组其实比较简单,而且也减少了内存的占用。
用指针来表示数组,只能指向数组头部,同时加上[N],可以指示有多少列。
但是并没有指示出有多少行。
因此在传递时,需要告诉其他函数,这个指针指向的数组有多少行,这样调用时就不会出错了。

在我们看来,指针指向了储存数组的一大片存储,但是,其实这一片存储不一定是连续的,这些就说来话长了,我们只需要知道此时指针指向的就是一大片。

我们来探讨一下,为什么要写成double (*P)[N]
1)二维数据是由多个一维数组组成
例如:double A[3][5];
它由三个一维数组组成:A[0];A[1];A[2]。(这里不用管为啥是行向量,因为c语言是这么定义的)

A[0]

A[1]

A[2]

又因为一维数组的数组名表示数组第一个元素的地址
因此,A[0] 等于 &A[0][0],即int* ddd = A[0];或者int* ddd = &A[0][0];ddd就指向了一维数组A[0]的首地址
*(ddd + 1)等于A[0][1]
*(ddd + 2)等于A[0][2]

2)一维数组的名为A[0],那么它的元素是A[0][0]、A[0][1]等。A[0]为数组第一个元素的地址——&A[0][0]
二维数组的名为A,那么它的元素是A[0]、A[1]、A[2]。A为数组第一个元素的地址——&A[0],即&&A[0][0]

所以这么看来,二维数组也挺简单的,取一次地址,即A[…],就可以找到一维数组了,再取一次地址,即A[…][…]就可以找到单个数了。

因此指针的指针是不是可以用来表示二维数组了???????

**p

int **P = A;

这样玩是有问题的,它和数组还是有些差别的。
其实大家有可能感觉出来,数组名有两个寓意
1)它是内部元素中首个元素的地址。
2)它暗含着自己有多少个元素的信息,这点非常重要,也是和指针区别的有效方式。(二维数组有mxn个元素,一维有n个元素)
因此
1)int **P指示一个指向指针的指针,不能和二维数组A画等号
但是
int (*P)[3] = A;
就可以了,即表示了首地址的信息,又告诉了A中有多少列。
(有时候只有列也行,数据填充时,能算出行数,赋值时也用过int A[][3] = {})

其实再具体一点,应该给出行的信息,于是

int (*P)[3] = A;加上A的行数,才能和二维数组A划等号

  • 13
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值