Qt QML绘制热力图实现原理

46 篇文章 23 订阅
本文详细介绍了如何在QML中利用QQuickPaintedItem结合QImage绘制热力图。首先,通过QPoint列表记录点位置,然后计算最大重复数和每个位置的透明度。接着,使用QImage绘制透明度渐变图,再根据点的重复次数转换为不同颜色。最后,将透明度图转换为颜色热力图并在QML中显示。完整示例代码和Demo可在作者的CSDN博客和GitHub仓库中找到。
摘要由CSDN通过智能技术生成

项目需要在QML根据地图上的点位置绘制热力图,最终效果:

经过查阅相关的博客和实现方法,总结思路如下:

  1. 由于需要在QML地图中使用,因此使用QQuickPaintedItem绘制,并注册至QML中使用
  2. 使用QImage绘制渐变透明度图,以每个位置点中心绘制透明度渐变的圆,圆的半径就是热力图的衍射程度。这样同一个位置叠加的点越多,该位置的越不透明。假定所有点中重复度最高的位置(重复度为N)透明度为不透明,则每个衍射渐变圆的透明度就是255/N。
  3. 得到的QImage图片每个像素点透明度则代表了该位置点的重复程度,将该图片上每个像素点透明度转为不同的颜色,绘制成的新图片就是热力图。

头文件变量:


    QList<QPoint> mPosList;//点位置列表
    int mMaxCount;//最大重复数
    int mAlpha;//每个位置点透明度
    int mDiffraction = 15;
    bool mLegendVisible;//热力图标识是否绘制
    bool mHideZeroPoint;//无热力位置是否绘制

    QImage alphaImage;//透明度图
    QImage mColorImage;//热力图颜色标识
    QImage mHeatImage;//最终热力图

    QList<QRgb> colorList;//热力图颜色透明度对应表

 绘制热力图标志和计算透明度/颜色映射表:

void MapHeatImage::drawColorImage()
{
    QLinearGradient colorGradient = QLinearGradient(QPoint(0,255),QPoint(0,0));
    colorGradient.setColorAt(0,Qt::blue);
    colorGradient.setColorAt(0.2,Qt::cyan);
    colorGradient.setColorAt(0.4,Qt::green);
    colorGradient.setColorAt(0.6,Qt::yellow);
    colorGradient.setColorAt(0.8,Qt::magenta);
    colorGradient.setColorAt(0.95,Qt::red);
    mColorImage = QImage(20,256,QImage::Format_ARGB32);
    QPainter painter(&mColorImage);
    painter.fillRect(mColorImage.rect(),colorGradient);
    for(int i=255;i>-1;i--){
        colorList.append(mColorImage.pixel(0,i));
    }
}

绘制各点重叠后透明度图:

void MapHeatImage::paintHeat()
{
    if(mPosList.isEmpty()){
        return;
    }
    QPen pen;
    pen.setWidth(0);
    pen.setColor("#00000000");
    alphaImage = QImage(this->width(),this->height(),QImage::Format_Alpha8);//只存有透明度
    alphaImage.fill(Qt::transparent);
    QPainter dataPainter;
    dataPainter.begin(&alphaImage);
    dataPainter.setPen(pen);

    mAlpha = 255/mMaxCount;
    for(QPoint point : mPosList){
        QRadialGradient gradient(point,mDiffraction);
        gradient.setColorAt(0,QColor(255,0,0,mAlpha));
        gradient.setColorAt(1,QColor(0,0,0,0));

        dataPainter.setBrush(gradient);
        dataPainter.drawEllipse(point,mDiffraction,mDiffraction);
    }
    transAlphaToColor();
}

根据透明度图各像素点,根据色彩对应表转为颜色热力图:

void MapHeatImage::transAlphaToColor()
{
    mHeatImage = QImage(this->width(),this->height(),QImage::Format_ARGB32);
    mHeatImage.fill(Qt::transparent);
    QPainter heatPainter(&mHeatImage);
    for(int r=0;r<alphaImage.height();r++){
        const uchar *line_data = alphaImage.scanLine(r);
        QRgb* line_heat = reinterpret_cast<QRgb*>(mHeatImage.scanLine(r));
        for(int c=0;c<alphaImage.width();c++){
            if(mHideZeroPoint){
                if(line_data[c]>0)
                    line_heat[c] = colorList[line_data[c]];
            }else{
                line_heat[c] = colorList[line_data[c]];
            }
        }
    }
    update();
}

将控件中绘制得到的热力图:

void MapHeatImage::paint(QPainter *painter)
{
    painter->drawImage(QPoint(0,0),mHeatImage);
    if(mLegendVisible){
        painter->drawImage(QPoint(10,10),mColorImage);
    }
}

关于热力图在QML地图中使用的Demo可转到我博客中:

Qt QML地图上绘制热力图(Qt/QML组件)https://blog.csdn.net/zjgo007/article/details/121687451?spm=1001.2014.3001.5501icon-default.png?t=LA92https://blog.csdn.net/zjgo007/article/details/121687451?spm=1001.2014.3001.5501完整示例GitHub:https://github.com/zjgo007/QmlDemo/tree/master/HeatDemoicon-default.png?t=LA92https://github.com/zjgo007/QmlDemo/tree/master/HeatDemo

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

喵喵叫的猴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值