• 14959阅读
  • 16回复

[提问]Qt用QLabel来显示摄像头,CPU占用率过高的问题 [复制链接]

上一主题 下一主题
离线honami520
 

只看楼主 倒序阅读 楼主  发表于: 2015-05-11
回复本帖可获得10RMB金钱奖励!
每人最多可获奖1次,奖池剩余10RMB金钱 (中奖几率10%)
我用的是linux,板子是全志A20的双核板子,CPU是1GHZ双核,内存512MB。用的摄像头是普通UVC摄像头。用ffmepg对摄像头数据编解码都OK,速度还挺快,结果被Qt的显示给拦住了。

我是V4L2读取一帧数据,然后YUV转换成RGB,然后转换成QImage显示到QLabel上面,定时器开的是40ms,40ms读取一帧数据,显示出来。在PC上面跑得好好的东西,到了开发板上面,就不行了。根据打印信息,定时的时间间隔编程60-70ms。然后在定时器里面执行的时间还是挺快的,只要5-8ms的时间。看来这个时间是在定时器外面,Qt自己运行的里面被消耗掉了的。

下面是我的定时服务程序代码

        video->get_frame((void **)&pp, &pp_len);
        //摄像头内部图片指针还原
        video->unget_frame();

        convert_yuv_to_rgb_buffer(pp, pf, 320, 240);
        ui->label->setPixmap(QPixmap::fromImage(*frame, Qt::AutoColor));

经过研究发现,只要执行了ui->label->setPixmap这句话,定时器间隔就变得不准,系统资源被严重消耗。问下各位,如果做过在开发板上面用Qt来显示摄像头的,有没有解决办法。或者有没有其他方法可以让摄像头的显示变快点的。
离线honami520

只看该作者 1楼 发表于: 2015-05-11
难道大家都不在板子上面做摄像头的应用吗?这个应该很常见啊,为什么一个回复的都没有啊
离线shanglei

只看该作者 2楼 发表于: 2015-05-11
用这种方式显示确实比较 占用资源 ,在window 上面我们用的gdi 渲染 就完全Ok 了 linux上面也应该有类似gdi 这样的绘图函数吧
离线hsl17

只看该作者 3楼 发表于: 2015-05-13
A20有linux资料吗?

只看该作者 4楼 发表于: 2015-06-04
我用QT5做的摄像头视频采集,v4l2架构,可是label什么也不显示。能帮忙看看吗?谢谢啊!代码也是从网上找的。
ProcessImage::ProcessImage(QWidget *parent):QWidget(parent)
{
    pp = (unsigned char *)malloc(640 * 480/*QWidget::width()*QWidget::height()*/* 3 * sizeof(char));
    painter = new QPainter(this);
    frame = new QImage(pp,640,480,QImage::Format_RGB888);
   // frame = new QPixmap(640,320);
    label = new QLabel();
    vd = new VideoDevice(tr("/dev/video0"));

    connect(vd, SIGNAL(display_error(QString)), this,SLOT(display_error(QString)));
    rs = vd->open_device();
    if(-1==rs)
    {
        QMessageBox::warning(this,tr("error"),tr("open /dev/dsp error"),QMessageBox::Yes);
        vd->close_device();
    }

    rs = vd->init_device();
    if(-1==rs)
    {
        QMessageBox::warning(this,tr("error"),tr("init failed"),QMessageBox::Yes);
        vd->close_device();
    }

    rs = vd->start_capturing();
    if(-1==rs)
    {
        QMessageBox::warning(this,tr("error"),tr("start capture failed"),QMessageBox::Yes);
        vd->close_device();
    }

    if(-1==rs)
    {
        QMessageBox::warning(this,tr("error"),tr("get frame failed"),QMessageBox::Yes);
        vd->stop_capturing();
    }

    timer = new QTimer(this);
    connect(timer,SIGNAL(timeout()),this,SLOT(update()));
    timer->start(30);

    QHBoxLayout *hLayout = new QHBoxLayout();
    hLayout->addWidget(label);
    setLayout(hLayout);
    setWindowTitle(tr("Capture"));
}

ProcessImage::~ProcessImage()
{
    rs = vd->stop_capturing();
    rs = vd->uninit_device();
    rs = vd->close_device();
}

void ProcessImage::paintEvent(QPaintEvent *)
{
    rs = vd->get_frame((void **)&p,&len);
    convert_yuv_to_rgb_buffer(p,pp,640,480/*QWidget::width(),QWidget::height()*/);
    frame->loadFromData((uchar *)pp,/*len*/640 * 480 * 3 * sizeof(char));

//    painter->begin(this);
//    painter->drawImage(0,0,*frame);
//    painter->end();
//    rs = vd->unget_frame();
   // frame->load("./img3.jpg");

    label->setPixmap(QPixmap::fromImage(*frame,Qt::AutoColor));
   // label->show();
    rs = vd->unget_frame();
   // label->drawFrame();

    //    QPixmap *pixImage = new QPixmap();
//    pixImage->loadFromData((uchar *)pp,sizeof(pp),0,Qt::AutoColor);
//    QPainter painter(this);
//    painter.begin(this);
//    painter.drawPixmap(0,0,QWidget::width(),QWidget::height(),*pixImage);
//    painter.end();
}

