Use QWT Library in Qt to Display Seismic Waveforms Part III: Code for Disaplysing Microseismic Waveforms

References: 

LIBS+=-L "D:\Qt\Qt5.7.0\5.7\mingw53_32\lib"-lqwt
 INCLUDEPATH+=D:\Qt\Qt5.7.0\5.7\mingw53_32\include\QWT
 include(D:\qwt-6.1.3\qwt.prf)

  1. Edit WaveformDisplay.pro file and add the codes above into the .pro file;
  2. Add csegy.h + csegy.cpp and util.h + util.cpp in order to read a SEGY file.
  3. Edit minwindow.h to include CSegy class, QwtPlotCurve class as well as some class member variables, including:
    • CSegy m_segy;
    • int m_nTraces; //SEGY 文件道数
    • int m_nSamples; //每道的采样数
    • int m_nGeo; //检波器个数
    • int m_nScale; //坐标轴尺度
    • int m_nComponent; //绘制分量, 0=Z分量, 1=X分量, 2=Y分量, 3=3分量
    • QVector<QVector<double>*> m_Traces; //一个SEGY文件中所有道的数据
    • QList<QwtPlotCurve *> m_curve; //曲线
  4. Edit minwindow.h to add public functions, including:
    • void LoadData(); //将SEGY中道数据读进QVector<QVector<double>*>
    • void PrepareCurves(); //为所有道准备曲线
    • void Plot(int component); //绘图
    • void GetVectorMax(QVector<double> vector, double &m_Max); //归一化中找最大值
  5. Edit minwindow.h to add private slots in order to allow widgets to response, including:
    • void OnBtnBrowseClicked();
  6. Edit minwindow.cpp to add functional codes for the public functions and privates slots. Please remember to connect the signal/slots in the constructor in order to make the Push Button work.

When all 6 steps listed above finish, debug/run the application and the following interface without any waveforms will be shown.

no show
Application running with a QWT widget

Click the PushButton Browse… to select one SEGY file. Here we take a 3C downhole microseismic data with 36 traces recorded by 12-level geophone array as an example. The 3C microseismic waveforms are displayed successfully, with Z, X and Y components are shown in green, blue and red respectively.

3C microseismic waveforms in QwtPlot
3C microseismic waveforms in QwtPlot

You can also add more buttons in the UI and switch waveform of each component to display at will. Here are the .h and .cpp files subject to your modification.

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

#include "csegy.h"
#include "qwt_plot_curve.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
Q_OBJECT

public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();

private:
Ui::MainWindow *ui;

private:
CSegy m_segy;
int m_nTraces; //SEGY 文件道数
int m_nSamples; //每道的采样数
int m_nGeo; //检波器个数
int m_nScale; //坐标轴尺度
int m_nComponent; //绘制分量, 0=Z分量, 1=X分量, 2=Y分量, 3=3分量

QVector<QVector<double>*> m_Traces; //一个SEGY文件中所有道的数据
QList<QwtPlotCurve *> m_curve; //曲线
public:
void LoadData(); //将SEGY中道数据读进QVector<QVector<double>*>
void PrepareCurves(); //为所有道准备曲线
void Plot(int component); //绘图
void GetVectorMax(QVector<double> vector, double &m_Max); //归一化中找最大值
private slots:
void OnBtnBrowseClicked(); //Browse控件的响应

};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include "QFileDialog"

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);

connect(ui->btnBrowse, SIGNAL(clicked(bool)), this, SLOT(OnBtnBrowseClicked()));

m_nScale = 1.0;
}

MainWindow::~MainWindow()
{
delete ui;
}

