VTK邊緣檢測:梯度算子,Sobel算子,Canny算子,Laplace算子

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QFileDialog>
#include <QDebug>
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2)
VTK_MODULE_INIT(vtkInteractionStyle)
#include <vtkSmartPointer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkJPEGReader.h>
#include <vtkImageData.h>
#include <vtkImageLuminance.h>
#include <vtkImageActor.h>
#include <vtkImageThreshold.h>
#include <vtkInteractorStyleImage.h>

namespace Ui {
    class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
private slots:
    void openFileSlot();
private:
    vtkSmartPointer<vtkRenderer>               pSrcGradientRenderer;
    vtkSmartPointer<vtkRenderer>               pGradientRenderer;

    vtkSmartPointer<vtkRenderer>               pSrcSobelRenderer;
    vtkSmartPointer<vtkRenderer>               pSobelXRenderer;
    vtkSmartPointer<vtkRenderer>               pSobelYRenderer;
    vtkSmartPointer<vtkRenderer>               pSobelRenderer;

    vtkSmartPointer<vtkRenderer>               pSrcCandyRenderer;
    vtkSmartPointer<vtkRenderer>               pCandyRenderer;

    vtkSmartPointer<vtkRenderer>               pSrcLaplaceRenderer;
    vtkSmartPointer<vtkRenderer>               pLaplaceRenderer;

    vtkSmartPointer<vtkInteractorStyleImage>   pImageStyle;
    vtkSmartPointer<vtkJPEGReader>             pJpegReader;

    vtkSmartPointer<vtkImageActor>             pSrcGradientImageActor;
    vtkSmartPointer<vtkImageActor>             pGradientImageActor;

    vtkSmartPointer<vtkImageActor>             pSrcSobelImageActor;
    vtkSmartPointer<vtkImageActor>             pSobelXImageActor;
    vtkSmartPointer<vtkImageActor>             pSobelYImageActor;
    vtkSmartPointer<vtkImageActor>             pSobelImageActor;

    vtkSmartPointer<vtkImageActor>             pSrcCandyImageActor;
    vtkSmartPointer<vtkImageActor>             pCandyImageActor;

    vtkSmartPointer<vtkImageActor>             pSrcLaplaceImageActor;
    vtkSmartPointer<vtkImageActor>             pLaplaceImageActor;
private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <vtkImageGradient.h>
#include <vtkImageMagnitude.h>
#include <vtkImageShiftScale.h>
#include <vtkImageSobel2D.h>
#include <vtkImageExtractComponents.h>
#include <vtkImageMathematics.h>
#include <vtkImageLuminance.h>
#include <vtkImageCast.h>
#include <vtkImageGaussianSmooth.h>
#include <vtkImageNonMaximumSuppression.h>
#include <vtkImageConstantPad.h>
#include <vtkImageToStructuredPoints.h>
#include <vtkLinkEdgels.h>
#include <vtkThreshold.h>
#include <vtkGeometryFilter.h>
#include <vtkSubPixelPositionEdgels.h>
#include <vtkStripper.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkProperty.h>
#include <vtkImageLaplacian.h>

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

    {
        pSrcGradientRenderer         = vtkSmartPointer<vtkRenderer>::New();
        pSrcGradientRenderer->SetBackground(1.0, 0, 0);
        pSrcGradientRenderer->SetViewport(0, 0, 0.5, 0.25);

        pGradientRenderer      = vtkSmartPointer<vtkRenderer>::New();
        pGradientRenderer->SetBackground(1.0, 0, 0);
        pGradientRenderer->SetViewport(0.5, 0, 1.0, 0.25);

    }

    {
        pSrcSobelRenderer = vtkSmartPointer<vtkRenderer>::New();
        pSrcSobelRenderer->SetBackground(0.0, 1.0, 0.0);
        pSrcSobelRenderer->SetViewport(0, 0.25, 0.25, 0.5);

        pSobelXRenderer      = vtkSmartPointer<vtkRenderer>::New();
        pSobelXRenderer->SetBackground(0.0, 1.0, 0.0);
        pSobelXRenderer->SetViewport(0.25, 0.25, 0.5, 0.5);

        pSobelYRenderer      = vtkSmartPointer<vtkRenderer>::New();
        pSobelYRenderer->SetBackground(0.0, 1.0, 0.0);
        pSobelYRenderer->SetViewport(0.5, 0.25, 0.75, 0.5);

        pSobelRenderer = vtkSmartPointer<vtkRenderer>::New();
        pSobelRenderer->SetBackground(0.0, 1.0, 0.0);
        pSobelRenderer->SetViewport(0.75, 0.25, 1.0, 0.5);
    }

