STM32F429+LTDC+卷积

一、缘起

因为之前想要DIY自己的开发板,还好死不死选择了STM32的,没办法也只能头铁的继续下去了,主要是:SDRAM,TF卡,7寸电容触摸屏,OV相机,百兆网口及COM口以便满足常规的应用需求,所有单功能测试已经完成,但是在功能集成的时候EMC严重干扰,而且也不知道自己哪来的自信,还打了个两层板的样,想降低一下开发成本,奈何想法很美好,现实很骨感!

二、调试及踩坑记录

一开始的时候发现点亮还是很开心的,但是随即各种问题也是让人无语。

1.显示不全问题,不知道是不是我买的这块屏幕独有的问题,总之工作在低频下侧边总有300个像素左右的宽度区域是黑的无法点亮,一开始以为是宽高方向设置错了了,各种配置比较,奈何网上大部分都是5寸屏,有7寸屏的也都是比较不出点什么,手上也没有其他电容屏测试,所以只能硬着头皮瞎猜调试,不过最后直觉使然下,居然尝试配置成高频模式下直接过了。当真是惊呆了,然后随之而来的问题

2.EMC,一开始的时候直接是通过硬件图层管理直接刷的原图,显示出来的效果和原图的色彩相差实在太大了,当时就懵圈了,后来仔细一想索性就做个猜想测试,将原图RGB三通道拆离分别一个通道一个通道的画到LCD 上去,一看问题就出来了。

WeChat_20230313191744

只有R通道时正常的,其他两个通道简直不忍直视了,实际如上面的视频也已经展示出了问题。

3.OV相机问题,EMC严重,已经可以成像,但是成像色彩严重偏差,几乎只有黑白两色,呈现轮廓明显存在畸变(暂时也没时间处理)

以上剩余问题需要重新设计PCB打样测试了。毕竟没有专业设备,也只能是边猜边解决了。也不知道EMC源头在哪,哎,无奈,SO 与此同时就顺便搞下软件上的进度。

毕竟是DIY自己的开发板,那同样的也要配套自己的软体系统

三、系统开发

1.RTOS:网上到处都是,有原理,有代码的,不过不怎么喜欢各种宏的条件编译,所以动手手撸一个吧,CPU Poll 切片多任务,满足基本应用要求。

2.文件系统,FAT32首选,不过据说存在删除回收的BUG,所以也是花了一个星期了解了一下FAT32长/短文件名规则及内容获取,手撸了一个半成品,从TF中读取文件及内容的功能。

写入、删除功能暂时不考虑,文件直接通过WIN系统存储进去就可以了,自己这边只是读一下处理。

3.主要应用任务,毕竟心血来潮之后总得让它跑起点什么,那么就从CNN入手,虽然只有180M主频32Mb内存,跑个CNN 是绰绰有余但是速度性能效率也不知道会怎么样。而且麻雀虽小但也得要五脏俱全吧。

四 、CNN及调试与记录

这也是目前要处理的重点了:所以为了方便开发和调试最终还是选择了WINDOWS及VS开发

CNN 卷积神经网络 网上一搜也是各种资料就不赘叙了、包括怎么卷,我们要做的只是代码实现而已。

目前初步 单步卷积,均值/最大值 池化,Relu激活函数,相当于是单层卷积已经完成,不过因为初步需要测试所以没有对图像大小做限制处理,边距操作也没有加入,以下代码,目前只是笔者初步测试,仅在以下的测试图片上完成,其他图片测试可自行调试修改

核心代码及测试代码,测试卷积核,以及测试效果如下,opencv 辅助读取一下图片,因为在window平台只是方便调试及测试,所以核心代码都采用 C 基础风格及语法处理,方便后面直接集成进自己的硬件上。

#define		MAXCHANNELCOUNT				3

typedef struct _inkpps {
	unsigned Width;
	unsigned Height;
	unsigned char Channel;
	unsigned char *pDatas[MAXCHANNELCOUNT];
}inkPicParam;

inkPicParam PicDataGet(char *path) {
	inkPicParam pp = { 0 };
	Mat in = imread(path);
	unsigned size = in.cols * in.rows;
	if (!in.empty() && size > 0) {
		pp.Width = in.cols;
		pp.Height = in.rows;
		pp.Channel = in.channels();

		int xd = in.depth();

		for (unsigned x = 0; x < MAXCHANNELCOUNT; x++)
			pp.pDatas[x] = (unsigned char *)malloc(size);
		size *= pp.Channel;
		IkrvPicChannelSplit((char *)in.data, size, pp.pDatas);
	}
	return pp;
}

