本次实验为基于V4L2框架,使用USB摄像头进行图像采集,用4.3寸LCD屏进行实时显示。由于,知识缺乏未能完整的进行下去,失败在图像实时显示上面,因为要放一段时间,所以在此做次记录,希望能帮助到一些小伙伴,站在前人的路上把该问题解决掉。
1、使用TQ2440开发板、4.3寸TFT LCD屏,分辨率为480*272 16bpp
2、普通USB摄像头,采集的图像格式为YUV422,分辨率为320*240
1、USB摄像头可以进行图片采集,但在lcd显示时不能全屏显示,只显示lcd屏上面一半,且出现三个窗口暂时不知怎么解决
2、摄像头采集的图片为YUV422格式要在LCD屏显示需要转成RGB565格式,这个已经完成
3、由于二十多块买的摄像头其分辨率320*240,需要将其放大到480*272,这个代码已经完成
三、所遇问题
现在不知如何解决图像正确显示问题。。。。
/*****************************************以上是上一次遇到的并停下的问题***************************************************************/
又经过了一个多星期,应该说放了一个多星期,就在前天突然在韦东山老师的第三个项目中找到的可以相关代码,然后参考其实现代码,我在原来的基础上改了图片显示的方式。
原来我之前是吧一张像素为320*240的图像,将其数据从其buf[0]->buf[Max_size]一股脑的直接写入fb映射的显存中去,而没有分行分行的去显示所采集图像的内容,这就导致原本下一行的像素数据直接填充到了这一行,这样自然会出现这些错位,多窗口的现象。
memcpy(fb_addr,buf[index].start,buf[index].length) //这是错误的,将导致一开始的多窗口效果
for (i = 0; i cHeight; i++) //camdev->cHeight为采集到的图像高度
{
//这里每次只拷贝一行的像素数据
memcpy(pucDst, pucSrc, camdev->cLineBytes);
pucSrc += camdev->cLineBytes;//到下一行取数据
pucDst += myfb->iLineBytes;//到下一行显示
}
修改代码后便可正常显示。下面这张截图是320*240像素放大到480*272像素的图像显示效果,图像放大,采用了最近邻插值法,这是最简单,但效果最不好的一种方法,所以图片会有点模糊,但已经可以完成由摄像头采集图像信息,并在lcd实时显示了。
/*
*函数功能:图像处理并显示
*/
void display_pic(Cam_dev *camdev,Fb_dev *myfb)
{
struct v4l2_buffer buf;
unsigned char* ptmp;
unsigned long i,j;
CLEAR (buf);
buf.memory = V4L2_MEMORY_MMAP;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
/*取出一缓冲帧*/
if (-1 == ioctl(camdev->cfd, VIDIOC_DQBUF, &buf))
{
printf(" VIDIOC_DQBUF error!\n");
exit(-1);
}
/*检查缓冲帧是否有效*/
assert(buf.index < 4);
/*图片格式转换:YUV422->RGB565*/
ptmp = (unsigned char*)buffers[buf.index].start;
Pyuv422torgb565(ptmp,camdev->displaybuf,camdev->cHeight,camdev->cWidth);
/*图像放大后LCD显示*/
PicZoomF(camdev,myfb);
/*小图像居中显示*/
//PicMerge(camdev,myfb);
if (-1 == ioctl(camdev->cfd, VIDIOC_QBUF, &buf))
{
printf("VIDIOC_QBUF error!\n");
exit(-1);
}
}
/*
*函数功能:居中显示小的图像
*/
int PicMerge(Cam_dev *camdev,Fb_dev *myfb)
{
int i;
int iX,iY;
unsigned char *pucSrc;
unsigned char *pucDst;
iX = (myfb->iWidth -camdev->cWidth )/2;
iY = (myfb->iHeight -camdev->cHeight )/2;
//指向yuv422->RGB565转换后的图像起始位置
pucSrc = camdev->displaybuf;
//计算空出来的起始的空格
pucDst = myfb->fb_addr + iY * myfb->iLineBytes + iX *myfb->iBpp/8;
for (i = 0; i cHeight; i++)
{
//这里每次只拷贝一行的像素数据
memcpy(pucDst, pucSrc, camdev->cLineBytes);
pucSrc += camdev->cLineBytes;//到下一行取数据
pucDst += myfb->iLineBytes;//到下一行显示
}
return 0;
}
/*
*函数功能:进行图像缩放并显示
*/
int PicZoomF(Cam_dev *camdev,Fb_dev *myfb)
{
unsigned long dwDstWidth = myfb->iWidth; //LCD一行像素宽度
unsigned long* pdwSrcXTable;
unsigned long x;
unsigned long y;
unsigned long dwSrcY;
unsigned char *pucDest;
unsigned char *pucSrc;
unsigned long dwPixelBytes =myfb->iBpp/2; //每个像素字节数
//创建了放一行像素的空间
pdwSrcXTable = malloc(sizeof(unsigned long) * dwDstWidth);
if (NULL == pdwSrcXTable)
{
printf("malloc error!\n");
return -1;
}
//生成表 pdwSrcXTable
for (x = 0; x < dwDstWidth; x++)
{
pdwSrcXTable[x]=(x*camdev->cWidth/myfb->iWidth);
}
//进行列的缩放
for (y = 0; y < myfb->iHeight; y++)
{
dwSrcY = (y * camdev->cHeight / myfb->iHeight);
//目标图像的第x行起始地址
pucDest = myfb->fb_addr + y*myfb->iLineBytes;
//原始图像的第x行起始地址
pucSrc = camdev->displaybuf + dwSrcY*camdev->cLineBytes;
for (x = 0; x