void MainWindow::LoadData()
{
QVector* m_ChangeData;
QVector tempVector;
float* pTrace[m_nTraces];

for (int i=0; i<m_nTraces; i++)
{

m_ChangeData=new QVector;
m_ChangeData->clear();
pTrace[i] = m_segy.GetTraceData(i+1);

tempVector.clear();

for (int k=0; k<m_nSamples; k++)
{
tempVector<<(double)(pTrace[i])[k];

}
//地震道单道归一化,每个采样点振幅值除以该道最大振幅值的绝对值
double absMax[100];
double absMin=0;
GetVectorMax(tempVector, absMax[i]);

for (int k=0; k<m_nSamples; k++) { tempVector[k] = ( tempVector[k]-absMin)/(absMax[i]-absMin); m_ChangeData->append(tempVector[k]);

}

m_Traces<<m_ChangeData; } } void MainWindow::PrepareCurves() { QwtPlotCurve* NewCurve; int i; while(!m_curve.isEmpty()) delete m_curve.takeFirst(); ui->qwtPlot->setAxisScale(ui->qwtPlot->yLeft,0,(double)(m_nGeo+1));
ui->qwtPlot->setAxisScale(ui->qwtPlot->xBottom, 0, (double)m_nSamples);

for(i=0;i<m_nGeo*3;i++) { NewCurve=new QwtPlotCurve; NewCurve->setRenderHint(QwtPlotItem::RenderAntialiased);
if(i%3==0)
NewCurve->setPen(QPen(Qt::green)); //Z分量绿色
else if(i%3==1)
NewCurve->setPen(QPen(Qt::blue)); //X分量蓝色
else if(i%3==2)
NewCurve->setPen(QPen(Qt::red)); //Y分量红色

NewCurve->attach(ui->qwtPlot);
NewCurve->setVisible(false);
m_curve<<NewCurve; } ui->qwtPlot->replot();
}

void MainWindow::Plot(int component)
{

int i,k;
double j=0.0;
double m_TempValue;
QVector m_TempData;
QVector vectorX3c;

for(i=0;i<m_curve.count();i++) m_curve[i]->setVisible(false);

//X轴数据
vectorX3c.clear();
for (int i=0; i<m_nSamples; i++)
{
vectorX3c<<j;
j+=1.0;
}

for(i=0;i<m_nGeo*3;i++)
{
m_TempData.clear();
if(i%3==component && component!=3)
{
for(k=0;k<m_Traces[i]->count();k++)
{
m_TempValue=(*m_Traces[i])[k];
m_TempValue=m_nScale*0.5*m_TempValue; //显示波形的幅度
m_TempValue=1+i/3+m_TempValue;
m_TempData<<m_TempValue; } m_curve[i]->setSamples(vectorX3c,m_TempData);
m_curve[i]->setVisible(true);
}
else if(component==3) //XYZ三条曲线一同显示
{
for(k=0;k<m_Traces[i]->count();k++)
{
m_TempValue=(*m_Traces[i])[k];
m_TempValue=m_nScale*0.5*m_TempValue; //显示波形的幅度
m_TempValue=1+i/3+m_TempValue;
m_TempData<<m_TempValue; } m_curve[i]->setSamples(vectorX3c,m_TempData);
m_curve[i]->setVisible(true);
}
}

ui->qwtPlot->replot();

}

void MainWindow::GetVectorMax(QVector vector, double &m_Max)
{
int i;
double m_MaxV, m_MinV;
m_MaxV=-100;m_MinV=100;
for(i=0;i<vector.count();i++) { if(vector[i]>m_MaxV)
m_MaxV=vector[i];
if(vector[i]<m_MinV) m_MinV=vector[i]; } if(abs(m_MinV)>m_MaxV)
m_Max=abs(m_MinV);
else
m_Max=m_MaxV;
}

void MainWindow::OnBtnBrowseClicked()
{
QString str = QFileDialog::getOpenFileName(
this,
tr("Select one SEG-Y file"),
tr(""),
tr("SEG-Y Files(*.sgy *.segy)")
);

//由QString转Const Char*
char szFilePath[200];
memset(szFilePath,0,200);
QStringData *data = str.data_ptr();
ushort *s = data->data();

for (int i = 0; isize; i++ )
{
szFilePath[i] = s[