Simple scatter method in 2d picture(Qt)

Result:

 grayMap:

 

MathTools:

//
// Created by Administrator on 2017/8/17.
//

#ifndef QTSCATTER_MATHTOOLS_H
#define QTSCATTER_MATHTOOLS_H


#include <string>
#include <vector>
#include <iostream>
#include <sstream>
using namespace std;

namespace TopVertex
{
    class GLY_MATH
    {
    public:
        template<typename T>
        static T min(T a, T b) {
            if (a > b) {
                return b;
            } else {
                return a;
            }
        }

        template<typename T>
        static T max(T a, T b) {
            if (a > b) {
                return a;
            } else {
                return b;
            }
        }

        template<typename T>
        static bool zero_compare(T a, double tol = 0.00001) {
            return a >= -tol && a <= tol;
        }

        // DO NOT USE THIS FIT TO FIT VECTOR VALUE
        template<typename T>
        static T fit(T var, T omin, T omax, T nmin, T nmax) {
            T d = omax - omin;
            if (zero_compare(d)) {
                return (nmin + nmax) * 0.5;
            }
            if (omin < omax) {
                if (var < omin) return nmin;
                if (var > omax) return nmax;
            } else {
                if (var < omax) return nmax;
                if (var > omin) return nmin;
            }
            return nmin + (nmax - nmin) * (var - omin) / d;
        }

        //return -1 to 1
        template<typename T>
        static T fit_negate(T var, T omin, T omax) {
            return fit(var, omin, omax, -1.0, 1.0);
        }


        //string split
        static std::vector<std::string> split_string(std::string &inputString, char &split_char) {
            std::stringstream ss(inputString);
            std::string sub_str;
            std::vector<std::string> sp_strPath;
            sp_strPath.clear();
            while (getline(ss, sub_str, split_char)) {
                sp_strPath.push_back(sub_str);
            }
            return sp_strPath;
        }

        //value to string
        template<typename T>
        // T must be a value int/float/double
        static std::string value_to_str(T &value) {
            std::ostringstream os;
            os << value;
            return os.str();
        }


        static int wang_inthash(int key) {
            // From http://www.concentric.net/~Ttwang/tech/inthash.htm
            key += ~(key << 16);
            key ^= (key >> 5);
            key += (key << 3);
            key ^= (key >> 13);
            key += ~(key << 9);
            key ^= (key >> 17);
            return key;
        }

        static int fastRandomInt(int seed) {
            int nseed = seed * 1664525+0XFFFFFFF;
            return wang_inthash(nseed);
        }

        static float fastRandom01(int seed)
        {
            return float(fastRandomInt(seed) % 1000000) / 1000000.0f;
        }

    };
}



#endif //QTSCATTER_MATHTOOLS_H
MathTools

点位移类,用于后续动画

//
// Created by Administrator on 2017/8/18.
//

#ifndef QTSCATTER_POINTMOTION_H
#define QTSCATTER_POINTMOTION_H

namespace TopVertex
{

    // our default motion
    template <typename T>
    class PolicyMotion
    {
    public:

        template <typename addVal>
        static void advect(T &point,const addVal &val,int loopId = 0)
        {
            // not implement
        }
    };

    // per step motion
    template <typename opType=int,
            template <typename> class Policy = PolicyMotion>
    class Motion
    {
    public:
        template <typename T>
        static void advect_motion(T begin, T end,float time)
        {
            int loopId = 0;
            while(begin!= end)
            {
                Policy<opType>::advect(*begin,time,loopId);
                begin++;
                loopId++;
            }
        }

    };

}


#endif //QTSCATTER_POINTMOTION_H
PointMotion.h

QImage分析像素:

//
// Created by Administrator on 2017/8/17.
//

#ifndef QTSCATTER_IMAGEPARSE_H
#define QTSCATTER_IMAGEPARSE_H

#include <QImage>
#include <QString>
#include <QPointF>
#include <QVector>
#include <QDebug>
#include <vector>




namespace TopVertex
{
    class ImageParse
    {
    public:
        enum PARSETYPE{UNIFORM=0x00,STEP=0x01};

        ImageParse() = default;

        explicit ImageParse(const QString &path);

        ImageParse(const QString &path,const int &ScatterNum);

        // parse image to data
        void parse(PARSETYPE parseFlag=UNIFORM);

        // our pixels positions
        std::vector<QPointF> &getParsePixelsPos();


