查看完整版本: [-- 使用Qt的QLabel获取绘图句柄问题! --]

QTCN开发网 -> Qt基础编程 -> 使用Qt的QLabel获取绘图句柄问题! [打印本页] 登录 -> 注册 -> 回复主题 -> 发表主题

nuanbing222 2014-09-23 16:00

使用Qt的QLabel获取绘图句柄问题!

        由于需要通过Qt开发摄像头的显示程序,该摄像头带了一个数据采集卡,通过DEMO知道需要使用EImage类,里面使用了draw(HDC)的函数,而QT中好像没有直接获取HDC的函数,QLabel类中有一个getDC()获取的HDC好像和MFC中的HDC不一样,用了不管用。所以在网上搜了一下,发现可以这样写:
        HWND hwnd = (HWND)m_label->winId();
        HDC hDC = GetDC(hwnd);
        m_dcImage24->draw(hDC);

        但是试了一下,发现还是不行,大神们,有没有其他的方法?

nuanbing222 2014-09-23 16:31
没有人知道吗?委实捉急的很啊。。。。。

dbzhang800 2014-09-23 16:32
不太了解
应该是一个普通的 QWidget 就可以吧
注意设置: Qt::WA_PaintOnScreen


nuanbing222 2014-09-23 16:36
该摄像头数据采集卡会分配内存地址用于采集的图像存储,我试过采用QPixmap的loadFromData方法直接从该地址处构建图片,进行显示,好像也不行。有没有Qt的图片类或者什么类可以操作内存数据的?

dbzhang800 2014-09-23 16:39
nuanbing222:该摄像头数据采集卡会分配内存地址用于采集的图像存储,我试过采用QPixmap的loadFromData方法直接从该地址处构建图片,进行显示,好像也不行。有没有Qt的图片类或者什么类可以操作内存数据的? (2014-09-23 16:36) 

QImage 是干这个的

nuanbing222 2014-09-23 17:15
dbzhang800:QImage 是干这个的 (2014-09-23 16:39) 

可是毫无反应啊。。。

dbzhang800 2014-09-23 23:08
nuanbing222:可是毫无反应啊。。。 (2014-09-23 17:15) 

什么叫毫无反应,构造的QImage无效 还是什么?

你的QImage采用的哪种format,和内存数据是否一致

roywillow 2014-09-24 08:45
loadFromData好像是把内存中的一个文件的数据载入的,比如说一个png文件读到内存里成了char*,然后就可以用这个函数来构建QImage了
如果你知道内存里存储的图像是RGB之类的明确的format,可以直接先构造一个正确大小和对应格式的的QImage,然后用data()或者scanLine()之类的函数来直接操作内存
另外我记得QPixmap好像可以返回一个句柄,能用吗?

nuanbing222 2014-09-24 10:17
dbzhang800:什么叫毫无反应,构造的QImage无效 还是什么?
你的QImage采用的哪种format,和内存数据是否一致 (2014-09-23 23:08) 

我定义了QImage为类的成员变量,怎么构造?我尝试着使用指针构造了一下,图片格式为Format_RGB888,并通过loadFromData函数载入内存数据,然后通过QLabel控件不太好显示啊。。。

dbzhang800 2014-09-24 10:28
nuanbing222:我定义了QImage为类的成员变量,怎么构造?我尝试着使用指针构造了一下,图片格式为Format_RGB888,并通过loadFromData函数载入内存数据,然后通过QLabel控件不太好显示啊。。。 (2014-09-24 10:17) 

loadFromData() 不是干这个,除非你的内存数据是完整的 .jpg/.png/jp2/.bmp 的图片文件。

你应该使用相应的QImage的构造函数。

nuanbing222 2014-09-24 11:38
dbzhang800:loadFromData() 不是干这个,除非你的内存数据是完整的 .jpg/.png/jp2/.bmp 的图片文件。
你应该使用相应的QImage的构造函数。 (2014-09-24 10:28) 

我试过了,用了构造函数QImage(const uchar* data, int width, int height, FORMAT format),还有QImage(int width, int height, FORMAT format)和函数fromData(const uchar* data, int len),好像会直接崩溃掉,我的图片格式是RGB888的,内存的长度是768*576*3,不知道是不是QImage的读取超届了。。。

Demo中使用的是EImage<V24>类,是可以正确操作内存的,图片也可以保存为bmp格式,只是在QT中这个类没法转化为Qt的图片类就没有办法显示啊,而其EImage类在网上也找不到说明。。。。