    {
        pSrcCandyRenderer = vtkSmartPointer<vtkRenderer>::New();
        pSrcCandyRenderer->SetBackground(0.0, 0.0, 1.0);
        pSrcCandyRenderer->SetViewport(0, 0.5, 0.5, 0.75);

        pCandyRenderer      = vtkSmartPointer<vtkRenderer>::New();
        pCandyRenderer->SetBackground(0.0, 0.0, 1.0);
        pCandyRenderer->SetViewport(0.5, 0.5, 1.0, 0.75);
    }

    {
        pSrcLaplaceRenderer      = vtkSmartPointer<vtkRenderer>::New();
        pSrcLaplaceRenderer->SetBackground(1.0, 0, 0);
        pSrcLaplaceRenderer->SetViewport(0, 0.75, 0.5, 1.0);

        pLaplaceRenderer      = vtkSmartPointer<vtkRenderer>::New();
        pLaplaceRenderer->SetBackground(1.0, 0, 0);
        pLaplaceRenderer->SetViewport(0.5, 0.75, 1.0, 1.0);
    }

    connect(ui->pushButton, SIGNAL(clicked(bool)), this, SLOT(openFileSlot()));
}

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

void MainWindow::openFileSlot()
{
#if 1
    QString selectFilePath = QFileDialog::getOpenFileName(this, QString("選擇圖像文件"), QString(""), QString("圖像(*.jpg)"));
#else
    QString selectFilePath = QFileDialog::getOpenFileName(this, QString("選擇圖像文件"), QString(""), QString("圖像(*.png)"));
#endif
    if(selectFilePath.isEmpty())
    {
        ui->textBrowser->append("選擇圖像路徑爲空!");
        return ;
    }
    else
    {
        ui->textBrowser->append(selectFilePath);
    }

    pJpegReader = vtkSmartPointer<vtkJPEGReader>::New();
    pJpegReader->SetFileName(selectFilePath.toStdString().c_str());
    pJpegReader->Update();

    int dims[3];
    pJpegReader->GetOutput()->GetDimensions(dims);

    qDebug() << "dims = " << dims[0] << ", " << dims[1] << ", " << dims[2];

    vtkSmartPointer<vtkImageLuminance> pImageLuminance = vtkSmartPointer<vtkImageLuminance>::New();
    pImageLuminance->SetInputData(pJpegReader->GetOutput());
    pImageLuminance->Update();

    // 計算圖像梯度
    {


        pSrcGradientImageActor = vtkSmartPointer<vtkImageActor>::New();
        pSrcGradientImageActor->SetInputData(pJpegReader->GetOutput());
        pSrcGradientRenderer->AddActor(pSrcGradientImageActor);
        ui->qvtkWidget->GetRenderWindow()->AddRenderer(pSrcGradientRenderer);

        vtkSmartPointer<vtkImageGradient> pImageGradient = vtkSmartPointer<vtkImageGradient>::New();
        pImageGradient->SetInputData(pImageLuminance->GetOutput());
        pImageGradient->SetDimensionality(2);
        pImageGradient->Update();

        vtkSmartPointer<vtkImageMagnitude> pImageMagnitude = vtkSmartPointer<vtkImageMagnitude>::New();
        pImageMagnitude->SetInputData(pImageGradient->GetOutput());
        pImageMagnitude->Update();

        double range[2];
        pImageMagnitude->GetOutput()->GetScalarRange(range);

        vtkSmartPointer<vtkImageShiftScale> pImageShift = vtkSmartPointer<vtkImageShiftScale>::New();
        pImageShift->SetOutputScalarTypeToUnsignedChar();
        pImageShift->SetScale(255 / range[1]);
        pImageShift->SetInputData(pImageMagnitude->GetOutput());
        pImageShift->Update();

        pGradientImageActor = vtkSmartPointer<vtkImageActor>::New();
        pGradientImageActor->SetInputData(pImageShift->GetOutput());
        pGradientRenderer->AddActor(pGradientImageActor);
        ui->qvtkWidget->GetRenderWindow()->AddRenderer(pGradientRenderer);
    }

    // Sobel算子
    {
        pSrcSobelImageActor = vtkSmartPointer<vtkImageActor>::New();
        pSrcSobelImageActor->SetInputData(pJpegReader->GetOutput());
        pSrcSobelRenderer->AddActor(pSrcSobelImageActor);
        ui->qvtkWidget->GetRenderWindow()->AddRenderer(pSrcSobelRenderer);

        vtkSmartPointer<vtkImageSobel2D> pImageSobel = vtkSmartPointer<vtkImageSobel2D>::New();
        pImageSobel->SetInputData(pImageLuminance->GetOutput());
        pImageSobel->Update();

        // X 分量
        {
            vtkSmartPointer<vtkImageExtractComponents> pImageExtract = vtkSmartPointer<vtkImageExtractComponents>::New();
            pImageExtract->SetComponents(0);  // pImageSobel 包含X, Y方向的梯度,所以需要抽取其中一個
            pImageExtract->SetInputData(pImageSobel->GetOutput());
            pImageExtract->Update();

            vtkSmartPointer<vtkImageMathematics> pImageMath = vtkSmartPointer<vtkImageMathematics>::New();
            pImageMath->SetOperationToAbsoluteValue();
            pImageMath->SetInput1Data(pImageExtract->GetOutput());
            pImageMath->Update();

            double range[2];
            pImageMath->GetOutput()->GetScalarRange(range);

            vtkSmartPointer<vtkImageShiftScale> pImageShift = vtkSmartPointer<vtkImageShiftScale>::New();
            pImageShift->SetOutputScalarTypeToUnsignedChar();
            pImageShift->SetScale(255 / range[1]);
            pImageShift->SetInputData(pImageMath->GetOutput());
            pImageShift->Update();

            pSobelXImageActor = vtkSmartPointer<vtkImageActor>::New();
            pSobelXImageActor->SetInputData(pImageShift->GetOutput());
            pSobelXRenderer->AddActor(pSobelXImageActor);
            ui->qvtkWidget->GetRenderWindow()->AddRenderer(pSobelXRenderer);
        }

        // Y分量
        {
            vtkSmartPointer<vtkImageExtractComponents> pImageExtract = vtkSmartPointer<vtkImageExtractComponents>::New();
            pImageExtract->SetComponents(1);  // pImageSobel 包含X, Y方向的梯度,所以需要抽取其中一個
            pImageExtract->SetInputData(pImageSobel->GetOutput());
            pImageExtract->Update();

            vtkSmartPointer<vtkImageMathematics> pImageMath = vtkSmartPointer<vtkImageMathematics>::New();
            pImageMath->SetOperationToAbsoluteValue();
            pImageMath->SetInput1Data(pImageExtract->GetOutput());
            pImageMath->Update();

            double range[2];
            pImageMath->GetOutput()->GetScalarRange(range);

            vtkSmartPointer<vtkImageShiftScale> pImageShift = vtkSmartPointer<vtkImageShiftScale>::New();
            pImageShift->SetOutputScalarTypeToUnsignedChar();
            pImageShift->SetScale(255 / range[1]);
            pImageShift->SetInputData(pImageMath->GetOutput());
            pImageShift->Update();

            pSobelYImageActor = vtkSmartPointer<vtkImageActor>::New();
            pSobelYImageActor->SetInputData(pImageShift->GetOutput());
            pSobelYRenderer->AddActor(pSobelYImageActor);
            ui->qvtkWidget->GetRenderWindow()->AddRenderer(pSobelYRenderer);
        }

        // 梯度
        {
            vtkSmartPointer<vtkImageMagnitude> pImageMagnitude = vtkSmartPointer<vtkImageMagnitude>::New();
            pImageMagnitude->SetInputData(pImageSobel->GetOutput());
            pImageMagnitude->Update();

            double range[2];
            pImageMagnitude->GetOutput()->GetScalarRange(range);

            vtkSmartPointer<vtkImageShiftScale> pImageShift = vtkSmartPointer<vtkImageShiftScale>::New();
            pImageShift->SetOutputScalarTypeToUnsignedChar();
            pImageShift->SetScale(255 / range[1]);
            pImageShift->SetInputData(pImageMagnitude->GetOutput());
            pImageShift->Update();

            pSobelImageActor = vtkSmartPointer<vtkImageActor>::New();
            pSobelImageActor->SetInputData(pImageShift->GetOutput());
            pSobelRenderer->AddActor(pSobelImageActor);
            ui->qvtkWidget->GetRenderWindow()->AddRenderer(pSobelRenderer);
        }
    }

    // Candy算子
    {
        pSrcCandyImageActor = vtkSmartPointer<vtkImageActor>::New();
        pSrcCandyImageActor->SetInputData(pJpegReader->GetOutput());
        pSrcCandyRenderer->AddActor(pSrcCandyImageActor);
        ui->qvtkWidget->GetRenderWindow()->AddRenderer(pSrcCandyRenderer);

        vtkSmartPointer<vtkImageCast> pImageCast = vtkSmartPointer<vtkImageCast>::New();
        pImageCast->SetInputData(pImageLuminance->GetOutput());
        pImageCast->SetOutputScalarTypeToFloat();
        pImageCast->Update();

        vtkSmartPointer<vtkImageGaussianSmooth> pImageGaussianSmooth = vtkSmartPointer<vtkImageGaussianSmooth>::New();
        pImageGaussianSmooth->SetInputData(pImageCast->GetOutput());
        pImageGaussianSmooth->SetDimensionality(2);
        pImageGaussianSmooth->SetRadiusFactors(1, 1, 0);
        pImageGaussianSmooth->Update();

        vtkSmartPointer<vtkImageGradient> pImageGradient = vtkSmartPointer<vtkImageGradient>::New();
        pImageGradient->SetInputData(pImageGaussianSmooth->GetOutput());
        pImageGradient->SetDimensionality(2);
        pImageGradient->Update();

        vtkSmartPointer<vtkImageMagnitude> pImageMagnitude = vtkSmartPointer<vtkImageMagnitude>::New();
        pImageMagnitude->SetInputData(pImageGradient->GetOutput());
        pImageMagnitude->Update();

        vtkSmartPointer<vtkImageNonMaximumSuppression> pImageNonMax = vtkSmartPointer<vtkImageNonMaximumSuppression>::New();
        pImageNonMax->SetMagnitudeInputData(pImageMagnitude->GetOutput());
        pImageNonMax->SetVectorInputData(pImageGradient->GetOutput());
        pImageNonMax->SetDimensionality(2);
        pImageNonMax->Update();

        vtkSmartPointer<vtkImageConstantPad> pImagePad = vtkSmartPointer<vtkImageConstantPad>::New();
        pImagePad->SetInputData(pImageGradient->GetOutput());
        pImagePad->SetOutputNumberOfScalarComponents(3);
        pImagePad->SetConstant(0);
        pImagePad->Update();

        vtkSmartPointer<vtkImageToStructuredPoints> pImageStruct = vtkSmartPointer<vtkImageToStructuredPoints>::New();
        pImageStruct->SetInputData(pImageNonMax->GetOutput());
        pImageStruct->SetVectorInputData(pImagePad->GetOutput());
        pImageStruct->Update();

        vtkSmartPointer<vtkLinkEdgels> pImageLink = vtkSmartPointer<vtkLinkEdgels>::New();
        pImageLink->SetInputData(pImageStruct->GetOutput());
        pImageLink->SetGradientThreshold(2);
        pImageLink->Update();

        vtkSmartPointer<vtkThreshold> pImageThreshold = vtkSmartPointer<vtkThreshold>::New();
        pImageThreshold->SetInputData(pImageLink->GetOutput());
        pImageThreshold->ThresholdByUpper(10);
        pImageThreshold->AllScalarsOff();
        pImageThreshold->Update();

        vtkSmartPointer<vtkGeometryFilter> pImageGeometry = vtkSmartPointer<vtkGeometryFilter>::New();
        pImageGeometry->SetInputConnection(pImageThreshold->GetOutputPort());
        pImageGeometry->Update();

        vtkSmartPointer<vtkImageToStructuredPoints> pImageStruct2 = vtkSmartPointer<vtkImageToStructuredPoints>::New();
        pImageStruct2->SetInputData(pImageMagnitude->GetOutput());
        pImageStruct2->SetVectorInputData(pImagePad->GetOutput());
        pImageStruct2->Update();

        vtkSmartPointer<vtkSubPixelPositionEdgels> pSubImageEdgels = vtkSmartPointer<vtkSubPixelPositionEdgels>::New();
        pSubImageEdgels->SetInputData(pImageGeometry->GetOutput());
        pSubImageEdgels->SetGradMapsData(pImageStruct2->GetStructuredPointsOutput());
        pSubImageEdgels->Update();

        vtkSmartPointer<vtkStripper> pStripper = vtkSmartPointer<vtkStripper>::New();
        pStripper->SetInputData(pSubImageEdgels->GetOutput());
        pStripper->Update();

        vtkSmartPointer<vtkPolyDataMapper> pPolyDataMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
        pPolyDataMapper->SetInputConnection(pStripper->GetOutputPort());
        pPolyDataMapper->ScalarVisibilityOff();
        pPolyDataMapper->Update();

        vtkSmartPointer<vtkActor> planeActor = vtkSmartPointer<vtkActor>::New();
        planeActor->SetMapper(pPolyDataMapper);
        planeActor->GetProperty()->SetAmbient(1.0);
        planeActor->GetProperty()->SetDiffuse(0.0);
        planeActor->GetProperty()->SetColor(1.0, 1.0, 1.0);
        pCandyRenderer->AddActor(planeActor);
        ui->qvtkWidget->GetRenderWindow()->AddRenderer(pCandyRenderer);
    }

    // Laplace算子
    {
        pSrcLaplaceImageActor = vtkSmartPointer<vtkImageActor>::New();
        pSrcLaplaceImageActor->SetInputData(pJpegReader->GetOutput());
        pSrcLaplaceRenderer->AddActor(pSrcLaplaceImageActor);
        ui->qvtkWidget->GetRenderWindow()->AddRenderer(pSrcLaplaceRenderer);

        vtkSmartPointer<vtkImageLaplacian> pImageLaplace = vtkSmartPointer<vtkImageLaplacian>::New();
        pImageLaplace->SetInputData(pImageLuminance->GetOutput());
        pImageLaplace->SetDimensionality(2);
        pImageLaplace->Update();

        double range[2];
        pImageLaplace->GetOutput()->GetScalarRange(range);

        vtkSmartPointer<vtkImageShiftScale> pImageShift = vtkSmartPointer<vtkImageShiftScale>::New();
        pImageShift->SetOutputScalarTypeToUnsignedChar();
        pImageShift->SetScale(255 / range[1]);
        pImageShift->SetInputData(pImageLaplace->GetOutput());
        pImageShift->Update();

        pLaplaceImageActor = vtkSmartPointer<vtkImageActor>::New();
        pLaplaceImageActor->SetInputData(pImageShift->GetOutput());
        pLaplaceRenderer->AddActor(pLaplaceImageActor);
        ui->qvtkWidget->GetRenderWindow()->AddRenderer(pLaplaceRenderer);
    }

    pImageStyle       = vtkSmartPointer<vtkInteractorStyleImage>::New();
    ui->qvtkWidget->GetInteractor()->SetInteractorStyle(pImageStyle);

    ui->qvtkWidget->GetRenderWindow()->Render();
}
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>400</width>
    <height>300</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralWidget">
   <layout class="QHBoxLayout" name="horizontalLayout" stretch="2,5">
    <item>
     <layout class="QVBoxLayout" name="verticalLayout">
      <item>
       <widget class="QPushButton" name="pushButton">
        <property name="text">
         <string>選擇圖像</string>
        </property>
       </widget>
      </item>
      <item>
       <widget class="QTextBrowser" name="textBrowser"/>
      </item>
     </layout>
    </item>
    <item>
     <widget class="QVTKWidget" name="qvtkWidget"/>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menuBar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>400</width>
     <height>22</height>
    </rect>
   </property>
  </widget>
  <widget class="QToolBar" name="mainToolBar">
   <attribute name="toolBarArea">
    <enum>TopToolBarArea</enum>
   </attribute>
   <attribute name="toolBarBreak">
    <bool>false</bool>
   </attribute>
  </widget>
  <widget class="QStatusBar" name="statusBar"/>
 </widget>
 <layoutdefault spacing="6" margin="11"/>
 <customwidgets>
  <customwidget>
   <class>QVTKWidget</class>
   <extends>QWidget</extends>
   <header>QVTKWidget.h</header>
  </customwidget>
 </customwidgets>
 <resources/>
 <connections/>
</ui>

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章