        // load image
        inline void loadImage(const QString &path) {
            if(!mImage.load(path))
                qDebug() << "Image load " << path << " error";
        }

        // set scatter num
        inline void setScatterNum(int pts) {
            mScatterNum = pts;
        }

        // get image
        QImage &getImage(){return mImage;}

    private:
        // Store image to parse
        QImage mImage;

        void parseUniform();
        void parseStep();

    private:
        // store our data in here
        std::vector<QPointF> mPixelsPos;

        // read Image path
        QString mImagePath;

        // scatter counts
        int mScatterNum;


    };
}



#endif //QTSCATTER_IMAGEPARSE_H
ImageParse.h
//
// Created by Administrator on 2017/8/17.
//

#include "ImageParse.h"
#include <QDebug>
#include <QColor>
#include <algorithm>
#include "MathTools.h"
#include "PointMotion.h"



// some function move points
namespace TopVertex
{

    // our default motion
    template <typename T>
    class randomMotion
    {
    public:
        template <typename addVal>
        static void advect(T &point,const addVal &val,int loopId)
        {
            auto rd01   = GLY_MATH::fastRandom01(loopId+1000);
            auto fitvar = GLY_MATH::fit<float>(rd01,0,1,-1,1); // random move 1 pixel pos
            point.rx() += fitvar*2;
            point.ry() += fitvar*2;
        }
    };

}
// some function move points

using namespace TopVertex;

ImageParse::ImageParse(const QString &path):
        mImagePath(path),
        mScatterNum(0){
    loadImage(path);

}
ImageParse::ImageParse(const QString &path,const int &ScatterNum):
        mImagePath(path),
        mScatterNum(ScatterNum){
    loadImage(path);

}

std::vector<QPointF> & ImageParse::getParsePixelsPos()
{
    return mPixelsPos;
}


void ImageParse::parse(PARSETYPE parseFlag)
{
    if(parseFlag == UNIFORM)
        parseUniform();
    else
        parseStep();

}



template <typename T>
static void RandomSelectByCount(int count, T &cont, T &desCont)
{
    for(int k = 0;k<count;k++)
    {
        auto rd01 = GLY_MATH::fastRandom01(k);
        auto numChoice = abs(int(rd01 * cont.size())-1) ;
        desCont.emplace_back(cont[numChoice]);
    }
}

void ImageParse::parseUniform() {
    qDebug() << "w/h:"<<mImage.width() << " "<< mImage.height() ;
    auto wdt = mImage.width();
    auto hdt = mImage.height();
    vector<QPointF> storePos;
    for(int ht = 0 ; ht < hdt; ht ++)
    {
        for(int wt = 0; wt< wdt ; wt ++)
        {
            QColor rgb = QColor(mImage.pixel(wt,ht));
            if (rgb.red()<=10)
                continue;
            storePos.emplace_back(QPointF(wt,ht));

        }
    }
    RandomSelectByCount(mScatterNum,storePos,mPixelsPos);
    Motion<QPointF,randomMotion>::advect_motion(mPixelsPos.begin(),mPixelsPos.end(),0.0);
}



void ImageParse::parseStep()
{


    auto wdt = mImage.width();
    auto hdt = mImage.height();


    int count_10_50   = floor(mScatterNum * 0.10);
    int count_50_100  = floor(mScatterNum * 0.15);
    int count_100_200 = floor(mScatterNum * 0.35);
    int count_200_255 = floor(mScatterNum * 0.45);


    qDebug() << "10-50   " << count_10_50;
    qDebug() << "50-100  " << count_50_100;
    qDebug() << "100-200 " << count_100_200;
    qDebug() << "200-255 " << count_200_255;


    vector<QPointF> part1;
    vector<QPointF> part2;
    vector<QPointF> part3;
    vector<QPointF> part4;

    for(int ht = 0 ; ht < hdt; ht ++)
    {
        for (int wt = 0; wt < wdt; wt++)
        {
            QColor rgb = QColor(mImage.pixel(wt, ht));
            if (rgb.red() <= 10)
                continue;

            if(rgb.red() >=11 && rgb.red()<50)
            {
                part1.emplace_back(QPointF(wt,ht));
            }
            if(rgb.red() >=50 && rgb.red()<100)
            {
                part2.emplace_back(QPointF(wt,ht));
            }
            if(rgb.red() >=100 && rgb.red()<200)
            {
                part3.emplace_back(QPointF(wt,ht));
            }
            if(rgb.red() >=200 && rgb.red()<=255)
            {
                part4.emplace_back(QPointF(wt,ht));
            }


        }
    }

    RandomSelectByCount(count_10_50, part1, mPixelsPos);
    RandomSelectByCount(count_50_100, part2, mPixelsPos);
    RandomSelectByCount(count_100_200, part3, mPixelsPos);
    RandomSelectByCount(count_200_255, part4, mPixelsPos);
    // random move points
    Motion<QPointF,randomMotion>::advect_motion(mPixelsPos.begin(),mPixelsPos.end(),0.0);

}
ImageParse.cpp

