
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 << );
key ^= (key >> );
key += (key << );
key ^= (key >> );
key += ~(key << );
key ^= (key >> );
return key;
} static int fastRandomInt(int seed) {
int nseed = seed * +0XFFFFFFF;
return wang_inthash(nseed);
} static float fastRandom01(int seed)
{
return float(fastRandomInt(seed) % ) / 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 = )
{
// 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 = ;
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+);
auto fitvar = GLY_MATH::fit<float>(rd01,,,-,); // random move 1 pixel pos
point.rx() += fitvar*;
point.ry() += fitvar*;
}
}; }
// some function move points using namespace TopVertex; ImageParse::ImageParse(const QString &path):
mImagePath(path),
mScatterNum(){
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 = ;k<count;k++)
{
auto rd01 = GLY_MATH::fastRandom01(k);
auto numChoice = abs(int(rd01 * cont.size())-) ;
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 = ; ht < hdt; ht ++)
{
for(int wt = ; wt< wdt ; wt ++)
{
QColor rgb = QColor(mImage.pixel(wt,ht));
if (rgb.red()<=)
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 = ; ht < hdt; ht ++)
{
for (int wt = ; wt < wdt; wt++)
{
QColor rgb = QColor(mImage.pixel(wt, ht));
if (rgb.red() <= )
continue; if(rgb.red() >= && rgb.red()<)
{
part1.emplace_back(QPointF(wt,ht));
}
if(rgb.red() >= && rgb.red()<)
{
part2.emplace_back(QPointF(wt,ht));
}
if(rgb.red() >= && rgb.red()<)
{
part3.emplace_back(QPointF(wt,ht));
}
if(rgb.red() >= && rgb.red()<=)
{
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(,);
setMinimumSize(QSize(,)); mImageParse.loadImage("./gray4.jpg");
mImageParse.setScatterNum();
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 = ,
int maxSample=)
{
for(int i=;i<maxSample;i++)
{
auto alpha = (maxSample-i) * glowTint;
pen.setColor(QColor(,,,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(,,,));
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()),,iw,,ww);
auto newy = GLY_MATH::fit<float>(float(pf.y()),,ih,,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(); }