I am a beginner in ITK, VTK and Qt. I use visual studio 9.
I am trying to read a DICOM series with ITK and display with VTK in QVTKWidget (Qt). I based on this code http://www.itk.org/Wiki/VTK/Examples/Cxx/IO/ReadDICOMSeries and I modified according to my needs.
when I read the series DICOM with VTK and display it in QVTKWidget it works, but when I want to read this series with ITK and display with VTK in QVTKWidget, the program displays the first image of series and when I go to the next image with the mouse wheel, the program crashes.
when I debugged, I got this error:
void VTKImageExportBase::UpdateInformationCallbackFunction(void *userData)
{
static_cast< VTKImageExportBase * >
( userData )->UpdateInformationCallback();//the error is here
}
I tried ausssi ImageToVTKImageFilter class but with the same problem.
here is my code:
void essaieAppQtVTK::drawDCMSeries(std::string folderDCM)
{
typedef unsigned short PixelType;
const unsigned int Dimension = 3;
typedef itk::Image< PixelType, Dimension > ImageType;
typedef itk::VTKImageExport<ImageType> ImageExportType;
typedef itk::ImageSeriesReader< ImageType > ReaderType;
ReaderType::Pointer reader = ReaderType::New();
typedef itk::GDCMImageIO ImageIOType;
ImageIOType::Pointer dicomIO = ImageIOType::New();
reader->SetImageIO( dicomIO );
typedef itk::GDCMSeriesFileNames NamesGeneratorType;
NamesGeneratorType::Pointer nameGenerator = NamesGeneratorType::New();
nameGenerator->SetUseSeriesDetails( true );
nameGenerator->AddSeriesRestriction("0008|0021" );
nameGenerator->SetDirectory( folderDCM);
typedef std::vector< std::string > SeriesIdContainer;
const SeriesIdContainer & seriesUID = nameGenerator->GetSeriesUIDs();
std::cout << seriesUID.size() << std::endl;
SeriesIdContainer::const_iterator seriesItr = seriesUID.begin();
SeriesIdContainer::const_iterator seriesEnd = seriesUID.end();
while( seriesItr != seriesEnd )
{
std::cout << seriesItr->c_str() << std::endl;
seriesItr++;
}
std::string seriesIdentifier;
seriesIdentifier = seriesUID.begin()->c_str();
std::cout << seriesIdentifier.c_str() << std::endl;
typedef std::vector< std::string > FileNamesContainer;
FileNamesContainer fileNames;
fileNames = nameGenerator->GetFileNames( seriesIdentifier );
reader->SetFileNames( fileNames );
try
{
reader->Update();
}
catch (itk::ExceptionObject &ex)
{
std::cout << ex << std::endl;
}
//------------------------------------------------------------------------
// ITK to VTK pipeline connection.
//------------------------------------------------------------------------
// Create the itk::VTKImageExport instance and connect it to the
// itk::CurvatureFlowImageFilter.
ImageExportType::Pointer exporter = ImageExportType::New();
exporter->SetInput(reader->GetOutput());
// Create the vtkImageImport and connect it to the
// itk::VTKImageExport instance.
vtkImageImport* importer = vtkImageImport::New();
ConnectPipelines(exporter, importer);
//------------------------------------------------------------------------
// VTK pipeline.
//------------------------------------------------------------------------
this->imageViewer= vtkImageViewer2::New();
imageViewer->SetInput(importer->GetOutput());
// slice status message
//******same code *****//
// usage hint message
//******same code *****//
// create an interactor with our own style (inherit from vtkInteractorStyleImage)
// in order to catch mousewheel and key events
//******same code *****//
// add slice status message and usage hint message to the renderer
//******same code *****//
//to display the result:
ui.qvtkWidget->SetRenderWindow(imageViewer->GetRenderWindow());
ui.qvtkWidget->GetRenderWindow()->GetInteractor()- >SetInteractorStyle(myInteractorStyle);
imageViewer->Render();
ui.qvtkWidget->update();
}
Optional: My exporter and importer are as given below:
template <typename ITK_Exporter, typename VTK_Importer>
void ConnectPipelines(ITK_Exporter exporter, VTK_Importer* importer)
{
importer->SetUpdateInformationCallback(exporter->GetUpdateInformationCallback());
importer->SetPipelineModifiedCallback(exporter->GetPipelineModifiedCallback());
importer->SetWholeExtentCallback(exporter->GetWholeExtentCallback());
importer->SetSpacingCallback(exporter->GetSpacingCallback());
importer->SetOriginCallback(exporter->GetOriginCallback());
importer->SetScalarTypeCallback(exporter->GetScalarTypeCallback());
importer->SetNumberOfComponentsCallback(exporter->GetNumberOfComponentsCallback());
importer->SetPropagateUpdateExtentCallback(exporter- >GetPropagateUpdateExtentCallback());
importer->SetUpdateDataCallback(exporter->GetUpdateDataCallback());
importer->SetDataExtentCallback(exporter->GetDataExtentCallback());
importer->SetBufferPointerCallback(exporter->GetBufferPointerCallback());
importer->SetCallbackUserData(exporter->GetCallbackUserData());
}
/**
* This function will connect the given vtkImageExport filter to
* the given itk::VTKImageImport filter.
*/
template <typename VTK_Exporter, typename ITK_Importer>
void ConnectPipelines(VTK_Exporter* exporter, ITK_Importer importer)
{
importer->SetUpdateInformationCallback(exporter->GetUpdateInformationCallback());
importer->SetPipelineModifiedCallback(exporter->GetPipelineModifiedCallback());
importer->SetWholeExtentCallback(exporter->GetWholeExtentCallback());
importer->SetSpacingCallback(exporter->GetSpacingCallback());
importer->SetOriginCallback(exporter->GetOriginCallback());
importer->SetScalarTypeCallback(exporter->GetScalarTypeCallback());
importer->SetNumberOfComponentsCallback(exporter->GetNumberOfComponentsCallback());
importer->SetPropagateUpdateExtentCallback(exporter->GetPropagateUpdateExtentCallback());
importer->SetUpdateDataCallback(exporter->GetUpdateDataCallback());
importer->SetDataExtentCallback(exporter->GetDataExtentCallback());
importer->SetBufferPointerCallback(exporter->GetBufferPointerCallback());
importer->SetCallbackUserData(exporter->GetCallbackUserData());
}
Maybe there is a fault at the Pipline between ITK and VTK, please please can help me to find a solution for this problem, I spent two weeks looking for a solution but all methods have failed, maybe there has another method to bind ITK and VTK apart ImageToVTKImageFilter class. I count on your help. thank you in advance.
I faced same error at the same point you showed inside void VTKImageExportBase::UpdateInformationCallbackFunction function I was using ImageToVTKImageFilter for conversion. What I was missing is update of ITK pipeline before connecting it to VTK viewer. In ITK to VTK pipeline connection part your code is also missing same thing. So use:
exporter->SetInput(reader->GetOutput());
exporter->Update();
then go for further.
Related
I am trying to print caller function, line number and file name without throwing an error for normal debugging purpose in QML. I can print caller function name as follows
console.log("Caller Function Name"+arguments.callee.caller.name);
You can override qInstallMessageHandler default function and provide your custom function which also prints line number / caller. You can find an example in the linked documentation. Another partial example:
void loggingMessageHandler(QtMsgType type, const QMessageLogContext & context, const QString & msg)
{
QString timeStr(QDateTime::currentDateTime().toString("dd-MM-yy HH:mm:ss:zzz"));
QString contextString(QString("[%1 %2]").arg(context.file).arg(context.line));
mutex.lock();
QString level;
if(logFile.isOpen())
{
switch (type) {
case QtInfoMsg: level = QString("INF"); break;
case QtDebugMsg: level = QString("DEB"); break;
case QtWarningMsg: level = QString("WAR"); break;
case QtCriticalMsg: level = QString("CRT"); break;
case QtFatalMsg: level = QString("FTL"); break;
}
QTextStream stream(&logFile);
stream << timeStr << " " << contextString << "\t" << level << "\t" << msg << endl;
stream.flush();
}
#if defined(Q_OS_WIN)
OutputDebugString(reinterpret_cast<const wchar_t *>(level.append(' ' + msg + '\n').utf16()));
#elif defined(Q_OS_ANDROID)
android_default_message_handler(type, context, level.append(" " + msg));
#else // MACX || IOS || LINUX
fprintf(stderr, "%s\n", level.append(" " + msg).toLocal8Bit().constData());
#endif
mutex.unlock();
}
If logFile is open, logging data is wrote to that in a critical section delimited by a QMutex otherwise it is simply output to the standard output of each platform.
Whatever is the handler you define, it can be combined with categorized logging (available since Qt 5.2) to easily setup a custom logging facility tailored on your needs. You just need to define your logging categories, as described in this blog post, and call qCDebug, qCInfo(), qCWarning() and so on. Depending on the active categories (set via the static function setFilterRules() of QLoggingCategory) different logging info can be printed or skipped.
That's especially interesting now that Qt 5.8 is available. Since this release, you can use categories also in QML, i.e. you can call console functions and pass along a category, e.g.
function myFancyFunction() {
// foo code
console.log(myFancyCategory, "message");
// bar code
}
Also, categories declaration can be done fully in QML via the ad hoc type LoggingCategory.
ADDENDUM (Qt < 5.0)
The proposed solution works in a Qt 5.0+ environment with categories fully usable with Qt 5.3+ and QML categories available in Qt 5.8+; in a Qt 4.x environment you should override qInstallMsgHandler but you do not have a QMessageLogContext. That means you should manage file/line info outside the handler, e.g. you have to use Q_FUNC_INFO or rely on __FILE__ and __LINE__ in C++ (note that the latters have been removed in latest 5.x releases as e.g. discussed here).
I am using DCMTK to read and hopefully modify DICOM images. I have the following code:
#include <iostream>
#include <opencv\cv.h>
#include <dcmtk\dcmimgle\dcmimage.h>
int main() {
try {
DicomImage* dicomImage = new DicomImage("C:/Users/Kriselle/Documents/000004.dcm");
if ((dicomImage != NULL) && (dicomImage->isMonochrome())) {
dicomImage->writeBMP("C:/Users/Kriselle/Documents/z.bmp", 8);
std::cout << "z.bmp is created" << std::endl;
}
else {
std::cout << "dicomImage is null or not monochrome" << std::endl;
}
}
catch (cv::Exception e) {
std::cerr << e.what() << std::endl;
}
return 0;
}
All I did was create a DicomImage and write its pixel data to a BMP file with the filename I specified but the image returns only a gray image with the outline of the original image barely recognized.
This is what it should look like: https://www.dropbox.com/s/6dw8nlae8hfvqf6/000004.jpg?dl=0
This is what the code produces: https://www.dropbox.com/s/fff2kch124bzjqy/z.bmp?dl=0
Am I missing something in the code or did I not understand what the function does? Can anyone please enlighten me? Thank you very much!
As you can read in the API documentation of the DicomImage class, the default is that no VOI transformation is enabled when rendering monochrome DICOM images. In your case, this seems to be inappropriate, so you should specify a more appropriate VOI setting (e.g. a min-max window) or use one of the VOI windows stored in the DICOM dataset (if any).
By the way, after loading the image in the constructor, you should also check the status of this process using the getStatus() method.
I'm working on integrating T-Cube motor controller (http://www.thorlabs.de/newgrouppage9.cfm?objectgroup_id=2419) into the software based on Qt-4.8.1 package. Due to there is no manual or any sort of tutorial how to retrieve ActiveX object and how to call methods I did the following.
1) Looked through Windows registry looking for words similar to motor controller name. Found a candidate with CLSID "{3CE35BF3-1E13-4D2C-8C0B-DEF6314420B3}".
2) Tried initializing it in the following way (code provided is shortened, all result checks are removed in order to improve readability):
HRESULT h_result = CoInitializeEx(NULL, COINIT_MULTITHREADED);
pd->moto = new QAxObject();
initialized = moto->setControl( "{3CE35BF3-1E13-4D2C-8C0B-DEF6314420B3}" );
QString stri = browser->generateDocumentation();
obj->dynamicCall("SetHWSerialNum(int)", params);
QVariantList params;
params << 0;
params << 0.0;
int result = pd->moto->dynamicCall("GetPosition(int, double&)", params).toInt();
value = params[1].toFloat();
QVariantList params;
params << 0;
params << dist;
params << dist;
params << true;
int result = pd->moto->dynamicCall("MoveRelativeEx(int, double, double, bool)", params).toInt();
3) generateDocumentation() method gives perfect description of ~150 methods.
4) All dynamicCall() invocations cause "Error calling ...: Unknown error", where "..." is a first argument of dynamicCall() from the list generateDocumentation()'s given me.
5) If I insert into dynamicCall() any method which isn't presented in the documentation generated the output is different. So I suppose that methods in documentation generated really exist.
6) If I use #import directive and try calling directly avoiding QAxObject usage I see "mg17motor.tlh" file but none of interfaces described there contain any methods. So I can't use it directly as well. Is it normal?
I would be very much obliged for any advice.
You can find the ActiveX object using the OLE viewer. Then search for something like
APT.. or MG.. under all objects. Then find the parameter ProgID=MGMOTOR.MGMotorCtrl.1.
Now in Qt don't use QAxObject but QAxWidget. Then you get something like:
QAxWidget* aptMotor;
QVariant chanID = QVariant(0);
aptMotor = new QAxWidget();
aptMotor->setControl("MGMOTOR.MGMotorCtrl.1");
//Nice html documentation on available functions
QFile file("out.html");
file.open(QIODevice::WriteOnly | QIODevice::Text);
QTextStream out(&file);
out << aptMotor->generateDocumentation();
file.close();
aptMotor->setProperty("HWSerialNum",QVariant(83853493));
aptMotor->dynamicCall("StartCtrl");
aptMotor->dynamicCall("EnableHWChannel(QVariant)",chanID);
QThread::sleep(1); // Give it time to enable the channel
double pos(0);
aptMotor->dynamicCall("SetAbsMovePos(QVariant,QVariant)",chanID,QVariant(pos));
aptMotor->dynamicCall("MoveAbsolute(QVariant,QVariant,QVariant)",chanID,0);
aptMotor->dynamicCall("StopCtrl");
I am trying to get networking information (IP Address, Netmask, Route etc.) for all my interfaces in Qt using NetworkManager DBus interface. The problem is when I try to access the property "Addresses" of org.freedesktop.NetworkManager.IP4Config I get the following error
QDBusAbstractInterface: type QDBusRawType<0x616175>* must be registered with QtDBus before it can be used to read property org.freedesktop.NetworkManager.IP4Config.Addresses
Addresses are invalid
Error 2 = "Unregistered type QDBusRawType<0x616175>* cannot be handled"
However I can get the value of this property using dbus-send with following command.
dbus-send --system --print-reply --dest=org.freedesktop.NetworkManager \
/org/freedesktop/NetworkManager/IP4Config/0 \
org.freedesktop.DBus.Properties.Get \
string:"org.freedesktop.NetworkManager.IP4Config" \
string:"Addresses"
I can also get good values for above interface's mentioned property via qtdbusviewer. Following is my code snippet.
QDBusInterface interface(NM_DBUS_SERVICE, NM_DBUS_PATH, NM_DBUS_IFACE, QDBusConnection::systemBus());
// Get a list of all devices
QDBusReply<QList<QDBusObjectPath> > result = interface.call("GetDevices");
foreach (const QDBusObjectPath& connection, result.value()) {
QDBusInterface device(NM_DBUS_SERVICE, connection.path(), "org.freedesktop.NetworkManager.Device", QDBusConnection::systemBus());
if ( device.property("DeviceType").toInt() == NM_DEVICE_TYPE_ETHERNET ) {
// Get the IPv4 information if the device is active
if ( device.property("State").toInt() == NETWORK_DEVICE_CONNECTED ) {
QVariant ipv4config = device.property("Ip4Config");
if ( ipv4config.isValid() ) {
QDBusObjectPath path = qvariant_cast<QDBusObjectPath>(ipv4config);
QDBusInterface ifc(NM_DBUS_SERVICE, path.path(), "org.freedesktop.NetworkManager.IP4Config", QDBusConnection::systemBus());
if ( ifc.isValid() ) {
qDebug() << "Error 1 = " << ifc.lastError().message(); // No error. Everything is OK.
QVariant addresses = ifc.property("Addresses"); // Throwing the QDBusAbstractInterface Error where the property is good and does exist.
if ( addresses.isValid() ) {
qDebug () << "Addresses are valid";
} else {
qDebug () << "Addresses are invalid";
}
qDebug() << "Error 2 = " << ifc.lastError().message();
}
}
}
}
}
UPDATE # 1
I think it appears to be problem of types. Qt-Dbus type system does not understand the type of "Addresses" property so unable to create a QVariant out of it. So I added following lines before reading the property "Addresses". NetworkManager defines the property Addresses as following type, so I guess my typedef is good.
aau - "Array of tuples of IPv4 address/prefix/gateway. All 3 elements of each tuple are in network byte order. Essentially: [(addr, prefix, gateway), (addr, prefix, gateway), ...]"
typedef QList<QList<uint> > Addresses;
Q_DECLARE_METATYPE(Addresses)
qDBusRegisterMetaType<Addresses>()
QVariant addresses = ifc.property("Addresses");
Also I switched to Qt 5.1 (Earlier I was using 4.8), and I am getting the same error in following form.
Cannot construct placeholder type QDBusRawType
Thoughts / Suggestions
Regards,
Farrukh Arshad.
So far as per my research the problem is related to the type conversion. The property value is in the form of aau (as per NM Dbus documentation). QDbusInterface.property returns QVariant. It does find the property but unable to determine the type of the property hence giving me the error message. But my concern is, I have registered the custom type of this property with the Qt Meta Object system as I have mentioned in the Update # 1 then why it is giving me this error my type was registered with the system properly and qDBusRegisterMetaType did returned me a valid integer. In Qt 5.1 the origin of the error is in qdbusmaster.cpp. One article suggests to register meta type as mentioned below, but to no avail.
qRegisterMetaType<Addresses>("Addresses");
qDBusRegisterMetaType<Addresses>();
For now I don't have time to further dig into to see if it is some bug or I am missing something, but I will update this post once I have actual solution.
WORKAROUND
Following workaround will work to read the given property value. For this workaround to work you need to add qdbus-private instead of qdbus and include .
QVariant ipv4config = device.property("Ip4Config");
if ( ipv4config.isValid() ) {
QDBusObjectPath path = qvariant_cast<QDBusObjectPath>(ipv4config);
QDBusMessage message = QDBusMessage::createMethodCall(NM_DBUS_SERVICE, path.path(), QLatin1String("org.freedesktop.DBus.Properties"), QLatin1String("Get"));
QList<QVariant> arguments;
arguments << "org.freedesktop.NetworkManager.IP4Config" << "Addresses";
message.setArguments(arguments);
QDBusConnection connection = QDBusConnection::systemBus();
QDBusMessage reply = connection.call(message);
foreach(QVariant var, reply.arguments()) {
qDebug () << "String = " << QDBusUtil::argumentToString(var).toHtmlEscaped();
}
}
The string will show you the IP Address / Subnet Mask / Router IP which you will have to extract from the output. For record, I have taken this approach from qdbusviewer.
This is not the the right solution, but it will get you out of trouble for the time being. There is also a good article suggesting usage of custom types with Qt Dbus.
http://techbase.kde.org/Development/Tutorials/D-Bus/CustomTypes
The best solution I've found for this has been to write a QDBusAbstractInterface implementation:
typedef QList<QList<uint> > UIntListList;
Q_DECLARE_METATYPE(UIntListList)
class DBusIP4ConfigInterface : public QDBusAbstractInterface
{
Q_OBJECT
public:
DBusIP4ConfigInterface(const QString &service, const QString &path, const QDBusConnection &connection,
QObject *parent = 0)
{
qDBusRegisterMetaType<UIntListList>();
}
virtual ~DBusIP4ConfigInterface() { }
Q_PROPERTY(UIntListList Addresses READ addresses)
UIntListList addresses() const
{
return qvariant_cast<UIntListList>(property("Addresses"));
}
Q_PROPERTY(QString Gateway READ gateway)
QString gateway() const
{
return qvariant_cast<QString>(property("Gateway"));
}
Q_SIGNALS:
void PropertiesChanged(const QVariantMap &properties);
};
This has the added advantage of being pretty easy to use:
UIntListList addresses = m_dbusIP4Config->addresses();
Q_ASSERT(addresses.size() >= 1);
Q_ASSERT(addresses[0].size() == 3);
QHostAddress ip = QHostAddress(qFromBigEndian(addresses[0][0]));
I have a QTreeView which is populated through a reimplementation of QFileSystemModel. As far as I know, QFileSystemModel installs a QFileSystemWatcher on the rootPath. What I'm trying to do is notify in my program when a file is being deleted directicly on the rootPath but i havent found any signal o reimplemented function which provides me that information.
My application upload some files thrugh an ftp connection and when the file is fully uploaded i remove it from the location, so i want a notification from the reimplementation of QFileSystemModel when the file is deleted directicly (not from the remove method or something similar).
I Hope you can help me. I have searched a lot on the web but I cant find anything.
Cheers.
You can use the FileSystemModel's rowsAboutToBeRemoved signal (inherited from QAbstractItemModel).
It will be fired whenever a row is removed from the model. The parent, start and end parameters allow you to get to the filename (in column 0 of the children).
Sample code:
// once you have your model set up:
...
QObject::connect(model, SIGNAL(rowsAboutToBeRemoved(const QModelIndex&, int, int)),
receiver, SLOT(toBeRemoved(const QModelIndex&, int, int)));
...
// in receiver class:
public slots:
void toBeRemoved(const QModelIndex &parent, int start, int end) {
std::cout << start << " -> " << end << std::endl;
std::cout << parent.child(start, 0).data().typeName() << std::endl;
std::cout << qPrintable(parent.child(start, 0).data().toString()) << std::endl;
}
(Using std::cout isn't good practice with Qt I think, this is just to get you started.)
The other aboutToBe... signals from QAbstractItemModel can be used for the other events that happen on the filesystem.