DicomImage's writeBMP function produces unclear gray image - dicom

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.

Related

QMetaType::convert failed

I'm trying to use QMetaType::convert to convert a QJsonValue to another dynamic type. At first, I tested the following code with the dynamic type setting to QString, the conversion was failed.
QJsonValue value("test");
QString string;
if (!QMetaType::convert(&value, QMetaType::QJsonValue, &string, QMetaType::QString))
{
qDebug() << "failed";
}
Then, I found this static method to check whether the meta system has a registered conversion between two meta types.
qDebug() << QMetaType::hasRegisteredConverterFunction(QMetaType::QJsonValue, QMetaType::QString);
unfortunately, the result was false. Maybe QJsonValue is so complex that the conversion from QJsonValue to QString is not supported. Finally, I tried this, and the result was still false:
qDebug() << QMetaType::hasRegisteredConverterFunction(QMetaType::Int, QMetaType::Int);
It's odd, seems to be, Qt dose not implement the converter functions between basic meta types. And, users can't use QMetaType::registerConverter to register converter function between two basic meta types.
I still can't believe that Qt dosen't implement conversions between basic meta types, is there any initializtion or .pro setting I missed?
I guess you have the QMetaType system and the QVariant class to encapsulate Qt data types on the one hand, and QJsonValue to encapsulate a value in JSON on the other hand.
QMetaType::convert can deal with QVariant data only. What you can do is to extract the QVariant from your QJsonValue and then use the QMetaType system to convert your data you know being a QString.
// Your code
QJsonValue value("test");
QString string ;
if (!QMetaType::convert(&value, QMetaType::QJsonValue, &string, QMetaType::QString))
{
qDebug() << "failed";
}
// Extract the QVariant data
QVariant variant = value.toVariant() ;
// Two way to test conversion between QVariant and a type
qDebug() << "canConvert template:" << variant.canConvert<QString>() << endl
<< "canConvert parameter:" << variant.canConvert( QMetaType::QString ) ;
if( variant.canConvert<QString>() )
{
// Convert using QVariant methods
qDebug() << "QVariant toString:" << variant.toString() ;
// Convert Using QJsonValue methods
qDebug() << "QJsonValue toString:" << value.toString() ; // It's just a string representation of the data, not the actual data
}
outputs :
failed
canConvert template: true
canConvert parameter: true
QVariant toString: "test"
QJsonValue toString: "test"
PS: the QJsonValue::Type : String is different from the QVariant::Type : String (QMetaType::QString) so there is no relationship between them.

how to connect ITK to VTK with c++?

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.

How to parse dynamic response using QtSoap?

I have currently the response of type:
<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><soap:Body><StartBuisnessResponse xmlns=\"http://test.com/kerosene/mytest/\"><StartBuisnessResult><Commodity><_price>45</_price></Commodity><Commodity><_price>36</_price></Commodity></StartBuisnessResult></StartBuisnessResponse></soap:Body></soap:Envelope>
Here, the node is dynamic. In such a case, I am not able to find a way to parse the response SOAP XML using QtSoap.
This is the Code which works for fetching the first commodity:
QString str("<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><soap:Body><StartBuisnessResponse xmlns=\"http://cg.nic.in/kerosene/finotest/\"><StartBuisnessResult><Commodity><_price>45</_price></Commodity><Commodity><_price>36</_price></Commodity></StartBuisnessResult></StartBuisnessResponse></soap:Body></soap:Envelope>");
QByteArray *arr = new QByteArray();
arr->append(str);
QtSoapMessage *testMsg = new QtSoapMessage();
testMsg->setContent(*arr);
const QtSoapType &testCont = testMsg->returnValue();
const QtSoapType &price = testCont["Commodity"];
qDebug() << "The value of the _price here is " << price["_price"].value().toString();
But how do I traverse through the subsequent nodes in this case? Any idea?
If you follow the example shown on Qt Solutions QtSoap that they have for Google, you should be on your way with it.
http://doc.qt.digia.com/solutions/4/qtsoap/index.html
http://doc.qt.digia.com/solutions/4/qtsoap/google-example.html
An alternative if you don't want to try that is to use the QXmlStreamReader:
http://qt-project.org/doc/qt-4.8/qxmlstreamreader.html#details
Here is some quick code to get out the _price information from this:
// add "QT += xml" to your .pro
#include <QXmlStreamReader>
#include <QDebug>
QXmlStreamReader xml(str);
while (!xml.atEnd())
{
if (xml.readNextStartElement())
qDebug() << qPrintable(xml.name().toString());
if(xml.name().toString() == "_price")
{
qDebug() << "\t" << xml.readElementText().toInt();
}
}
You also have a number of other alternatives available, too. See Qt XML Processing.
Hope that helps.