void Release(inkPicParam *pp) {
	for (unsigned m = 0; m < MAXCHANNELCOUNT; m++) {
		if (pp->pDatas[m] != 0)
			free(pp->pDatas[m]);
	}
	memset(pp, 0, sizeof(inkPicParam));
}
int main()
{

	inkPicParam ipp = PicDataGet("../testBMP/test.jpg");

	//横线卷积核
	char rkconv[3][3] = {
		{1,1,1},
		{0,0,0},
		{-1,-1,-1}
	};

	//竖线卷积核
	char ckconv[3][3] = {
		{ 1,0,-1 },
		{ 1,0,-1 },
		{ 1,0,-1 }
	};

	char nkconv[3][3] = {
		{-1,-1,-1},
		{-1,8,-1},
		{-1,-1,-1}
	};

	char xkconv[3][3] = {
		{1,2,1},
		{2,4,2},
		{1,2,1}
	};


	inkScPicParam iscp = { 0 };
	char *k = 0;



	k = rkconv[0];
	iscp.pDatas = ipp.pDatas[0];
	iscp.Width = ipp.Width;
	iscp.Height = ipp.Height;
	IkrvCnnConvolution(&iscp, &k, 3);
	//inkCnnPool(INK_AVERPOOL, &iscp, 4);
	Mat tc1(iscp.Height, iscp.Width, CV_MAKETYPE(CV_8U, 1), iscp.pDatas, iscp.Width * 1);
	imwrite("../testBMP/tc1.jpg", tc1);


	k = ckconv[0];
	iscp.pDatas = ipp.pDatas[1];
	iscp.Width = ipp.Width;
	iscp.Height = ipp.Height;
	IkrvCnnConvolution(&iscp, &k, 3);
	//inkCnnPool(INK_AVERPOOL, &iscp, 4);
	Mat tc2(iscp.Height, iscp.Width, CV_MAKETYPE(CV_8U, 1), iscp.pDatas, iscp.Width * 1);
	imwrite("../testBMP/tc2.jpg", tc2);


	k = nkconv[0];
	iscp.pDatas = ipp.pDatas[2];
	iscp.Width = ipp.Width;
	iscp.Height = ipp.Height;
	IkrvCnnConvolution(&iscp, &k, 3);
	//inkCnnPool(INK_AVERPOOL, &iscp, 4);
	Mat tc3(iscp.Height, iscp.Width, CV_MAKETYPE(CV_8U, 1), iscp.pDatas, iscp.Width * 1);
	imwrite("../testBMP/tc3.jpg", tc3);

	Release(&ipp);
	return 0;
}
void IkrvCnnConvolution(inkScPicParam *inPpOut, char **ckd, unsigned char kDimension) {
	unsigned ki = 0, sCuri = 0;
	unsigned sSize = 0, nd = 0;
	unsigned sr = 0, sc = 0;
	unsigned srcw = inPpOut->Width;
	short sumval = 0;
	if (kDimension % 2 != 0) {
		nd = (kDimension - 1);
		inPpOut->Height = (inPpOut->Height - nd);
		inPpOut->Width = (inPpOut->Width - nd);
		ki = 0;
		sSize = inPpOut->Height * inPpOut->Width;
		for (unsigned x = 0; x < sSize; x++)
		{
			sumval = 0;
			sr = x / inPpOut->Width;
			sc = x % inPpOut->Width;
			for (unsigned kh = 0; kh < kDimension; kh++) {
				for (unsigned kw = 0; kw < kDimension; kw++) {
					ki = kh * kDimension + kw;
					sCuri = (sr + kh)*srcw + (sc + kw);
					sumval += (inPpOut->pDatas[sCuri] * (*ckd)[ki]);
				}
			}
			inPpOut->pDatas[x] = Relu(sumval / (kDimension * kDimension));
		}
	}
}

测试一下,将原图拆成三个通道,分别采用三个不同的卷积核卷(上面代码中的卷积核)下,测试效果如下:

 

 

 在横竖线的卷积核对应的结果图像下特征也是显然明显的。

五、后续

接下去,就是最终的全连接层以及分类器了,等后面有时间继续更新。

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值