Wednesday, 2 July 2014

Histogram with Selection Callback




Input : Jpeg Image

Commands:
Left Click will Draw the rectangle and select the cell enclosed.
Right Click will Draw the rectangle and zoom the cells enclosed.


Steps to build:

  • Create Folder name ChartTest keep below files in it.
  • Create QChartwithInteraction.cpp and copy the below code
  • Create CMakeLists.txt and copy the below code
  • Use CMAKE.exe give path(c://ChartTest) of ChartTest in source and in Bin add bin next to it path(c://ChartTest//Bin) 
  •  Click on Configure it will create the Bin folder in that path automatically. Provide ITK and VTK library path if it won't take automatically.
  • Then again Click on Configure
  • Than Click on Generate
  • Now open the Bin folder and click on .sln file
  • Click on BuildSolution under Build or press F7 key to Build it in Visual studio 
  •  Now draw rectangle using Left click on Chart View you can see the selected cell value on command window.

Code:

QChartwithInteraction.cpp


//VTK
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include <vtkRenderWindowInteractor.h>
#include "vtkSmartPointer.h"
#include <vtkImageData.h>
#include <vtkJPEGReader.h>
//For chart Display 
#include "vtkContextView.h"
#include "vtkContextScene.h"
#include "vtkChartXY.h"
#include "vtkPlot.h"
#include "vtkTable.h"
#include <vtkImageAccumulate.h>
#include<vtkIntArray.h>
#include<vtkImageExtractComponents.h>
#include <vtkCommand.h>
#include <vtkIdTypeArray.h>
#include <vtkSelection.h> // for selecting XY chart 
#include <vtkContextMouseEvent.h>// For Mouse click translation
#include <vtkExtractSelection.h>
#include <vtkChartLegend.h>
#include <vtkAxis.h>

//Qt
#include <QApplication>
#include <QWidget>
#include <QMainWindow>
#include <QHBoxLayout>
#include "QVTKWidget.h"
#include "vtkQtTableView.h"


//------------------------



#define VTK_CREATE(type, name) \
vtkSmartPointer<type> name = vtkSmartPointer<type>::New()


class ChartCallback: public vtkCommand
{
public:
static ChartCallback *New() 
    { return new ChartCallback; }

void Intialize(double * min,QVTKWidget *qvtkWidget)
{
m_min=min;
m_qvtkWidget=qvtkWidget;
}
     

virtual void Execute(vtkObject *caller, unsigned long eventId, void* )
    { 
vtkSmartPointer<vtkChartXY> View = vtkChartXY::SafeDownCast(caller);
int j =View->GetSelectionMode();
       
vtkSmartPointer<vtkChartLegend> leg=View->GetLegend();
j=View->GetNumberOfItems();
       
  if(eventId==75)
  {
  int max=View->GetPlot(0)->GetSelection()->GetNumberOfTuples();
  std::cout<<"Selected Intensity"<<endl;
for(int i=-1;i<max-1;i++)
{
double data=View->GetPlot(0)->GetSelection()->GetComponent(View->GetNumberOfPlots(),i);
data=double(m_min[0]+data);
std::cout<<data<<endl;
}
  }

  View->Update();
  m_qvtkWidget->update();
}
public:
vtkSmartPointer<vtkExtractSelection> m_extract;
vtkSmartPointer<vtkAnnotationLink> m_link;
vtkSmartPointer<vtkSelection> m_sel;
vtkSmartPointer<vtkTable> m_table;
vtkSmartPointer<vtkAnnotationLink> link;
double *m_min;
QVTKWidget *m_qvtkWidget;


};

//---------------------------------------------------------------
int main( int argc, char * argv [] )
{
// Qt initialization
QApplication app(argc, argv);
QMainWindow mainWindow;
mainWindow.setGeometry(0, 0, 1150, 600);

// QVTK set up and initialization
QVTKWidget *qvtkWidget = new QVTKWidget(&mainWindow);
    
//Setting Data Path to VTK Reader 
vtkSmartPointer<vtkJPEGReader> reader=vtkSmartPointer<vtkJPEGReader>::New();
reader->SetFileName("D:\\testing_Dataset\\Data.jpg");//DataSet Path

reader->Update();
double X[2];
reader->GetOutput()->GetScalarRange(X);

//Generate Table 
vtkTable * table= vtkTable::New();     
vtkIntArray* arrX = vtkIntArray::New(); 
arrX->SetName("Intensity");
table->AddColumn(arrX); 
vtkIntArray* arrC = vtkIntArray::New();  
arrC->SetName("No of Pixels"); 
table->AddColumn(arrC); 

vtkSmartPointer<vtkImageExtractComponents> extract = 
    vtkSmartPointer<vtkImageExtractComponents>::New();
extract->SetInput( reader->GetOutput());
    extract->SetComponents( 0 );
    extract->Update();
    vtkSmartPointer<vtkImageAccumulate> histogram = 
    vtkSmartPointer<vtkImageAccumulate>::New();
    histogram->SetInputConnection( extract->GetOutputPort() );
histogram->SetComponentExtent( int(X[0]),int(X[1]),0,0,0,0 );
    histogram->SetComponentOrigin( 0,0,0 );
    histogram->SetComponentSpacing( 1,0,0 );
    histogram->SetIgnoreZero( 0 );
    histogram->Update();
int x = int(X[0]);
int y = int(X[1]);

int range = y-x;

    int* output = static_cast<int*>(histogram->GetOutput()->GetScalarPointer());
table->SetNumberOfRows(range+1);
for( int i = 0; i<=range+1; i++,x++)
      {
 table->SetValue(i,0,x);
 table->SetValue(i,1,*output);
 
 output++;
      }

vtkPlot *line = 0;
//Chart Implimentation
vtkChartXY *chart = vtkChartXY::New();
vtkContextView *view=vtkContextView::New();
line = chart->AddPlot(vtkChart::BAR);
line->SetInput(table,0,1);

chart->GetAxis(vtkAxis::LEFT)->SetTitle("No of Pixel");
chart->GetAxis(vtkAxis::BOTTOM)->SetTitle("intensity");

chart->GetAxis(vtkAxis::BOTTOM)->SetGridVisible(false);
chart->GetAxis(vtkAxis::LEFT)->SetGridVisible(false);
chart->SetForceAxesToBounds(true);//start from minimum range
chart->SetBarWidthFraction(1);
    //Draw Chart
chart->Update();
view->GetScene()->AddItem(chart);
// Translate the Widget Action //Left mouse click for select the chart // Right click for Zoom 
chart->SetActionToButton(vtkChart::SELECT, 
vtkContextMouseEvent::LEFT_BUTTON); 
chart->SetActionToButton(vtkChart::ZOOM, 
vtkContextMouseEvent::RIGHT_BUTTON); 

    //Providing Chart callback
vtkSmartPointer<ChartCallback> cbk =
vtkSmartPointer<ChartCallback>::New();
cbk->Intialize(X,qvtkWidget);

//Important:: This is for telling Callback to send signal if Chart cell will select
chart->AddObserver(vtkSelection::CELL,cbk);
  
//----------------------------------------------------------  

#if VTK_MAJOR_VERSION <= 5
  line->SetInput(table, 0, 1);
  
#else
  line->SetInputData(table, 0, 1);
#endif
line->SetColor(0, 0.5, 255, 255);

//Setting ContexView in QvtkWidget
view->SetInteractor(qvtkWidget->GetInteractor());
qvtkWidget->SetRenderWindow(view->GetRenderWindow());
view->GetRenderWindow()->SetMultiSamples(0);
view->GetInteractor()->Initialize();


// Now lets try to add a table view
QWidget *widget = new QWidget(&mainWindow);
QHBoxLayout *layout = new QHBoxLayout(widget);
VTK_CREATE(vtkQtTableView, tableView);
tableView->SetSplitMultiComponentColumns(true);
tableView->AddRepresentationFromInput(table);
tableView->Update();
layout->addWidget(qvtkWidget, 2);
layout->addWidget(tableView->GetWidget());
mainWindow.setCentralWidget(widget);

// Now show the application and start the event loop
mainWindow.show();

return app.exec();
}



CMakeLists.txt

PROJECT (Charts)

IF(NOT VTK_BINARY_DIR)
FIND_PACKAGE(VTK REQUIRED)
IF(NOT VTK_USE_CHARTS)
  MESSAGE(FATAL_ERROR "Example ${PROJECT_NAME} requires VTK_USE_CHARTS.")
ENDIF(NOT VTK_USE_CHARTS)
INCLUDE(${VTK_USE_FILE})
ENDIF(NOT VTK_BINARY_DIR)


IF(VTK_USE_QVTK)
  FIND_PACKAGE(Qt4 REQUIRED)
  INCLUDE(${QT_USE_FILE})
  INCLUDE_DIRECTORIES(${QT_INCLUDE_DIR})
  ADD_EXECUTABLE(QChartTable QChartwithInteraction.cpp)
  TARGET_LINK_LIBRARIES(QChartTable
    QVTK
    ${QT_LIBRARIES}
    vtkRendering
    vtkCharts
  )

ENDIF(VTK_USE_QVTK)



                             *NOTE: Let me know if you need any modification in it.