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,这个代码已经完成

三、所遇问题

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

   

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

最新情况:

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

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

 

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

原来我之前是吧一张像素为320*240的图像,将其数据从其buf[0]->buf[Max_size]一股脑的直接写入fb映射的显存中去,而没有分行分行的去显示所采集图像的内容,这就导致原本下一行的像素数据直接填充到了这一行,这样自然会出现这些错位,多窗口的现象。

   以前的代码:

memcpy(fb_addr,buf[index].start,buf[index].length)    //这是错误的,将导致一开始的多窗口效果

   修改之后:

for (i = 0; i <camdev->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 <camdev->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 <dwDstWidth; x++)
        {
            /* 原图座标: pdwSrcXTable[x],srcy
             * 缩放座标: x, y
*/
memcpy(pucDest+x*dwPixelBytes, pucSrc+pdwSrcXTable[x]*dwPixelBytes, dwPixelBytes);
        }
    }


    free(pdwSrcXTable);
return 0;
}

 

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

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
2022 / 01/ 30: 新版esptool 刷micropython固件指令不是 esptool.py cmd... 而是 esptool cmd... 即可;另外rshell 在 >= python 3.10 的时候出错解决方法可以查看:  已于2022年发布的: 第二章:修复rshell在python3.10出错 免费内容: https://edu.csdn.net/course/detail/29666 micropython语法和python3一样,编写起来非常方便。如果你快速入门单片机玩物联网而且像轻松实现各种功能,那绝力推荐使用micropython。方便易懂易学。 同时如果你懂C语音,也可以用C写好函数并编译进micropython固件里然后进入micropython调用(非必须)。 能通过WIFI联网(2.1章),也能通过sim卡使用2G/3G/4G/5G联网(4.5章)。 为实现语音控制,本教程会教大家使用tensorflow利用神经网络训练自己的语音模型并应用。为实现通过网页控制,本教程会教大家linux(debian10 nginx->uwsgi->python3->postgresql)网站前后台入门。为记录单片机传输过来的数据, 本教程会教大家入门数据库。  本教程会通过通俗易懂的比喻来讲解各种原理与思路,并手把手编写程序来实现各项功能。 本教程micropython版本是 2019年6月发布的1.11; 更多内容请看视频列表。  学习这门课程之前你需要至少掌握: 1: python3基础(变量, 循环, 函数, 常用库, 常用方法)。 本视频使用到的零件与淘宝上大致价格:     1: 超声波传感器(3)     2: MAX9814麦克风放大模块(8)     3: DHT22(15)     4: LED(0.1)     5: 8路5V低电平触发继电器(12)     6: HX1838红外接收模块(2)     7:红外发射管(0.1),HX1838红外接收板(1)     other: 电表, 排线, 面包板(2)*2,ESP32(28)  

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值