dbzhang800 2014-09-24 11:51
nuanbing222:
我的图片格式是RGB888的,内存的长度是768*576*3


如果你说的属实,这对QImage应该很简单,直接用构造函数就行了。

但是你提到了QImage::fromData() 和 崩溃什么的,只能说明:你在不分青红皂白地乱试

nuanbing222 2014-09-24 12:07
dbzhang800:如果你说的属实,这对QImage应该很简单,直接用构造函数就行了。
但是你提到了QImage::fromData() 和 崩溃什么的,只能说明:你在不分青红皂白地乱试[表情]
....... (2014-09-24 11:51) 

那能不能提示一下使用哪个构造函数。。。

dbzhang800 2014-09-24 12:27
多个都可以,包括你试过的那个

xuang 2014-09-24 13:03
nuanbing222:那能不能提示一下使用哪个构造函数。。。
 (2014-09-24 12:07) 

如果你不是一定要对采集卡的原始内存数据进行操作,我建议你先new一个QImage,然后用QImage的bits()获取这个QImage的图像数据指针,然后用for循环或者memcpy将原始的图像数据拷贝过来。

roywillow 2014-09-24 14:35
我觉得你能明确那个format没错就成功了一半了吧,对应的QImage的format应该是QImage::Format_RGB888,你可以构造的时候就传入data,或者构造完再修改也可以
另外如果你传入char*作为data的话,要确保这个char*保持有效才可以,Qt是不会自己进行拷贝的,文档说的很清楚:
QImage::QImage(uchar * data, int width, int height, Format format, QImageCleanupFunction cleanupFunction = 0, void * cleanupInfo = 0)
Constructs an image with the given width, height and format, that uses an existing memory buffer, data. The width and height must be specified in pixels, data must be 32-bit aligned, and each scanline of data in the image must also be 32-bit aligned.

The buffer must remain valid throughout the life of the QImage and all copies that have not been modified or otherwise detached from the original buffer. The image does not delete the buffer at destruction. You can provide a function pointer cleanupFunction along with an extra pointer cleanupInfo that will be called when the last copy is destroyed.

If format is an indexed color format, the image color table is initially empty and must be sufficiently expanded with setColorCount() or setColorTable() before the image is used.
似乎从文档看传入的data必须是32位对齐的?即使是RGB888的24位数据?可能下面那个带bytesPerLine的更有用?

nuanbing222 2014-09-24 14:56
xuang:如果你不是一定要对采集卡的原始内存数据进行操作,我建议你先new一个QImage,然后用QImage的bits()获取这个QImage的图像数据指针,然后用for循环或者memcpy将原始的图像数据拷贝过来。 (2014-09-24 13:03) 

非常感谢,我试了一下,好像也不行,我是这样写的:
        QImage* image = new QImage(768, 576, QImage::Format_RGB888);
        memcpy(image->bits(), (uchar*)pLinearAddr, 768*576*3);
最后采用QPixmap的fromImage()转化一下,使用QLabel的setPixmap()函数进行显示,没有显示。。。。