void ProcessImage::display_error(QString err)
{
    QMessageBox::warning(this,tr("error"), err,QMessageBox::Yes);
}

/*yuv格式转换为rgb格式*/
int ProcessImage::convert_yuv_to_rgb_buffer(unsigned char *yuv, unsigned char *rgb, unsigned int width, unsigned int height)
{
unsigned int in, out = 0;
unsigned int pixel_16;
unsigned char pixel_24[3];
unsigned int pixel32;
int y0, u, y1, v;
for(in = 0; in < width * height * 2; in += 4) {
  pixel_16 =
   yuv[in + 3] << 24 |
   yuv[in + 2] << 16 |
   yuv[in + 1] <<  8 |
   yuv[in + 0];
  y0 = (pixel_16 & 0x000000ff);
  u  = (pixel_16 & 0x0000ff00) >>  8;
  y1 = (pixel_16 & 0x00ff0000) >> 16;
  v  = (pixel_16 & 0xff000000) >> 24;
  pixel32 = convert_yuv_to_rgb_pixel(y0, u, v);
  pixel_24[0] = (pixel32 & 0x000000ff);
  pixel_24[1] = (pixel32 & 0x0000ff00) >> 8;
  pixel_24[2] = (pixel32 & 0x00ff0000) >> 16;
  rgb[out++] = pixel_24[0];
  rgb[out++] = pixel_24[1];
  rgb[out++] = pixel_24[2];
  pixel32 = convert_yuv_to_rgb_pixel(y1, u, v);
  pixel_24[0] = (pixel32 & 0x000000ff);
  pixel_24[1] = (pixel32 & 0x0000ff00) >> 8;
  pixel_24[2] = (pixel32 & 0x00ff0000) >> 16;
  rgb[out++] = pixel_24[0];
  rgb[out++] = pixel_24[1];
  rgb[out++] = pixel_24[2];
}
return 0;
}

int ProcessImage::convert_yuv_to_rgb_pixel(int y, int u, int v)
{
unsigned int pixel32 = 0;
unsigned char *pixel = (unsigned char *)&pixel32;
int r, g, b;
r = y + (1.370705 * (v-128));
g = y - (0.698001 * (v-128)) - (0.337633 * (u-128));
b = y + (1.732446 * (u-128));
if(r > 255) r = 255;
if(g > 255) g = 255;
if(b > 255) b = 255;
if(r < 0) r = 0;
if(g < 0) g = 0;
if(b < 0) b = 0;
pixel[0] = r * 220 / 256;
pixel[1] = g * 220 / 256;
pixel[2] = b * 220 / 256;
return pixel32;
}
/*yuv格式转换为rgb格式*/
离线hsl17

只看该作者 5楼 发表于: 2015-06-19
用软件编码当然慢
离线hezf

只看该作者 6楼 发表于: 2015-07-10
楼主请问移植的具体步骤在哪里能找到
我也是A20
好难啊!
none

只看该作者 7楼 发表于: 2015-08-07
楼主解决这个问题了吗?
离线hlr159hlr

只看该作者 8楼 发表于: 2015-10-29
yuv转RGB是可以使用硬件转化的
离线hehui

只看该作者 9楼 发表于: 2016-11-01
回帖奖励+ 10
不要用QLABEL,用QWIDGET直接画才行
离线jdlyyear

只看该作者 10楼 发表于: 2016-11-02
遇到同样问题,哥们解决了吗
离线wyqhnr

只看该作者 11楼 发表于: 2016-11-03
QLabel来显示图片还可以 ,显示摄像头也是这样吗
离线hehui

只看该作者 12楼 发表于: 2016-11-03
回 jdlyyear 的帖子
jdlyyear:遇到同样问题,哥们解决了吗 (2016-11-02 21:24) 

这个问题很容易 的,直接在QWidget上的paintevent里画就行了,用QLabel可能会卡死
离线黑佐

只看该作者 13楼 发表于: 2016-12-27
我是用qwidget的哦
离线quweibing

只看该作者 14楼 发表于: 2018-07-02
我也遇到这个问题,请问最后怎么解决的呢?
离线lanmanck

只看该作者 15楼 发表于: 2020-09-07
回 shanglei 的帖子
shanglei:用这种方式显示确实比较 占用资源 ,在window 上面我们用的gdi 渲染 就完全Ok 了 linux上面也应该有类似gdi 这样的绘图函数吧  (2015-05-11 22:49) 

你好,我试了gdi和paintevent,同样的10~20% cpu占用,使用海康的api只有5%,怎么弄gdi小一点?
精彩博客:labisart.com
离线liaohanghua

只看该作者 16楼 发表于: 2021-11-17
不要用QT去显示,我们都是底层去显示然后置顶就可以了,QT显示没用GPU非常卡。
快速回复
限100 字节
 
上一个 下一个