二、图像数据的处理
思路:
- OV2640组件的完善
- rgb565数据转灰度图
- 双线性插值算法压缩图片
1.OV2640组件的完善
RT-THREAD提供了对摄像头OV2640的组件支持,我们在RT-THREAD SETTINGS中设置开启OV2640
尝试编译会发现失败,6errors,2warnings
查看报错我们可以发现是因为有类型未被定义
打开stm32h7xx_hal_conf.h查看没有打开的宏定义
打开DCMI、JPEG的宏
此时编译虽然不报错,但还有程序上的欠缺,RT-THREAD的OV2640组件是没有DMA中断的,需要加一句代码(见后文),然后是要手动写一个初始化程序配置OV2640的各个引脚
找到drv_ov2640.c和drv_dcmi.c
dcmi初始化中加入标识出的代码
void ov2640_pin_init(void)
{
/*
* SCL PH15 127
* SDA PH13 125
*
* D0 PH9 121
* D1 PH10 122
* D2 PG10 106
* D3 PG11 107
* D4 PH14 126
* D5 PI4 132
* D6 PI6 134
* D7 PI7
* HSYNC PH8 120
* VSYNC PI5 133
* PCLK PA6 6
*
* PWON PC7 39
* RESET PC6 38
*/
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_DCMI_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOG_CLK_ENABLE();
__HAL_RCC_GPIOI_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_Initure.Pin = GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_14 | GPIO_PIN_8;
GPIO_Initure.Mode = GPIO_MODE_AF_PP;
GPIO_Initure.Pull = GPIO_NOPULL;
GPIO_Initure.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_Initure.Alternate = GPIO_AF13_DCMI;
HAL_GPIO_Init(GPIOH, &GPIO_Initure);
GPIO_Initure.Pin = GPIO_PIN_10 | GPIO_PIN_11;
GPIO_Initure.Mode = GPIO_MODE_AF_PP;
GPIO_Initure.Pull = GPIO_NOPULL;
GPIO_Initure.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_Initure.Alternate = GPIO_AF13_DCMI;
HAL_GPIO_Init(GPIOG, &GPIO_Initure);
GPIO_Initure.Pin = GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7;
GPIO_Initure.Mode = GPIO_MODE_AF_PP;
GPIO_Initure.Pull = GPIO_NOPULL;
GPIO_Initure.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_Initure.Alternate = GPIO_AF13_DCMI;
HAL_GPIO_Init(GPIOI, &GPIO_Initure);
GPIO_Initure.Pin = GPIO_PIN_6;
GPIO_Initure.Mode = GPIO_MODE_AF_PP;
GPIO_Initure.Pull = GPIO_NOPULL;
GPIO_Initure.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_Initure.Alternate = GPIO_AF13_DCMI;
HAL_GPIO_Init(GPIOA, &GPIO_Initure);
GPIO_Initure.Pin = GPIO_PIN_6 | GPIO_PIN_7;
GPIO_Initure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_Initure.Pull = GPIO_PULLUP;
GPIO_Initure.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_Initure.Alternate = 0x00;
HAL_GPIO_Init(GPIOC, &GPIO_Initure);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7, GPIO_PIN_RESET);
}
你可以将这个函数设置为自动初始化,也可以在ov2640_init里将它调用
2.rgb565数据转灰度图
准备工作完成,现在将RGB565图像转为灰度,思路就是先将其填充转变为RGB888,然后用灰度公式转为灰度
rgb565_len = 320*240;
if (rgb565_len)
{
for(i=0;i<240;i++)
{
for(j=0;j<320;j++)
{
B = (*p)&0x1f;
G = (*p>>5)&0x3f;
R = (*p>>11)&0x1f;
B = B<<3;//*8
G = G<<2;//*4
R = R<<3;//*8
Gray= (rt_uint8_t)( (R*38 + G*75 + B*15) >> 7);//7位精度,测试效果最佳
dest[i][j]=Gray;
p++;
}
}
ifperson_app(dest);//进一步处理以及最终判决函数
}
3.双线性插值算法压缩图片
之前说过,为了简化模型,我们的模型入口参数是5050的u8,需要我们将输入的320240的图片压缩成50*50进行输入,这需要用到双线性插值算法
将二维数组压缩
/*
* 简述:该函数将320X240图像数组用算法缩小并输出50X50的图像数据
* 参数:320X240的数组输入,50X50的数组输出
*/
void Bilinear_interpolation_algorithm(rt_uint8_t array_in_320X240[][320],rt_uint8_t array_out_50X50[][50])
{
rt_uint16_t i_in,j_in,i_out,j_out;
float Px,Py;
float R2,R1;
for(j_out=0;j_out<50;j_out++)
{
Py=((float)j_out+0.5)*scaling_y-0.5;//计算纵坐标
j_in=(rt_uint16_t)Py;
//经计算320*240->50*50不需要判断边界
for(i_out=0;i_out<50;i_out++)
{
Px=((float)i_out+0.5)*scaling_x-0.5;
i_in=(rt_uint16_t)(((float)i_out+0.5)*scaling_x-0.5);//计算横坐标
R2=((float)i_in+1.0-Px)*array_in_320X240[j_in][i_in]+(Px-i_in)*array_in_320X240[j_in][i_in+1];//计算R2的灰度值
R1=((float)i_in+1.0-Px)*array_in_320X240[j_in+1][i_in]+(Px-i_in)*array_in_320X240[j_in+1][i_in+1];
array_out_50X50[j_out][i_out]=(rt_uint16_t)((Py-j_in)*R1+(j_in+1-Py)*R2);
}
}
}
其实这个函数可以进一步封装,变为任意格式的图像输入,任意格式的缩放输出,大致实现与上面的320240转5050相同.至此,图像数据处理部分结束,下一章写一下红外遥控部分在RT-THREAD系统中遇到的一些问题以及解决