xuang 2014-09-24 15:23
nuanbing222:非常感谢,我试了一下,好像也不行,我是这样写的:
        QImage* image = new QImage(768, 576, QImage::Format_RGB888);
        memcpy(image->bits(), (uchar*)pLinearAddr, 768*576 .. (2014-09-24 14:56) 

你可以试试memcpy是不是真的从pLinearAddr处将数据拷贝至image的bits中了,我觉得很可能是因为pLinearAddr处的图像数据不是按照每个像素BGR三字节的顺序排列的。你可以试试这么写:
QImage* image = new QImage(768, 576, QImage::Format_RGB888);
int bytePerLine = image->bytesPerLine();
int imageWidth = image->width();
int imageHeight = image->height();
unsigned char* imageData = image->bits();
for (int i=0;i<imageHeight;i++)
{
    for (int j=0;j<imageWidth;j++)
    {
        // 这里赋值时最好先确定pLinearAddr处的数据长度是imageHeight*imageWidth*3
        // 也不排除它的图像数据长度与QImage\Bmp位图相同,每行都需要向4字节对齐,那就得改成pLinearAddr[i*bytePerLine + j*3 + k]了
        // 这里假设你的pLinearAddr数据是按照Blue\Green\Red的顺序排列每个像素灰度的
        imageData[i*bytePerLine + j*3 + 0] = pLinearAddr[i*imageWidth*3 + j*3 + 0];
        imageData[i*bytePerLine + j*3 + 1] = pLinearAddr[i*imageWidth*3 + j*3 + 1];
        imageData[i*bytePerLine + j*3 + 2] = pLinearAddr[i*imageWidth*3 + j*3 + 2];
    }
}
之所以用for循环不用memcpy是因为现在还不能确定你的pLinearAddr数据排布与QImage的要求一致,这样写可以通过单步调试的方法知道pLinearAddr的数据排布。

dbzhang800 2014-09-24 15:37
xuang:
你可以试试memcpy是不是真的从pLinearAddr处将数据拷贝至image的bits中了,我觉得很可能是因为pLinearAddr处的图像数据不是按照每个像素BGR三字节的顺序排列的。你可以试试这么写:
QImage* image = new QImage(768, 576, QImage::Format_RGB888);
int bytePerLine = image->bytesPerLine();
int imageWidth = image->width();
.......

你考虑的太复杂了。有时候考虑问题从简单角度的考虑会更容易解决问题。

其实楼主要测试的话:创建一个新的小工程,分配一个的w*h*3的 uchar * 数组,里面随机值都不怕,然后直接构建一个QImage,然后直接QImage::save() 保存成图片文件 。 总共也就10行左右的代码,一切问题都说明了。

nuanbing222 2014-09-24 15:47
xuang:你可以试试memcpy是不是真的从pLinearAddr处将数据拷贝至image的bits中了,我觉得很可能是因为pLinearAddr处的图像数据不是按照每个像素BGR三字节的顺序排列的。你可以试试这么写:
QImage* image = new QImage(768, 576, QImage::Format_RGB888);
int bytePerLine = image->b .. (2014-09-24 15:23) 

非常感谢您详细的回复,我按照您的代码试了一下,还是不能显示。不过,我需要问一下,如果每行都要4字节对齐,得改成pLinearAddr[i*bytePerLine + j*3 + k],其中的K是什么?
另外,我做的工程有点特殊,我们是使用QML作为前台界面,QT做后台数据处理,所以基本上没法调试,只能够靠结果或者打印LOG的方式来查看运行情况。
还好,我能保证分配的pLinearAddr的地址长度为768*576*3,格式为RGB888. 所以有个问题,为什么您的代码中要说明是BGR而不是RGB呢?

xuang 2014-09-24 16:03
nuanbing222:非常感谢您详细的回复,我按照您的代码试了一下,还是不能显示。不过,我需要问一下,如果每行都要4字节对齐,得改成pLinearAddr,其中的K是什么?
另外,我做的工程有点特殊,我们是使用QML作为前台界面,QT做后台数据处理,所以基本上没法调试,只能够靠结果或者打印LOG的方式 .. (2014-09-24 15:47) 

k表示通道数,这里就是0、1、2三个取值,刚才图个方便就没有展开写。
我记得QImage中的RGB888是按照BGR的顺序反向排列的,这一点你可以自己确认一下,无非就是显示彩色图像时颜色花了,但是内容是正确的。我之前用QImage::Format_ARGB32格式的QImage中四位字节顺序也是BGRA的反向排列。这个只是小问题,关键还是不能显示的问题。
你可以先不用你的pLinearAddr数据作为图像数据,直接对QImage的bits进行赋值,做一张全白或者全红的图像出来看看能不能显示,如果这都不能显示那就得找别的问题了。

dbzhang800 2014-09-24 16:14
xuang:
k表示通道数,这里就是0、1、2三个取值,刚才图个方便就没有展开写。
我记得QImage中的RGB888是按照BGR的顺序反向排列的,这一点你可以自己确认一下,无非就是显示彩色图像时颜色花了,但是内容是正确的。我之前用QImage::Format_ARGB32格式的QImage中四位字节顺序也是BGRA的反向排列。这个只是小问题,关键还是不能显示的问题。
你可以先不用你的pLinearAddr数据作为图像数据,直接对QImage的bits进行赋值,做一张全白或者全红的图像出来看看能不能显示,如果这都不能显示那就得找别的问题了。

看到楼主被你上一回帖引到不太正确的道路上了。我补充一点东西:

1. 你对QImage的32位对齐可能理解有偏差,楼主w和h都是4的倍数。指定没有这个对齐问题
2. RGB888,就是R、G、B。你可能混淆了RGB888和RGB24(QImage没有这个格式), RGB32和RGBX8888,以及ARGB32和RGBA8888 的区别。


xuang 2014-09-24 16:24
dbzhang800:看到楼主被你上一回帖引到不太正确的道路上了。我补充一点东西:
1. 你对QImage的32字节对齐可能理解有偏差,楼主w和h都是4的倍数。指定没有这个对齐问题
2. RGB888,就是R、G、B。你可能混淆了RGB888和RGB24(QImage没有这个格式), RGB32和RGBX8888,以及ARGB32和RGBA8888 的区 .. (2014-09-24 16:14) 

多谢版主指教,之前确实没有主要到这两种类型的区别,简单地当作一种类型处理了。

nuanbing222 2014-09-25 09:31
xuang:多谢版主指教,之前确实没有主要到这两种类型的区别,简单地当作一种类型处理了。 (2014-09-24 16:24) 

您好,我这样试了一下:
        QImage* image = new QImage(768, 576, QImage::Format_RGB888);
        uchar* imageData = image->bits();
        for(int i=0; i<768*576*3; i++)
                imageData = 222;
        QPixmap pixmap;
        pixmap.fromImage(*image);
        label->setPixmap(pixmap);
怎么完全没有显示啊。。。我哪里写错了吗?

nuanbing222 2014-09-25 09:36
dbzhang800:看到楼主被你上一回帖引到不太正确的道路上了。我补充一点东西:
1. 你对QImage的32位对齐可能理解有偏差,楼主w和h都是4的倍数。指定没有这个对齐问题
2. RGB888,就是R、G、B。你可能混淆了RGB888和RGB24(QImage没有这个格式), RGB32和RGBX8888,以及ARGB32和RGBA8888 的区别 .. (2014-09-24 16:14) 

您好,非常感谢您的回复和指导,但是我好像还是不知道怎么做,按照你的说法,使用QImage直接构建我也试过了,只是在不行之后才试了其它的方法,因为现在比较急,所以尽量还是多试一下。

您可否给一个比较详细的方法,我是个菜鸟,谢谢!

另外,在供应商给的Demo程序中,他使用了一个EImage<EC24>的类,网上查不到,不知道您是否接触过,这个类可以使用draw(HDC)的方式进行绘图,只是在Qt中没有办法获取与MFC相同的空间句柄,导致我使用同样的方法,无法进行绘制,所以才进行了各种尝试。

dbzhang800 2014-09-25 10:02
nuanbing222:
您好,非常感谢您的回复和指导,但是我好像还是不知道怎么做,按照你的说法,使用QImage直接构建我也试过了,只是在不行之后才试了其它的方法,因为现在比较急,所以尽量还是多试一下。
您可否给一个比较详细的方法,我是个菜鸟,谢谢!
.......


写测试代码,应该越简单越好。无论对你测试自己代码,还是去给某个库提交bug,这都是非常有好处的。

在QImage没搞清楚的情况下,你就开始将其转QPixmap了,而后又用QLabel显示,如此一来,你又如何判定是QImage的问题??

有效的测试代码应该是下面这种风格,你认为QImage的构造有问题,你就应该专门测试它。(另外,你们写程序,都不写单元测试么??)
  1. #include <QImage>

    const int w = 100;
    const int h = 200;

    int main()
    {
        qsrand(0);

        uchar *bytes = new uchar[w*h*3];
        for (int i=0; i<w*h*3; ++i)
            bytes[i] = qrand()%255;

        QImage img(bytes, w, h, QImage::Format_RGB888);
        img.save("t.png");

        delete bytes;
        return 0;
    }


xuang 2014-09-25 15:36
nuanbing222:您好,我这样试了一下:
        QImage* image = new QImage(768, 576, QImage::Format_RGB888);
        uchar* imageData = image->bits();
        .. (2014-09-25 09:31)

你确定你的代码里写的是
for(int i=0; i<768*576*3; i++)
                imageData = 222;
而不是
for(int i=0; i<768*576*3; i++)
                imageData【i】 = 222;
?



nuanbing222 2014-09-26 10:37
xuang:你确定你的代码里写的是
for(int i=0; i<768*576*3; i++)
                imageData = 222;
而不是
....... (2014-09-25 15:36) 

非常抱歉,现在才进行回复,非常感谢您的意见和指导,目前我已经完成了工作。

我犯了一个非常弱智的错误,就是这个错误让我在这个问题上走了很远。

lanmanck 2020-09-07 13:34
版主这个分析问题方法值得学习。


查看完整版本: [-- 使用Qt的QLabel获取绘图句柄问题! --] [-- top --]



Powered by phpwind v8.7 Code ©2003-2011 phpwind
Gzip disabled