显示窗口:

//
// Created by Administrator on 2017/8/17.
//

#ifndef QTSCATTER_VIDEOWIDGET_H
#define QTSCATTER_VIDEOWIDGET_H

#include <QWidget>
#include "ImageParse.h"
#include <QResizeEvent>

namespace  TopVertex
{
    class VideoWidget:public QWidget
    {
        Q_OBJECT
    public:



        explicit VideoWidget(QWidget *parent = nullptr):QWidget(parent)
        {
            resize(1280,720);
            setMinimumSize(QSize(50,50));


            mImageParse.loadImage("./gray4.jpg");
            mImageParse.setScatterNum(1000);
            mImageParse.parse(ImageParse::STEP);


            // mainwindow background picture
            mBgImage.load("./dp.jpg");


            mInitW = width();
            mInitH = height();
        }
    private:
        ImageParse mImageParse;
        int mInitW;
        int mInitH;
        QImage mBgImage;
    protected:
        void paintEvent(QPaintEvent *e) override ;
        void resizeEvent(QResizeEvent *e) override;

    };


}


#endif //QTSCATTER_VIDEOWIDGET_H
VideoWidget.h
//
// Created by Administrator on 2017/8/17.
//

#include "VideoWidget.h"
#include <algorithm>
#include "MathTools.h"
using namespace TopVertex;
#include <QPainter>
using namespace std;


template <typename T>
static void paintGlow(QPainter &painter,
                      QPen &pen,
                      T &cont,
                      float glowRadius = 1.2,
                      float glowTint = 1,
                      int maxSample=10)
{
    for(int i=0;i<maxSample;i++)
    {
        auto alpha = (maxSample-i) * glowTint;
        pen.setColor(QColor(255,0,0,alpha));
        pen.setWidthF(i * glowRadius);
        painter.setPen(pen);
        auto iter = cont.begin();
        for_each(iter,cont.end(),[&painter](const QPointF&pf){painter.drawPoint(pf);});
    }
}



void VideoWidget::paintEvent(QPaintEvent *e)
{
    QPainter painter(this);
    painter.drawImage(this->rect(),mBgImage);
    painter.setRenderHint(QPainter::HighQualityAntialiasing);

    QPen pen(QColor(255,0,0,255));
    pen.setWidthF(1.0);
    painter.setBrush(Qt::blue);
    painter.setPen(pen);
    auto &pos = mImageParse.getParsePixelsPos();
    auto iter = pos.begin();
    for_each(iter,pos.end(),[&painter](const QPointF&pf){painter.drawPoint(pf);});
    paintGlow(painter,pen,mImageParse.getParsePixelsPos());

}
void VideoWidget::resizeEvent(QResizeEvent *e)
{
    // orig image width height
    auto iw = mInitW;
    auto ih = mInitH;
    // current width and height
    auto ww = this->width();
    auto wh = this->height();
    auto &pos = mImageParse.getParsePixelsPos();
    auto iter = pos.begin();
    auto resize = [&ww,&wh,&iw,&ih](QPointF&pf)
    {
        auto newx = GLY_MATH::fit<float>(float(pf.x()),0,iw,0,ww);
        auto newy = GLY_MATH::fit<float>(float(pf.y()),0,ih,0,wh);

        pf.rx() = newx;
        pf.ry() = newy;
    };
    for_each(iter,pos.end(),resize);
    mInitW = width();
    mInitH = height();

}
VideoWidget.cpp

 main.cpp

#include <QApplication>
#include "ImageParse.h"
#include <QDebug>
#include "VideoWidget.h"

using namespace TopVertex;

int main(int argc, char *argv[])
{
    
    QApplication a(argc, argv);
    VideoWidget w;
    w.show();
    return a.exec();
    

}
View Code
原文地址:https://www.cnblogs.com/gearslogy/p/7395818.html