I am trying to convert a DICOM file into PLY format using VTK to further convert it into .pcd (point cloud format). I have followed the example provided here.
However in the above example the code is supposed to change .vtu format into .ply format. I changed the code to convert the .dcm format into .ply format as shown below. The build succeeded and the exe file is working as well, however, it does not write the required output file. Can anyone please point out where did I go wrong??
#include <vtkSmartPointer.h>
#include <vtkPolyData.h>
#include <vtkDICOMImageReader.h>
#include <vtkXMLPolyDataReader.h>
#include <vtkPLYWriter.h>
int main(int argc, char *argv[])
{
if(argc < 3)
{
std::cerr << "Required arguments: input.vtp output.ply" << std::endl;
return EXIT_FAILURE;
}
std::string inputFileName = argv[1];
std::string outputFileName = argv[2];
// Read the DICOM file in the specified directory.
vtkSmartPointer<vtkDICOMImageReader> reader =
vtkSmartPointer<vtkDICOMImageReader>::New();
reader->SetFileName(inputFilename.c_str());
reader->Update();
vtkSmartPointer<vtkPLYWriter> writer = vtkSmartPointer<vtkPLYWriter>::New();
writer->SetFileName(outputFileName.c_str());
writer->SetInputConnection(reader->GetOutputPort());
writer->Update();
return EXIT_SUCCESS;
}
Below is an example of a simple contouring of a DICOM file and extraction of the largest connected area of polydata from the Marching Cubes filter then saved as a PLY format file. This should answer your question.
`
#include <vtkSmartPointer.h>
#include <vtkPolyData.h>
#include <vtkDICOMImageReader.h>
#include "vtkMarchingCubes.h"
#include "vtkPolyDataConnectivityFilter.h"
#include <vtkPLYWriter.h>
int main(int argc, char *argv[])
{
if(argc < 3)
{
std::cerr << "Required arguments: input.dcm output.ply" << std::endl;
return EXIT_FAILURE;
}
std::string inputFileName = argv[1];
std::string outputFileName = argv[2];
// Read the DICOM file in the specified directory.
vtkSmartPointer<vtkDICOMImageReader> reader =
vtkSmartPointer<vtkDICOMImageReader>::New();
reader->SetFileName(inputFilename.c_str());
reader->Update();
//arb. threshold for bone based on CT Hounsfield Units
float isoValue = 400.0
vtkSmartPointer<vtkMarchingCubes> surface = vtkSmartPointer<vtkMarchingCubes>::New();
surface->SetInputConnection(reader->GetOutputPort());
surface->ComputeNormalsOn();
surface->SetValue(0, isoValue);
surface->Update()
// To remain largest region
vtkSmartPointer<vtkPolyDataConnectivityFilter> confilter =
vtkSmartPointer<vtkPolyDataConnectivityFilter>::New();
confilter->SetInputConnection(surface->GetOutputPort());
confilter->SetExtractionModeToLargestRegion();
confilter->Update();
vtkSmartPointer<vtkPLYWriter> writer = vtkSmartPointer<vtkPLYWriter>::New();
writer->SetFileName(outputFileName.c_str());
writer->SetInputConnection(confilter->GetOutputPort());
writer->Update();
return EXIT_SUCCESS;
}
Related
Here is a example (part of code) from OpenCV (https://docs.opencv.org/3.4.0/d4/da4/group__core__xml.html):
test.yml
%YAML:1.0
---
frameCount: 5
read.cpp
#include "opencv2/opencv.hpp"
#include <time.h>
using namespace cv;
using namespace std;
int main()
{
FileStorage fs("test.yml", FileStorage::READ);
int frameCount = (int) fs["frameCount"];
cout << frameCount << endl;
return 0;
}
Given the code, it works well and reads the yaml file. But when I remove %YAML:1.0, the code throws:
OpenCV Error: Unknown error code -49 (Input file is empty) in cvOpenFileStorage, file /home/pengfei/Documents/opencv-3.3.1/modules/core/src/persistence.cpp, line 4484
terminate called after throwing an instance of 'cv::Exception'
what(): /home/pengfei/Documents/opencv-3.3.1/modules/core/src/persistence.cpp:4484: error: (-49) Input file is empty in function cvOpenFileStorage
[1] 27146 abort (core dumped) ./Read
But I checked the yaml.org. There is no rule stating %YAML:1.0 is necessary. (http://yaml.org/start.html)
**My questions are (updated according to answer from #zindarod ): **
1. Is this OpenCV specific feature??
Yes, this is OpenCV specific requirment.
const char* yaml_signature = "%YAML";
const char* json_signature = "{";
const char* xml_signature = "<?xml";
OpenCV checks the file signature, then decide how to interpret the file.
2. How to know the yaml version I should use??
The yaml verison doesn't matter too much.
But it's better to use 1.0 specification. Probably OpenCV cannot parse other new specifications.
In OpenCV-3.3.1 in function cvOpenFileStorage located at /modules/core/src/persistence.cpp:
...
else
{
if( mem )
{
fs->strbuf = filename;
fs->strbufsize = fnamelen;
}
size_t buf_size = 1 << 20;
const char* yaml_signature = "%YAML";
const char* json_signature = "{";
const char* xml_signature = "<?xml";
char buf[16];
icvGets( fs, buf, sizeof(buf)-2 );
char* bufPtr = cv_skip_BOM(buf);
size_t bufOffset = bufPtr - buf;
if(strncmp( bufPtr, yaml_signature, strlen(yaml_signature) ) == 0)
fs->fmt = CV_STORAGE_FORMAT_YAML;
else if(strncmp( bufPtr, json_signature, strlen(json_signature) ) == 0)
fs->fmt = CV_STORAGE_FORMAT_JSON;
else if(strncmp( bufPtr, xml_signature, strlen(xml_signature) ) == 0)
fs->fmt = CV_STORAGE_FORMAT_XML;
else if(fs->strbufsize == bufOffset)
CV_Error(CV_BADARG_ERR, "Input file is empty");
...
OpenCV checks for file signature (json, yaml and xml). The version of YAML does not matter, as long as the first line contains the string "%YAML" in it.
This is what my code looks like, I got the undefined reference to imread and so on:
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main( int argc, const char** argv )
{
Mat img = imread("MyPicture.jpg", CV_LOAD_IMAGE_UNCHANGED); //read the image data in the file "MyPic.JPG" and store it in 'img'
if (img.empty()) //check whether the image is loaded or not
{
cout << "Error : Image cannot be loaded..!!" << endl;
//system("pause"); //wait for a key press
return -1;
}
namedWindow("MyWindow", CV_WINDOW_AUTOSIZE); //create a window with the name "MyWindow"
imshow("MyWindow", img); //display the image which is stored in the 'img' in the "MyWindow" window
waitKey(0); //wait infinite time for a keypress
destroyWindow("MyWindow"); //destroy the window with the name, "MyWindow"
return 0;
}
I am using Codeblocks and the g++ compiler. Also I have linked the opencv_world310d.lib to debug and opencv_world310.lib to release.
Plus I have given the path in searchdirectory compiler and linker.
Any hints?
I used vtkDICOMImageReader to read the DICOM file. I used the vtkImageThreshold to threshold a CT image. And now i want to write it back to my hard disk before further processing.
I tried vtkImageWriter library to write it back. But it is not working when i try to open the file using 3D slicer. I am much grateful if anyone can suggest me a methodology for writing Dicom files.
i have included my code here and i am trying to threshold a dicom image and viewing it. Then i would like to save the thresholded image as a dicom file. But i could not succeed in doing that. please help me.
thanks in advance.
#include <itkImageToVTKImageFilter.h>
#include <vtkSmartPointer.h>
#include <vtkImageData.h>
#include <vtkImageThreshold.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleImage.h>
#include <vtkRenderer.h>
#include <vtkImageMapper3D.h>
#include <vtkImageActor.h>
#include <vtkImageCast.h>
#include <vtkNIFTIImageWriter.h>
#include <vtkImageMandelbrotSource.h>
#include <vtkImageViewer2.h>
#include <vtkDICOMImageReader.h>
int main(int argc, char* argv[])
{
std::string folder = argv[1];
vtkSmartPointer<vtkDICOMImageReader> reader =
vtkSmartPointer<vtkDICOMImageReader>::New();
reader->SetFileName(folder.c_str());
reader->Update();
vtkSmartPointer<vtkImageViewer2> imageViewer =
vtkSmartPointer<vtkImageViewer2>::New();
imageViewer->SetInputConnection(reader->GetOutputPort());
// threshold the images
vtkSmartPointer<vtkImageThreshold> imageThreshold =
vtkSmartPointer<vtkImageThreshold>::New();
imageThreshold->SetInputConnection(reader->GetOutputPort());
// unsigned char lower = 127;
unsigned char upper = 511;
imageThreshold->ThresholdByLower(upper);
imageThreshold->ReplaceInOn();
imageThreshold->SetInValue(0);
imageThreshold->ReplaceOutOn();
imageThreshold->SetOutValue(511);
imageThreshold->Update();
// Create actors
vtkSmartPointer<vtkImageActor> inputActor =
vtkSmartPointer<vtkImageActor>::New();
inputActor->GetMapper()->SetInputConnection(
reader->GetOutputPort());
vtkSmartPointer<vtkImageActor> thresholdedActor =
vtkSmartPointer<vtkImageActor>::New();
thresholdedActor->GetMapper()->SetInputConnection(
imageThreshold->GetOutputPort());
// There will be one render window
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->SetSize(600, 300);
// And one interactor
vtkSmartPointer<vtkRenderWindowInteractor> interactor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
interactor->SetRenderWindow(renderWindow);
// Define viewport ranges
// (xmin, ymin, xmax, ymax)
double leftViewport[4] = {0.0, 0.0, 0.5, 1.0};
double rightViewport[4] = {0.5, 0.0, 1.0, 1.0};
// Setup both renderers
vtkSmartPointer<vtkRenderer> leftRenderer =
vtkSmartPointer<vtkRenderer>::New();
renderWindow->AddRenderer(leftRenderer);
leftRenderer->SetViewport(leftViewport);
leftRenderer->SetBackground(.6, .5, .4);
vtkSmartPointer<vtkRenderer> rightRenderer =
vtkSmartPointer<vtkRenderer>::New();
renderWindow->AddRenderer(rightRenderer);
rightRenderer->SetViewport(rightViewport);
rightRenderer->SetBackground(.4, .5, .6);
leftRenderer->AddActor(inputActor);
rightRenderer->AddActor(thresholdedActor);
leftRenderer->ResetCamera();
rightRenderer->ResetCamera();
renderWindow->Render();
interactor->Start();
vtkSmartPointer<vtkNIFTIImageWriter> writer =
vtkSmartPointer<vtkNIFTIImageWriter>::New();
writer->SetInputConnection(reader->GetOutputPort());
writer->SetFileName("output");
writer->Write();
// writing the thresholded image to the hard drive.
//this is the part i am not able to code. Please can somebody help me please?
return EXIT_SUCCESS;
}
First, do you want to save out the thresholded image or just the image as read in? If not replace reader with imageThreshold
writer->SetInputConnection(reader->GetOutputPort())
From looking at the VTK tests of NIFTI readers and writers the following options may be required...
writer->SetNIFTIHeader(reader->GetNIFTIHeader())
writer->SetQFac(reader->GetQFac());
writer->SetTimeDimension(reader->GetTimeDimension());
writer->SetTimeSpacing(reader->GetTimeSpacing());
writer->SetRescaleSlope(reader->GetRescaleSlope());
writer->SetRescaleIntercept(reader->GetRescaleIntercept());
writer->SetQFormMatrix(reader->GetQFormMatrix());
I would test with adding these options and then see what you get
I think VTK is a little bit confused to process image. I only use it to display image.I wrote a piece of code for you. The code which read , threshold and write dicom image is below.It use only itk. I think it fills the bill.
#include "itkBinaryThresholdImageFilter.h"
#include "itkImageFileReader.h"
#include "itkGDCMImageIO.h"
#include "itkImageFileWriter.h"
#include "itkImage.h"
int main () {
typedef unsigned char InputPixelType ; //Pixel Type of Input image
typedef unsigned char OutputPixelType; //Pixel Type of Output image
const unsigned int InputDimension = 2; //Dimension of image
typedef itk::Image < InputPixelType, InputDimension > InputImageType; //Type definition of Input Image
typedef itk::Image < InputPixelType, InputDimension > OutputImageType;//Type definition of Output Image
typedef itk::ImageSeriesReader< InputImageType > ReaderType;//Type definition of Reader
typedef itk::BinaryThresholdImageFilter<InputImageType, OutputImageType > FilterType; // Type definition of Filter
typedef itk::ImageFileWriter<OutputImageType> ImageWriterType; //Definition of Writer of Ouput image
typedef itk::GDCMImageIO ImageIOType; //Type definition of Image IO for Dicom images
//Starts Reading Process
ReaderType::Pointer reader = ReaderType::New(); //Creates reader
ImageIOType::Pointer gdcmImageIO_input = ImageIOType::New(); //Creates ImageIO object for input image
reader->SetImageIO( gdcmImageIO_input ); // Sets image IO of reader
reader->SetFileNames( "example_image.dcm" ); // Sets filename to reader
//Exceptional handling
try
{
reader->UpdateLargestPossibleRegion();
}
catch (itk::ExceptionObject & e)
{
std::cerr << "exception in file reader " << std::endl;
std::cerr << e << std::endl;
return EXIT_FAILURE;
}
// Start filtering process
FilterType::Pointer filter = FilterType::New(); //Creates filter
filter->SetInput( reader->GetOutput() );
filter->SetOutsideValue( 0); // Set pixel value which are out of lower and upper threshold value
filter->SetInsideValue( 255 );// Set pixel value which are within lower and upper threshold value
filter->SetLowerThreshold( 25 ); // Lower threshold value 25
filter->SetUpperThreshold( 150 );// Upper threshold value 150
filter->Update();
//Starts Writing Process
ImageWriterType::Pointer imageWriter = ImageWriterType::New(); // Creates writer
ImageIOType::Pointer gdcmImageIO_output = ImageIOType::New(); // Creates Image IO object for output image
imageWriter->SetImageIO( gdcmImageIO_output ); // Set image IO as dicom
imageWriter->SetInput(filter->GetOutput() ); // Connects output of filter with to input of writer
imageWriter->SetFileName(example_image_thresholded.dcm); // Sets output file name
//Exceptional handling
try
{
imageWriter->Update();
}
catch ( itk::ExceptionObject &exception )
{
std::cerr << "Exception in file writer ! " << std::endl;
std::cerr << exception << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
I’m beginner in C++ and OpenCV. As you know stasm is a C++ software library for finding features in faces that introduced in: http://www.milbo.users.sonic.net/stasm I want to use stasm 4.1 library for image recognition. I read manual stasm but I don’t understand how add "stasm_lib.h" to my project!! Please guide me step by step for locating face landmarks, after running I got this error:
cannot open include file: fetal error C1083 'stasm_lib.h' No such file or directory
#include <stdio.h>
#include <stdlib.h>
#include "opencv/highgui.h"
#include "stasm_lib.h"
int main()
{
static const char* path = "../data/testface.jpg";
cv::Mat_<unsigned char> img(cv::imread(path, CV_LOAD_IMAGE_GRAYSCALE));
if (!img.data)
{
printf("Cannot load %s\n", path);
exit(1);
}
int foundface;
float landmarks[2 * stasm_NLANDMARKS]; // x,y coords
if (!stasm_search_single(&foundface, landmarks,
(char*)img.data, img.cols, img.rows, path, "../data"))
{
printf("Error in stasm_search_single: %s\n", stasm_lasterr());
exit(1);
}
if (!foundface)
printf("No face found in %s\n", path);
else
{
// draw the landmarks on the image as white dots
stasm_force_points_into_image(landmarks, img.cols, img.rows);
for (int i = 0; i < stasm_NLANDMARKS; i++)
img(cvRound(landmarks[i*2+1]), cvRound(landmarks[i*2])) = 255;
}
cv::imshow("stasm minimal", img);
cv::waitKey();
return 0;
}`
Thanks a lot
Newbie question and yes I have spent a lot of time sifting through similar questions and Answers with no luck.
What I am trying to do is save frames from a video file in a sequential order. I have managed to save one image using c and I cannot seem to save images after that. I have started using c++ in opencv instead of c and all I can do is view the video and not save any jpg's from it.
I am using opencv2.4.4a on mac if that helps.
below is my c example
#include <stdio.h>
#include <stdlib.h>
#include <opencv/cv.h>
#include <opencv/highgui.h>
#include <iostream>
using namespace cv;
using namespace std;
int main (int argc, char** argv)
{
//initializing capture from file
CvCapture * capture = cvCaptureFromAVI ("/example/example.mov");
//Capturing a frame
IplImage* img = 0;
if(!cvGrabFrame(capture)) //capture a frame
{
printf)Could not grab a fram\n\7");
exit(0);
}
img=cvRerieveFrame(capture); //retrieve the captured frame
//writing an image to a file
if (!cvSaveImage("/frames/test.jpg", img))
printf("Could not save: %s\n","test.jpg");
//free resources
cvReleaseCapture(&capture);
}
Thank you in advance
edit to the above.
I have added to the above code which results in an image to be saved with the test.jpg and then gets rewritten with the next frame. How do I tell opencv to not copy over the last image and rename the next frame to test_2.jpg eg, test_1.jpg, test_2.jpg and so on?
double num_frames = cvGetCaptureProperty (capture, CV_CAP_PROP_FRAME_COUNT);
for (int i = 0; i < (int)num_frames; i++)
{
img = cvQueryFrame(capture);
cvSaveImage("frames/test.jpg", img);
}
cvReleaseCapture(&capture);
}
This is my code... I tryed a lot and finally made it
this is c++ using opencv 3... hope it works
#include "opencv2/opencv.hpp"
#include <sstream>
#include <iostream>
using namespace cv;
using namespace std;
Mat frame,img;
int counter;
int main(int,char**)
{
VideoCapture vid("video3.avi");
while (!vid.isOpened())
{
VideoCapture vid("video2.MOV");
cout << "charging" << endl;
waitKey(1000);
}
cout << "Video opened!" << endl;
while(1)
{
stringstream file;
vid.read(frame);
if(frame.empty()) break;
file << "/home/pedro/workspace/videoFrame/Debug/frames/image" << counter << ".jpg";
counter++;
imwrite(file.str(),frame);
char key = waitKey(10);
if ( key == 27)
{break;}
}
}
Use an index that will keep track of the number part in the filename. In the image capturing loop, add the index with the filename and build the final filename.
here is an example :
while(1)
{
cap.read ( frame);
if( frame.empty()) break;
imshow("video", frame);
char filename[80];
sprintf(filename,"C:/Users/cssc/Desktop/testFolder/test_%d.png",i);
imwrite(filename, frame);
i++;
char key = waitKey(10);
if ( key == 27) break;
}
This is my way to do in Python3.0. Have to have CV2 3+ version for it to work.
This function saves images with frequency given.
import cv2
import os
print(cv2.__version__)
# Function to extract frames
def FrameCapture(path,frame_freq):
# Path to video file
video = cv2.VideoCapture(path)
success, image = video.read()
# Number of frames in video
fps = int(video.get(cv2.CAP_PROP_FPS))
length = int(video.get(cv2.CAP_PROP_FRAME_COUNT))
print('FPS:', fps)
print('Extracting every {} frames'.format(frame_freq))
print('Total Frames:', length)
print('Number of Frames Saved:', (length // frame_freq) + 1)
# Directory for saved frames
try:
frame_dir = path.split('.')[0]
os.mkdir(frame_dir)
except FileExistsError:
print('Directory ({}) already exists'.format(frame_dir))
# Used as counter variable
count = 0
# checks whether frames were extracted
success = 1
# vidObj object calls read
# function extract frames
while count < length :
video.set(cv2.CAP_PROP_POS_FRAMES , count)
success, image = video.read()
# Saves the frames with frame-count
cv2.imwrite(frame_dir + "/frame%d.jpg" % count, image)
count = count + frame_freq