Read exif metadata of images in Qt

In my Qt app I want to read exif data of images. QImage or QPixmap don't seem to provide such hooks.
Is there any API in Qt that allows reading exif without using external libraries like libexif?
EDIT: This is a duplicate of this
For me, the best choice was easyexif by Mayank Lahiri. You only need to add two files exif.cpp and exif.h to your project.
int main(int argc, char *argv[])
{
for (int i=1; i<argc; ++i){
QFile file(argv[i]);
if (file.open(QIODevice::ReadOnly)){
QByteArray data = file.readAll();
easyexif::EXIFInfo info;
if (int code = info.parseFrom((unsigned char *)data.data(), data.size())){
qDebug() << "Error parsing EXIF: code " << code;
continue;
}
qDebug() << "Camera model : " << info.Model.c_str();
qDebug() << "Original date/time : " << info.DateTimeOriginal.c_str();
} else
qDebug() << "Can't open file:" << argv[i];
}
return 0;
}
Try QExifImageHeader from qt extended framework. qtextended.org is not available for me? but you may search for other download mirrows.
QImageReader has a method named transformation() which is introduced in version 5.5, first you should try that.
You can also check the following link to see how it's done using Windows GDI in Qt, http://amin-ahmadi.com/2015/12/17/how-to-read-image-orientation-in-qt-using-stored-exif/

How to get magic number of a binary file

There is a magic number associated with each binary file , does anyone know how to retrieve this information from the file?
file <file_name>
magic numbers are usually stored in (linux):
/usr/share/file/magic
also check this link, someone was trying to use libmagic to get the information in C program, might be useful if you're writing something yourself.
Use libmagic from the file package to try and sniff out the type of file if that's your goal.
There are no general "magic" numbers in binary files on unix, though different formats might define their own. The above library knows about many of those and also use various other heuristics to try and figure out the format/type of file.
The unix file command uses magic number. see the file man page for more.(and where to find the magic file )
Read this: http://linux.die.net/man/5/magic
It's complex, and depends on the specific file type you're looking for.
There is a file command which in turn uses a magic library, the magic library reads from a file found in /etc called magic (this is installation dependant and may vary), which details what are the first few bytes of the file and tells the file what kind of a file it is, be it, jpg, binary, text, shell script. There is an old version of libmagic found on sourceforge. Incidentally, there is a related answer to this here.
Hope this helps,
Best regards,
Tom.
Expounding on #nos's answer:
Example below uses the default magic database to query the file passed on the command line. (Essentially an implementation of the file command. See man libmagic for more details/functions.
#include <iostream>
#include <magic.h>
#include <cassert>
int main(int argc, char **argv) {
if (argc == 1) {
std::cerr << "Usage " << argv[0] << " [filename]" << std::endl;
return -1;
}
const char * fname = argv[1];
magic_t cookie = magic_open(0);
assert (cookie !=nullptr);
int rc = magic_load(cookie, nullptr);
assert(rc == 0);
auto f= magic_file(cookie, fname);
if (f ==nullptr) {
std::cerr << magic_error(cookie) << std::endl;
} else {
std::cout << fname << ' ' << f << std::endl;
}
}

Resources