目标:使用OV5640进行二值化处理,实现平衡小车的自动寻迹。获取源代码请点击=>OV5640-二值化-摄像头寻迹
首先我们使用的是如下的摄像头模组。
在某宝上购买后,发现驱动代码使用的是DCMI(摄像头接口)的DMA总线协议进行数据传输。
DCMI_DMA_Init((u32)&LCD->LCD_RAM,1,DMA_MemoryDataSize_HalfWord,DMA_MemoryInc_Disable);//DCMI DMA配置
为了进行图像二值化,首先我们需要获取图像信息,在配套的驱动代码中寻找,发现DMA总线上数据为8位,采用了8个IO进行并行数据传输,通篇无法找到我们可以利用的图像数组。
一、获取图像信息和二值化
经过一番查阅了解到DMA总线是一种系统总线,CPU通过它直接和外部设备进行通信,通信中使用中断方式。看到这里,想必大家也明白了了吧,也就是说,图像数据无法被外界直接获取,它是在CPU内部传输的,所以,我们选择间接获取数据。
使用DMA总线进行图像数据传输,最终还是要显示的,所以我们从这里入手,在原子哥的STM32程序中,我们找到了LCD屏的打点函数和读点函数。
在lcd.h文件中我们找到了如下两句:
void LCD_Fast_DrawPoint(u16 x,u16 y,u16 color);//快速画点
u16 LCD_ReadPoint(u16 x,u16 y);//读点
通过上面的LCD_ReadPoint(u16 x,u16 y)函数,我们可以轻松地获取到图像中某像素点的颜色,通过扫描整个图像,获取所有的图像信息。通过LCD_Fast_DrawPoint(u16 x,u16 y,u16 color)函数,我们可以在LCD屏幕上输出我们设定阈值的二值化图像。
整个原理就这么简单,接下来我们进行实际操作:
将读点函数直接放在主函数中时,我们发现这时LCD屏上图像发生乱码,显然这样操作影响了原来DMA的正常传输,所以,我们需要在读点之前将DMA关闭,而且图像数据必须完整,因此正确的操作是:DMA读取一帧数据->中断中关闭DMA->读取图像点位数据->重新开启DMA。
//DCMI中断服务函数
void DCMI_IRQHandler(void)
{
if(DCMI_GetITStatus(DCMI_IT_FRAME)==SET)//捕获到一帧图像
{
DCMI_ClearITPendingBit(DCMI_IT_FRAME);//清除帧中断
DCMI_Stop();
}
}
DCMI_Start(); //启动传输
完成上述操作后,我们得到了16位的颜色数据
//画笔颜色
#define WHITE 0xFFFF
#define BLACK 0x0000
这时我们只需要根据我们的需求设定阈值就可以将颜色数据二值化为黑白。
二、提高图像帧率
本来到这里就结束了,但是在使用过程中发现经过这样一系列操作后,摄像头输出图像的帧率降得很低,要提高实际帧率,有两个办法,一是降低图像分辨率,而是修改OV5640的配置文件,让它输出更高的帧率。
由于OV5640配套驱动代码中OV5640图像输出和显示和LCD屏的配置有关,所以这里我们直间修改lcd.c中的配置,原来240x320的分辨率变为了60x80的分辨率。
接着我们修改帧率,修改ov5640cfg.h文件中0x3035和0x3036的值为0x21和0xac(50帧)。
这样利用OV5640进行图像处理和二值化操作的目标就基本实现了。