TQ2440 基于V4L2编程框架的 LCD实时显示(下)

绪上一篇:

本次实验为基于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,这个代码已经完成

三、所遇问题

现在不知如何解决图像正确显示问题。。。。

   

TQ2440 基于V4L2编程框架的 LCD实时显示(下)_第1张图片

/*****************************************以上是上一次遇到的并停下的问题***************************************************************/

最新情况:

又经过了一个多星期,应该说放了一个多星期,就在前天突然在韦东山老师的第三个项目中找到的可以相关代码,然后参考其实现代码,我在原来的基础上改了图片显示的方式。

之前由于摄像头采集到的图像像素为320*240,而lcd显示屏像素为480*272,因此采集到的图像像素和显示屏像素是不相等的。当时,我的想法是直接在lcd上从fb0的映射地址起始处写入数据,然后就出现了之前出现的三个一个屏三个窗口的结果。无奈之下,我就想就参考下韦东山老师项目中的居中显示吧,没想到一试竟然马上成功了。如下图所示。

TQ2440 基于V4L2编程框架的 LCD实时显示(下)_第2张图片

 

然后仔细看代码,以及修改了一些代码进行测试,终于找出了以前困扰我许久的显示问题:为什么会出现三个或多个窗口?

原来我之前是吧一张像素为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实时显示了。

TQ2440 基于V4L2编程框架的 LCD实时显示(下)_第3张图片

以下是部分核心代码:


/*
*函数功能:图像处理并显示
*/
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 

 

工程源码下载:http://download.csdn.net/download/chasing_chasing/9947863

 

你可能感兴趣的:(linux学习)