void NoneLocalMeans::recompileOpenCLCode(Image::pointer input) { // Check if there is a need to recompile OpenCL code if(input->getDimensions() == mDimensionCLCodeCompiledFor && input->getDataType() == mTypeCLCodeCompiledFor && !recompile) return; recompile = false; OpenCLDevice::pointer device = getMainDevice(); std::string buildOptions = ""; if(!device->isWritingTo3DTexturesSupported()) { buildOptions = "-DTYPE=" + getCTypeAsString(mOutputType); } buildOptions += " -D WINDOW="; buildOptions += std::to_string((windowSize-1)/2); buildOptions += " -D GROUP="; buildOptions += std::to_string((groupSize-1)/2); buildOptions += " -D KVERSION="; buildOptions += std::to_string(k); buildOptions += " -D EUCLID="; buildOptions += std::to_string(k); cl::Program program; if(input->getDimensions() == 2) { program = getOpenCLProgram(device, "2D", buildOptions); } else { //createOpenCLProgram(std::string(FAST_SOURCE_DIR) + "Algorithms/NoneLocalMeans/NoneLocalMeans3Dgs.cl", "3D"); program = getOpenCLProgram(device, "3D", buildOptions); } mKernel = cl::Kernel(program, "noneLocalMeans"); mDimensionCLCodeCompiledFor = input->getDimensions(); mTypeCLCodeCompiledFor = input->getDataType(); }
void ImageImporter::execute() { if (mFilename == "") throw Exception("No filename was supplied to the ImageImporter"); uchar* convertedPixelData; // Load image from disk using Qt QImage image; reportInfo() << "Trying to load image..." << Reporter::end(); if(!image.load(mFilename.c_str())) { throw FileNotFoundException(mFilename); } reportInfo() << "Loaded image with size " << image.width() << " " << image.height() << Reporter::end(); QImage::Format format; if(mGrayscale) { format = QImage::Format_Grayscale8; } else { format = QImage::Format_RGB888; } QImage convertedImage = image.convertToFormat(format); // Get pixel data convertedPixelData = convertedImage.bits(); Image::pointer output = getOutputData<Image>(); std::cout << "image info" << std::endl; std::cout << convertedImage.width() << std::endl; std::cout << convertedImage.depth() << std::endl; std::cout << convertedImage.bytesPerLine() << std::endl; if(convertedImage.width()*convertedImage.depth()/8 != convertedImage.bytesPerLine()) { const int bytesPerPixel = (convertedImage.depth()/8); std::unique_ptr<uchar[]> fixedPixelData = std::make_unique<uchar[]>(image.width()*image.height()); // Misalignment for(int scanline = 0; scanline < image.height(); ++scanline) { std::memcpy( &fixedPixelData[scanline*image.width()*bytesPerPixel], &convertedPixelData[scanline*convertedImage.bytesPerLine()], image.width()*bytesPerPixel ); } output->create( image.width(), image.height(), TYPE_UINT8, mGrayscale ? 1 : 3, getMainDevice(), fixedPixelData.get() ); } else { output->create( image.width(), image.height(), TYPE_UINT8, mGrayscale ? 1 : 3, getMainDevice(), convertedPixelData ); } }
void BinaryThresholding::execute() { if(!mLowerThresholdSet && !mUpperThresholdSet) { throw Exception("BinaryThresholding need at least one threshold to be set."); } Image::pointer input = getStaticInputData<Image>(0); Segmentation::pointer output = getStaticOutputData<Segmentation>(0); output->createFromImage(input); if(getMainDevice()->isHost()) { throw Exception("Not implemented yet."); } else { OpenCLDevice::pointer device = OpenCLDevice::pointer(getMainDevice()); cl::Program program; if(input->getDimensions() == 3) { program = getOpenCLProgram(device, "3D"); } else { program = getOpenCLProgram(device, "2D"); } cl::Kernel kernel; if(mLowerThresholdSet && mUpperThresholdSet) { kernel = cl::Kernel(program, "tresholding"); kernel.setArg(3, mLowerThreshold); kernel.setArg(4, mUpperThreshold); } else if(mLowerThresholdSet) { kernel = cl::Kernel(program, "thresholdingWithOnlyLower"); kernel.setArg(3, mLowerThreshold); } else { kernel = cl::Kernel(program, "thresholdingWithOnlyUpper"); kernel.setArg(3, mUpperThreshold); } cl::NDRange globalSize; OpenCLImageAccess::pointer access = input->getOpenCLImageAccess(ACCESS_READ, device); if(input->getDimensions() == 2) { OpenCLImageAccess::pointer access2 = output->getOpenCLImageAccess(ACCESS_READ_WRITE, device); kernel.setArg(0, *access->get2DImage()); kernel.setArg(1, *access2->get2DImage()); globalSize = cl::NDRange(output->getWidth(), output->getHeight()); } else { // TODO no 3d image write support OpenCLImageAccess::pointer access2 = output->getOpenCLImageAccess(ACCESS_READ_WRITE, device); kernel.setArg(0, *access->get3DImage()); kernel.setArg(1, *access2->get3DImage()); globalSize = cl::NDRange(output->getWidth(), output->getHeight(), output->getDepth()); } kernel.setArg(2, (uchar)mLabel); cl::CommandQueue queue = device->getCommandQueue(); queue.enqueueNDRangeKernel( kernel, cl::NullRange, globalSize, cl::NullRange ); } }
void executeAlgorithmOnHost(Image::pointer input, Image::pointer output) { ImageAccess inputAccess = input->getImageAccess(ACCESS_READ); ImageAccess outputAccess = output->getImageAccess(ACCESS_READ_WRITE); T * inputData = (T*)inputAccess.get(); T * outputData = (T*)outputAccess.get(); unsigned int nrOfElements = input->getWidth()*input->getHeight()*input->getDepth()*input->getNrOfComponents(); for(unsigned int i = 0; i < nrOfElements; i++) { outputData[i] = 2.0*inputData[i]; } }
void SeededRegionGrowing::recompileOpenCLCode(Image::pointer input) { // Check if there is a need to recompile OpenCL code if(input->getDimensions() == mDimensionCLCodeCompiledFor && input->getDataType() == mTypeCLCodeCompiledFor) return; OpenCLDevice::pointer device = getMainDevice(); std::string buildOptions = ""; if(input->getDataType() == TYPE_FLOAT) { buildOptions = "-DTYPE_FLOAT"; } else if(input->getDataType() == TYPE_INT8 || input->getDataType() == TYPE_INT16) { buildOptions = "-DTYPE_INT"; } else { buildOptions = "-DTYPE_UINT"; } std::string filename; if(input->getDimensions() == 2) { filename = "Algorithms/SeededRegionGrowing/SeededRegionGrowing2D.cl"; } else { filename = "Algorithms/SeededRegionGrowing/SeededRegionGrowing3D.cl"; } int programNr = device->createProgramFromSource(std::string(FAST_SOURCE_DIR) + filename, buildOptions); mKernel = cl::Kernel(device->getProgram(programNr), "seededRegionGrowing"); mDimensionCLCodeCompiledFor = input->getDimensions(); mTypeCLCodeCompiledFor = input->getDataType(); }
void setScalarAsFloat(T* data, uint position, Image::pointer image, float value, uchar channel) { Vector3ui size = image->getSize(); if(position >= size.x()*size.y()*size.z()) throw OutOfBoundsException(); uint address = position*image->getNrOfComponents() + channel; if(image->getDataType() == TYPE_SNORM_INT16) { data[address] = value * 32767.0f;; } else if(image->getDataType() == TYPE_UNORM_INT16) { data[address] = value * 65535.0f;; } else { data[address] = value; } }
void ImageSlicer::execute() { Image::pointer input = getStaticInputData<Image>(); Image::pointer output = getStaticOutputData<Image>(); if(input->getDimensions() != 3) throw Exception("Image slicer can only be used for 3D images"); if(!mArbitrarySlicing && !mOrthogonalSlicing) throw Exception("No slice plane given to the ImageSlicer"); // TODO if(mOrthogonalSlicing) { orthogonalSlicing(input, output); } else { arbitrarySlicing(input, output); } }
float getScalarAsFloat(T* data, uint position, Image::pointer image, uchar channel) { Vector3ui size = image->getSize(); if(position >= size.x()*size.y()*size.z()) throw OutOfBoundsException(); T value = data[position*image->getNrOfComponents() + channel]; float floatValue; if(image->getDataType() == TYPE_SNORM_INT16) { floatValue = std::max(-1.0f, (float)value / 32767.0f); } else if(image->getDataType() == TYPE_UNORM_INT16) { floatValue = (float)value / 65535.0f; } else { floatValue = value; } return floatValue; }
void transferVTKDataToFAST(vtkImageData* image, Image::pointer output) { void* data; DataType type; switch(image->GetScalarType()) { case VTK_FLOAT: data = readVTKData<float>(image); type = TYPE_FLOAT; break; case VTK_CHAR: case VTK_SIGNED_CHAR: data = readVTKData<char>(image); type = TYPE_INT8; break; case VTK_UNSIGNED_CHAR: data = readVTKData<uchar>(image); type = TYPE_UINT8; break; case VTK_SHORT: data = readVTKData<short>(image); type = TYPE_INT16; break; case VTK_UNSIGNED_SHORT: data = readVTKData<ushort>(image); type = TYPE_UINT16; break; default: throw Exception("VTK image of unsupported type was supplied to the VTKImageImporter"); break; } int * size = image->GetDimensions(); if(image->GetDataDimension() == 2) { output->create(size[0]-1, size[1]-1,type,1,Host::getInstance(),data); } else if(image->GetDataDimension() == 3) { output->create(size[0]-1, size[1]-1,size[2]-1,type,1,Host::getInstance(),data); } else { throw Exception("Wrong number of dimensions in VTK image"); } deleteArray(data, type); }
void Dilation::execute() { Image::pointer input = getInputData<Image>(); if(input->getDataType() != TYPE_UINT8) { throw Exception("Data type of image given to Dilation must be UINT8"); } Image::pointer output = getOutputData<Image>(); output->createFromImage(input); SceneGraph::setParentNode(output, input); output->fill(0); OpenCLDevice::pointer device = std::dynamic_pointer_cast<OpenCLDevice>(getMainDevice()); cl::CommandQueue queue = device->getCommandQueue(); cl::Program program = getOpenCLProgram(device); cl::Kernel dilateKernel(program, "dilate"); Vector3ui size = input->getSize(); OpenCLImageAccess::pointer access = input->getOpenCLImageAccess(ACCESS_READ, device); dilateKernel.setArg(0, *access->get3DImage()); dilateKernel.setArg(2, mSize/2); if(!device->isWritingTo3DTexturesSupported()) { OpenCLBufferAccess::pointer access2 = output->getOpenCLBufferAccess(ACCESS_READ_WRITE, device); dilateKernel.setArg(1, *access2->get()); queue.enqueueNDRangeKernel( dilateKernel, cl::NullRange, cl::NDRange(size.x(), size.y(), size.z()), cl::NullRange ); } else { OpenCLImageAccess::pointer access2 = output->getOpenCLImageAccess(ACCESS_READ_WRITE, device); dilateKernel.setArg(1, *access2->get3DImage()); queue.enqueueNDRangeKernel( dilateKernel, cl::NullRange, cl::NDRange(size.x(), size.y(), size.z()), cl::NullRange ); } }
static igtl::TransformMessage::Pointer createIGTLTransformMessage(Image::pointer image) { // Create transform message from the scene graph information of image igtl::Matrix4x4 matrix; AffineTransformation::pointer T = image->getSceneGraphNode()->getTransformation(); for(int i = 0; i < 4; i++) { for(int j = 0; j < 4; j++) { matrix[i][j] = T->getTransform().matrix()(i,j); }} igtl::TransformMessage::Pointer message = igtl::TransformMessage::New(); message->SetDeviceName("DummyTransform"); message->SetMatrix(matrix); return message; }
void SegmentationRenderer::draw(Matrix4f perspectiveMatrix, Matrix4f viewingMatrix, float zNear, float zFar, bool mode2D) { std::lock_guard<std::mutex> lock(mMutex); OpenCLDevice::pointer device = std::dynamic_pointer_cast<OpenCLDevice>(getMainDevice()); if(mColorsModified) { // Transfer colors to device (this doesn't have to happen every render call..) std::unique_ptr<float[]> colorData(new float[3*mLabelColors.size()]); std::unordered_map<int, Color>::iterator it; for(it = mLabelColors.begin(); it != mLabelColors.end(); it++) { colorData[it->first*3] = it->second.getRedValue(); colorData[it->first*3+1] = it->second.getGreenValue(); colorData[it->first*3+2] = it->second.getBlueValue(); } mColorBuffer = cl::Buffer( device->getContext(), CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(float)*3*mLabelColors.size(), colorData.get() ); } if(mFillAreaModified) { // Transfer colors to device (this doesn't have to happen every render call..) std::unique_ptr<char[]> fillAreaData(new char[mLabelColors.size()]); std::unordered_map<int, Color>::iterator it; for(it = mLabelColors.begin(); it != mLabelColors.end(); it++) { if(mLabelFillArea.count(it->first) == 0) { // Use default value fillAreaData[it->first] = mFillArea; } else { fillAreaData[it->first] = mLabelFillArea[it->first]; } } mFillAreaBuffer = cl::Buffer( device->getContext(), CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(char)*mLabelColors.size(), fillAreaData.get() ); } mKernel = cl::Kernel(getOpenCLProgram(device), "renderToTexture"); mKernel.setArg(2, mColorBuffer); mKernel.setArg(3, mFillAreaBuffer); mKernel.setArg(4, mBorderRadius); mKernel.setArg(5, mOpacity); for(auto it : mDataToRender) { Image::pointer input = std::static_pointer_cast<Image>(it.second); uint inputNr = it.first; if(input->getDimensions() != 2) throw Exception("SegmentationRenderer only supports 2D images. Use ImageSlicer to extract a 2D slice from a 3D image."); if(input->getDataType() != TYPE_UINT8) throw Exception("SegmentationRenderer only support images with dat type uint8."); // Check if a texture has already been created for this image if(mTexturesToRender.count(inputNr) > 0 && mImageUsed[inputNr] == input) continue; // If it has already been created, skip it // If it has not been created, create the texture OpenCLImageAccess::pointer access = input->getOpenCLImageAccess(ACCESS_READ, device); cl::Image2D *clImage = access->get2DImage(); // Run kernel to fill the texture cl::CommandQueue queue = device->getCommandQueue(); if (mTexturesToRender.count(inputNr) > 0) { // Delete old texture glDeleteTextures(1, &mTexturesToRender[inputNr]); mTexturesToRender.erase(inputNr); glDeleteVertexArrays(1, &mVAO[inputNr]); mVAO.erase(inputNr); } cl::Image2D image; cl::ImageGL imageGL; std::vector<cl::Memory> v; GLuint textureID; // TODO The GL-CL interop here is causing glClear to not work on AMD systems and therefore disabled /* if(DeviceManager::isGLInteropEnabled()) { // Create OpenGL texture glGenTextures(1, &textureID); glBindTexture(GL_TEXTURE_2D, textureID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, input->getWidth(), input->getHeight(), 0, GL_RGBA, GL_FLOAT, 0); // Create CL-GL image imageGL = cl::ImageGL( device->getContext(), CL_MEM_READ_WRITE, GL_TEXTURE_2D, 0, textureID ); glBindTexture(GL_TEXTURE_2D, 0); glFinish(); mKernel.setArg(1, imageGL); v.push_back(imageGL); queue.enqueueAcquireGLObjects(&v); } else { */ image = cl::Image2D( device->getContext(), CL_MEM_READ_WRITE, cl::ImageFormat(CL_RGBA, CL_FLOAT), input->getWidth(), input->getHeight() ); mKernel.setArg(1, image); //} mKernel.setArg(0, *clImage); queue.enqueueNDRangeKernel( mKernel, cl::NullRange, cl::NDRange(input->getWidth(), input->getHeight()), cl::NullRange ); /*if(DeviceManager::isGLInteropEnabled()) { queue.enqueueReleaseGLObjects(&v); } else {*/ // Copy data from CL image to CPU auto data = make_uninitialized_unique<float[]>(input->getWidth() * input->getHeight() * 4); queue.enqueueReadImage( image, CL_TRUE, createOrigoRegion(), createRegion(input->getWidth(), input->getHeight(), 1), 0, 0, data.get() ); // Copy data from CPU to GL texture glGenTextures(1, &textureID); glBindTexture(GL_TEXTURE_2D, textureID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, input->getWidth(), input->getHeight(), 0, GL_RGBA, GL_FLOAT, data.get()); glBindTexture(GL_TEXTURE_2D, 0); glFinish(); //} mTexturesToRender[inputNr] = textureID; mImageUsed[inputNr] = input; queue.finish(); } glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); drawTextures(perspectiveMatrix, viewingMatrix, mode2D); glDisable(GL_BLEND); }
void executeAlgorithmOnHost(Image::pointer input, Image::pointer output, unsigned char group, unsigned char window, float strength, unsigned char sigma) { throw Exception("This is on host, does not work atm"); ImageAccess::pointer inputAccess = input->getImageAccess(ACCESS_READ); ImageAccess::pointer outputAccess = output->getImageAccess(ACCESS_READ_WRITE); T * inputData = (T*)inputAccess->get(); T * outputData = (T*)outputAccess->get(); unsigned int width = input->getWidth(); unsigned int height = input->getHeight(); //Window is window-1/2 //group is group-1/2 //strength is strength*strength //sigma is sigma*sigma //Not working atm with the T //Does not work with outofbounds atm //So this code is for all pixels inbound, meaning x + group + window < width / x - group - window > 0 //same for y for (int x = 0; x < width; x++){ for (int y = 0; y < height; y++){ double normSum = 0.0; double totSum = 0.0; double indi = 0.0; double groupTot = 0.0; double value = 0.0; for (int i = x - window; i <= x + window; i++){ for (int j = y - window; j <= y + window; j++){ if (i != x && j != y){ int mX = x - group; int mY = y - group; for (int k = i - group; k <= i + group; k++, mX++){ for (int l = j - group; l <= j + group; l++, mY++){ //This is wrong, need to fix T //indi = inputData[mX][mY] - inputData[k][l]; indi = abs(indi*indi); indi = exp( - (indi/strength)); groupTot += indi; } } //This is wrong, need to fix T //value = inputData[i][j]; double pA[] = {i,j}; double pB[] = {x,y}; //double dist = i, j - x, y; double dist = std::inner_product(std::begin(pA), std::end(pA), std::begin(pB), 0.0); double gaussWeight = exp(-(dist / (2.0 * sigma))); gaussWeight = gaussWeight / (2.0 * sigma); groupTot *= gaussWeight; normSum += groupTot; totSum += groupTot * value; groupTot = 0.0; } } } value = totSum / normSum; /* Not sure it needed if (value < 0){ value = 0; } if (value > 1.0){ value = 1.0f; } */ //This is wrong, need to fix T //outputData[x][y] = (T)value; } } }
/* void NoneLocalMeans::recompileOpenCLCode(Image::pointer input) { // Check if there is a need to recompile OpenCL code if (input->getDimensions() == mDimensionCLCodeCompiledFor && input->getDataType() == mTypeCLCodeCompiledFor && !recompile) return; OpenCLDevice::pointer device = getMainDevice(); recompile = false; std::string buildOptions = ""; const bool writingTo3DTextures = device->getDevice().getInfo<CL_DEVICE_EXTENSIONS>().find("cl_khr_3d_image_writes") != std::string::npos; if (!writingTo3DTextures) { switch (mOutputType) { case TYPE_FLOAT: buildOptions += " -DTYPE=float"; break; case TYPE_INT8: buildOptions += " -DTYPE=char"; break; case TYPE_UINT8: buildOptions += " -DTYPE=uchar"; break; case TYPE_INT16: buildOptions += " -DTYPE=short"; break; case TYPE_UINT16: buildOptions += " -DTYPE=ushort"; break; } } buildOptions += " -D WINDOW="; buildOptions += std::to_string((windowSize-1)/2); buildOptions += " -D GROUP="; buildOptions += std::to_string((groupSize-1)/2); std::string filename; //might have to seperate color vs gray here, for better runtime if (input->getDimensions() == 2) { if(k == 0){ filename = "Algorithms/NoneLocalMeans/NoneLocalMeans2Dconstant.cl"; }else if(k == 1){ filename = "Algorithms/NoneLocalMeans/NoneLocalMeans2Dgaussian.cl"; }else{ filename = "Algorithms/NoneLocalMeans/NoneLocalMeans2Dconstant.cl"; } //filename = "Algorithms/NoneLocalMeans/NoneLocalMeans2DgsPixelWise.cl"; //filename = "Algorithms/NoneLocalMeans/NoneLocalMeans2Dgs.cl"; //filename = "Algorithms/NoneLocalMeans/NoneLocalMeans2Dc.cl"; } else { filename = "Algorithms/NoneLocalMeans/NoneLocalMeans3Dgs.cl"; } int programNr = device->createProgramFromSource(std::string(FAST_SOURCE_DIR) + filename, buildOptions); mKernel = cl::Kernel(device->getProgram(programNr), "noneLocalMeans"); mDimensionCLCodeCompiledFor = input->getDimensions(); mTypeCLCodeCompiledFor = input->getDataType(); }*/ void NoneLocalMeans::execute() { Image::pointer input = getStaticInputData<Image>(0); Image::pointer output = getStaticOutputData<Image>(0); // Initialize output image ExecutionDevice::pointer device = getMainDevice(); if(mOutputTypeSet) { output->create(input->getSize(), mOutputType, input->getNrOfComponents()); output->setSpacing(input->getSpacing()); } else { output->createFromImage(input); } mOutputType = output->getDataType(); SceneGraph::setParentNode(output, input); if(device->isHost()) { switch(input->getDataType()) { fastSwitchTypeMacro(executeAlgorithmOnHost<FAST_TYPE>(input, output, groupSize, windowSize, denoiseStrength, sigma)); } } else { OpenCLDevice::pointer clDevice = device; recompileOpenCLCode(input); cl::NDRange globalSize; OpenCLImageAccess::pointer inputAccess = input->getOpenCLImageAccess(ACCESS_READ, device); if(input->getDimensions() == 2) { OpenCLImageAccess::pointer outputAccess = output->getOpenCLImageAccess(ACCESS_READ_WRITE, device); mKernel.setArg(2, (denoiseStrength*denoiseStrength)); mKernel.setArg(3, (sigma*sigma)); globalSize = cl::NDRange(input->getWidth(),input->getHeight()); mKernel.setArg(0, *inputAccess->get2DImage()); mKernel.setArg(1, *outputAccess->get2DImage()); clDevice->getCommandQueue().enqueueNDRangeKernel( mKernel, cl::NullRange, globalSize, cl::NullRange ); } else { // Create an auxilliary image //Image::pointer output2 = Image::New(); //output2->createFromImage(output); globalSize = cl::NDRange(input->getWidth(),input->getHeight(),input->getDepth()); if(clDevice->isWritingTo3DTexturesSupported()) { mKernel.setArg(2, (denoiseStrength*denoiseStrength)); mKernel.setArg(3, (sigma*sigma)); OpenCLImageAccess::pointer outputAccess = output->getOpenCLImageAccess(ACCESS_READ_WRITE, device); //OpenCLImageAccess::pointer outputAccess2 = output2->getOpenCLImageAccess(ACCESS_READ_WRITE, device); //cl::Image3D* image2; cl::Image3D* image; image = outputAccess->get3DImage(); //image2 = outputAccess->get3DImage(); mKernel.setArg(0, *inputAccess->get3DImage()); mKernel.setArg(1, *image); clDevice->getCommandQueue().enqueueNDRangeKernel( mKernel, cl::NullRange, globalSize, cl::NullRange ); }else{ mKernel.setArg(2, (denoiseStrength*denoiseStrength)); mKernel.setArg(3, (sigma*sigma)); OpenCLBufferAccess::pointer outputAccess = output->getOpenCLBufferAccess(ACCESS_READ_WRITE, device); mKernel.setArg(0, *inputAccess->get3DImage()); mKernel.setArg(1, *outputAccess->get()); clDevice->getCommandQueue().enqueueNDRangeKernel( mKernel, cl::NullRange, globalSize, cl::NullRange ); } } } }
static igtl::ImageMessage::Pointer createIGTLImageMessage(Image::pointer image) { // size parameters int size[3] = {(int)image->getWidth(), (int)image->getHeight(), (int)image->getDepth()}; // image dimension float spacing[3] = {image->getSpacing().x(), image->getSpacing().y(), image->getSpacing().z()}; // spacing (mm/pixel) int svoffset[3] = {0, 0, 0}; // sub-volume offset int scalarType; size_t totalSize = image->getWidth()*image->getHeight()*image->getDepth()*image->getNrOfChannels(); switch(image->getDataType()) { case TYPE_UINT8: scalarType = igtl::ImageMessage::TYPE_UINT8; totalSize *= sizeof(unsigned char); break; case TYPE_INT8: scalarType = igtl::ImageMessage::TYPE_INT8; totalSize *= sizeof(char); break; case TYPE_UINT16: scalarType = igtl::ImageMessage::TYPE_UINT16; totalSize *= sizeof(unsigned short); break; case TYPE_INT16: scalarType = igtl::ImageMessage::TYPE_INT16; totalSize *= sizeof(short); break; case TYPE_FLOAT: scalarType = igtl::ImageMessage::TYPE_FLOAT32; totalSize *= sizeof(float); break; } //------------------------------------------------------------ // Create a new IMAGE type message igtl::ImageMessage::Pointer imgMsg = igtl::ImageMessage::New(); imgMsg->SetDimensions(size); imgMsg->SetSpacing(spacing); imgMsg->SetNumComponents(image->getNrOfChannels()); imgMsg->SetScalarType(scalarType); imgMsg->SetDeviceName("DummyImage"); imgMsg->SetSubVolume(size, svoffset); imgMsg->AllocateScalars(); ImageAccess::pointer access = image->getImageAccess(ACCESS_READ); memcpy(imgMsg->GetScalarPointer(), access->get(), totalSize); return imgMsg; }
void MetaImageImporter::execute() { if(mFilename == "") throw Exception("Filename was not set in MetaImageImporter"); // Open and parse mhd file std::fstream mhdFile; mhdFile.open(mFilename.c_str(), std::fstream::in); if(!mhdFile.is_open()) throw FileNotFoundException(mFilename); std::string line; std::string rawFilename; bool sizeFound = false, rawFilenameFound = false, typeFound = false, dimensionsFound = false; std::string typeName; // Find NDims first bool imageIs3D = false; do { std::getline(mhdFile, line); if(line.substr(0, 5) == "NDims") { if(line.substr(5+3, 1) == "3") { imageIs3D = true; } else if(line.substr(5+3, 1) == "2") { imageIs3D = false; } dimensionsFound = true; } } while(!mhdFile.eof() && !dimensionsFound); if(!dimensionsFound) throw Exception("NDims not found in metaimage file."); // Reset and start reading file from beginning mhdFile.seekg(0); unsigned int width, height, depth = 1; unsigned int nrOfComponents = 1; Image::pointer output = getOutputData<Image>(0); Vector3f spacing(1,1,1), offset(0,0,0), centerOfRotation(0,0,0); Matrix3f transformMatrix = Matrix3f::Identity(); bool isCompressed = false; std::size_t compressedDataSize = 0; do{ std::getline(mhdFile, line); boost::trim(line); if(line.size() == 0) // line is empty continue; int firstSpace = line.find(" "); std::string key = line.substr(0, firstSpace); boost::trim(key); int equalSignPos = line.find("="); std::string value = line.substr(equalSignPos+1); boost::trim(value); if(key == "DimSize") { std::vector<std::string> values; boost::split(values, value, boost::is_any_of(" ")); // Remove any empty values: values.erase(std::remove(values.begin(), values.end(), ""), values.end()); if(imageIs3D) { if(values.size() != 3) throw Exception("DimSize in MetaImage file did not contain 3 numbers"); depth = boost::lexical_cast<int>(values[2]); } else { if(values.size() != 2) throw Exception("DimSize in MetaImage file did not contain 2 numbers"); } width = boost::lexical_cast<int>(values[0]); height = boost::lexical_cast<int>(values[1]); sizeFound = true; } else if(key == "CompressedData" && value == "True") { isCompressed = true; } else if(key == "CompressedDataSize") { compressedDataSize = boost::lexical_cast<int>(value); } else if(key == "ElementDataFile") { rawFilename = value; rawFilenameFound = true; // Remove any trailing spaces int pos = rawFilename.find(" "); if(pos > 0) rawFilename = rawFilename.substr(0,pos); // Get path name pos = mFilename.rfind('/'); if(pos > 0) rawFilename = mFilename.substr(0,pos+1) + rawFilename; } else if(key == "ElementType") { typeFound = true; typeName = value; // Remove any trailing spaces int pos = typeName.find(" "); if(pos > 0) typeName = typeName.substr(0,pos); if(typeName == "MET_SHORT") { } else if(typeName == "MET_USHORT") { } else if(typeName == "MET_CHAR") { } else if(typeName == "MET_UCHAR") { } else if(typeName == "MET_INT") { } else if(typeName == "MET_UINT") { } else if(typeName == "MET_FLOAT") { } else { throw Exception("Trying to read volume of unsupported data type", __LINE__, __FILE__); } } else if(key == "ElementNumberOfChannels") { nrOfComponents = boost::lexical_cast<int>(value.c_str()); if(nrOfComponents <= 0) throw Exception("Error in reading the number of components in the MetaImageImporter"); } else if(key == "ElementSpacing") { std::vector<std::string> values; boost::split(values, value, boost::is_any_of(" ")); // Remove any empty values: values.erase(std::remove(values.begin(), values.end(), ""), values.end()); if(imageIs3D) { if(values.size() != 3) throw Exception("ElementSpacing in MetaImage file did not contain 3 numbers"); spacing[0] = boost::lexical_cast<float>(values[0]); spacing[1] = boost::lexical_cast<float>(values[1]); spacing[2] = boost::lexical_cast<float>(values[2]); } else { if(values.size() != 2 && values.size() != 3) throw Exception("ElementSpacing in MetaImage file did not contain 2 or 3 numbers"); spacing[0] = boost::lexical_cast<float>(values[0]); spacing[1] = boost::lexical_cast<float>(values[1]); if(values.size() == 2) { spacing[2] = 1; } else { spacing[2] = boost::lexical_cast<float>(values[2]); } } } else if(key == "CenterOfRotation") { //reportInfo() << "WARNING: CenterOfRotation in Metaimage file ignored" << Reporter::end; std::vector<std::string> values; boost::split(values, value, boost::is_any_of(" ")); // Remove any empty values: values.erase(std::remove(values.begin(), values.end(), ""), values.end()); if(imageIs3D) { if(values.size() != 3) throw Exception("CenterOfRotation in MetaImage file did not contain 3 numbers"); centerOfRotation[0] = boost::lexical_cast<float>(values[0]); centerOfRotation[1] = boost::lexical_cast<float>(values[1]); centerOfRotation[2] = boost::lexical_cast<float>(values[2]); } else { if(values.size() != 2 && values.size() != 3) throw Exception("CenterOfRotation in MetaImage file did not contain 2 or 3 numbers"); centerOfRotation[0] = boost::lexical_cast<float>(values[0]); centerOfRotation[1] = boost::lexical_cast<float>(values[1]); if(values.size() == 2) { centerOfRotation[2] = 0; } else { centerOfRotation[2] = boost::lexical_cast<float>(values[2]); } } } else if(key == "Offset" || key == "Origin" || key == "Position") { std::vector<std::string> values; boost::split(values, value, boost::is_any_of(" ")); // Remove any empty values: values.erase(std::remove(values.begin(), values.end(), ""), values.end()); if(values.size() != 3) throw Exception("Offset/Origin/Position in MetaImage file did not contain 3 numbers"); offset[0] = boost::lexical_cast<float>(values[0].c_str()); offset[1] = boost::lexical_cast<float>(values[1].c_str()); offset[2] = boost::lexical_cast<float>(values[2].c_str()); } else if(key == "TransformMatrix" || key == "Rotation" || key == "Orientation") { std::vector<std::string> values; boost::split(values, value, boost::is_any_of(" ")); // Remove any empty values: values.erase(std::remove(values.begin(), values.end(), ""), values.end()); if(values.size() != 9) throw Exception("Encountered a transform/orientation/rotation matrix with incorrect number of elements in the MetaImageImporter"); for(unsigned int i = 0; i < 3; i++) { for(unsigned int j = 0; j < 3; j++) { transformMatrix(j,i) = boost::lexical_cast<float>(values[j+i*3].c_str()); }} } } while(!mhdFile.eof()); mhdFile.close(); if(!sizeFound || !rawFilenameFound || !typeFound || !dimensionsFound) throw Exception("Error reading the mhd file", __LINE__, __FILE__); void * data; DataType type; if(typeName == "MET_SHORT") { type = TYPE_INT16; data = readRawData<short>(rawFilename, width, height, depth, nrOfComponents, isCompressed, compressedDataSize); } else if(typeName == "MET_USHORT") { type = TYPE_UINT16; data = readRawData<unsigned short>(rawFilename, width, height, depth, nrOfComponents, isCompressed, compressedDataSize); } else if(typeName == "MET_CHAR") { type = TYPE_INT8; data = readRawData<char>(rawFilename, width, height, depth, nrOfComponents, isCompressed, compressedDataSize); } else if(typeName == "MET_UCHAR") { type = TYPE_UINT8; data = readRawData<unsigned char>(rawFilename, width, height, depth, nrOfComponents, isCompressed, compressedDataSize); } else if(typeName == "MET_FLOAT") { type = TYPE_FLOAT; data = readRawData<float>(rawFilename, width, height, depth, nrOfComponents, isCompressed, compressedDataSize); } if(imageIs3D) { output->create(width,height,depth,type,nrOfComponents,getMainDevice(),data); } else { output->create(width,height,type,nrOfComponents,getMainDevice(),data); } output->setSpacing(spacing); // Create transformation AffineTransformation::pointer T = AffineTransformation::New(); T->translation() = offset; T->linear() = transformMatrix; output->getSceneGraphNode()->setTransformation(T); // Clean up deleteArray(data, type); }
void DoubleFilter::execute() { if(!mInput.isValid()) { throw Exception("No input supplied to GaussianSmoothingFilter"); } Image::pointer input = mInput; Image::pointer output = mOutput; // Initialize output image output->createFromImage(input, mDevice); if(mDevice->isHost()) { // Execution device is Host, use the executeAlgorithmOnHost function with the given data type switch(input->getDataType()) { // This macro creates a case statement for each data type and sets FAST_TYPE to the correct C++ data type fastSwitchTypeMacro(executeAlgorithmOnHost<FAST_TYPE>(input, output)); } } else { // Execution device is an OpenCL device OpenCLDevice::pointer device = boost::static_pointer_cast<OpenCLDevice>(mDevice); // Set build options based on the data type of the data std::string buildOptions = ""; switch(input->getDataType()) { case TYPE_FLOAT: buildOptions = "-DTYPE=float"; break; case TYPE_INT8: buildOptions = "-DTYPE=char"; break; case TYPE_UINT8: buildOptions = "-DTYPE=uchar"; break; case TYPE_INT16: buildOptions = "-DTYPE=short"; break; case TYPE_UINT16: buildOptions = "-DTYPE=ushort"; break; } // Compile the code int programNr = device->createProgramFromSource(std::string(FAST_SOURCE_DIR) + "Tests/Algorithms/DoubleFilter.cl", buildOptions); cl::Kernel kernel = cl::Kernel(device->getProgram(programNr), "doubleFilter"); // Get global size for the kernel cl::NDRange globalSize(input->getWidth()*input->getHeight()*input->getDepth()*input->getNrOfComponents()); // Set the arguments for the kernel OpenCLBufferAccess inputAccess = input->getOpenCLBufferAccess(ACCESS_READ, device); OpenCLBufferAccess outputAccess = output->getOpenCLBufferAccess(ACCESS_READ_WRITE, device); kernel.setArg(0, *inputAccess.get()); kernel.setArg(1, *outputAccess.get()); // Execute the kernel device->getCommandQueue().enqueueNDRangeKernel( kernel, cl::NullRange, globalSize, cl::NullRange ); } // Update timestamp of the output data output->updateModifiedTimestamp(); }
void ImageSlicer::orthogonalSlicing(Image::pointer input, Image::pointer output) { OpenCLDevice::pointer device = getMainDevice(); // Determine slice nr and width and height unsigned int sliceNr; if(mOrthogonalSliceNr < 0) { switch(mOrthogonalSlicePlane) { case PLANE_X: sliceNr = input->getWidth()/2; break; case PLANE_Y: sliceNr = input->getHeight()/2; break; case PLANE_Z: sliceNr = input->getDepth()/2; break; } } else { // Check that mSliceNr is valid sliceNr = mOrthogonalSliceNr; switch(mOrthogonalSlicePlane) { case PLANE_X: if(sliceNr >= input->getWidth()) sliceNr = input->getWidth()-1; break; case PLANE_Y: if(sliceNr >= input->getHeight()) sliceNr = input->getHeight()-1; break; case PLANE_Z: if(sliceNr >= input->getDepth()) sliceNr = input->getDepth()-1; break; } } unsigned int slicePlaneNr, width, height; Vector3f spacing(0,0,0); switch(mOrthogonalSlicePlane) { case PLANE_X: slicePlaneNr = 0; width = input->getHeight(); height = input->getDepth(); spacing.x() = input->getSpacing().y(); spacing.y() = input->getSpacing().z(); break; case PLANE_Y: slicePlaneNr = 1; width = input->getWidth(); height = input->getDepth(); spacing.x() = input->getSpacing().x(); spacing.y() = input->getSpacing().z(); break; case PLANE_Z: slicePlaneNr = 2; width = input->getWidth(); height = input->getHeight(); spacing.x() = input->getSpacing().x(); spacing.y() = input->getSpacing().y(); break; } output->create(width, height, input->getDataType(), input->getNrOfComponents()); output->setSpacing(spacing); OpenCLImageAccess::pointer inputAccess = input->getOpenCLImageAccess(ACCESS_READ, device); OpenCLImageAccess::pointer outputAccess = output->getOpenCLImageAccess(ACCESS_READ_WRITE, device); cl::CommandQueue queue = device->getCommandQueue(); cl::Program program = getOpenCLProgram(device); cl::Kernel kernel(program, "orthogonalSlicing"); kernel.setArg(0, *inputAccess->get3DImage()); kernel.setArg(1, *outputAccess->get2DImage()); kernel.setArg(2, sliceNr); kernel.setArg(3, slicePlaneNr); queue.enqueueNDRangeKernel( kernel, cl::NullRange, cl::NDRange(width, height), cl::NullRange ); // TODO set scene graph transformation }
#include "catch.hpp" #include "VTKImageImporter.hpp" #include "VTKImageExporter.hpp" #include "ImageImporter.hpp" using namespace fast; // TODO rewrite this test so that it doesn't use the vtk exporter TEST_CASE("Import an image from VTK to FAST", "[fast][VTK]") { ImageImporter::pointer importer = ImageImporter::New(); importer->setFilename(std::string(FAST_TEST_DATA_DIR) + "US-2D.jpg"); Image::pointer fastImage = importer->getOutput(); // VTK Export vtkSmartPointer<VTKImageExporter> vtkExporter = VTKImageExporter::New(); vtkExporter->SetInput(fastImage); vtkSmartPointer<vtkImageData> vtkImage = vtkExporter->GetOutput(); vtkExporter->Update(); // VTK Import example VTKImageImporter::pointer vtkImporter = VTKImageImporter::New(); vtkImporter->setInput(vtkImage); Image::pointer importedImage = vtkImporter->getOutput(); vtkImporter->update(); CHECK(fastImage->getWidth() == importedImage->getWidth()); CHECK(fastImage->getHeight() == importedImage->getHeight()); CHECK(fastImage->getDepth() == 1); CHECK(fastImage->getDimensions() == 2); CHECK(fastImage->getDataType() == TYPE_FLOAT); }
void ManualImageStreamer::producerStream() { uint i = mStartNumber; int replays = 0; uint64_t previousTimestamp = 0; auto previousTimestampTime = std::chrono::high_resolution_clock::time_point::min(); int currentSequence = 0; while(true) { { std::unique_lock<std::mutex> lock(mStopMutex); if(mStop) { mStreamIsStarted = false; mFirstFrameIsInserted = false; mHasReachedEnd = false; break; } } try { Image::pointer image = mImages[currentSequence].at(i); addOutputData(0, image); if(image->getCreationTimestamp() != 0) { uint64_t timestamp = image->getCreationTimestamp(); // Wait as long as necessary before adding image // Time passed since last frame auto timePassed = std::chrono::duration_cast<std::chrono::milliseconds>( std::chrono::high_resolution_clock::now() - previousTimestampTime); while (timestamp > previousTimestamp + timePassed.count()) { // Wait int64_t left = (timestamp - previousTimestamp) - timePassed.count(); reportInfo() << "Sleeping for " << left << " ms" << reportEnd(); std::this_thread::sleep_for(std::chrono::milliseconds(left)); timePassed = std::chrono::duration_cast<std::chrono::milliseconds>( std::chrono::high_resolution_clock::now() - previousTimestampTime); } previousTimestamp = timestamp; previousTimestampTime = std::chrono::high_resolution_clock::now(); } if(mSleepTime > 0) std::this_thread::sleep_for(std::chrono::milliseconds(mSleepTime)); if(!mFirstFrameIsInserted) { { std::lock_guard<std::mutex> lock(mFirstFrameMutex); mFirstFrameIsInserted = true; } mFirstFrameCondition.notify_one(); } mNrOfFrames++; i += mStepSize; } catch(std::out_of_range &e) { if(i > 0) { reportInfo() << "Reached end of stream" << Reporter::end(); // If there where no files found at all, we need to release the execute method if(!mFirstFrameIsInserted) { { std::lock_guard<std::mutex> lock(mFirstFrameMutex); mFirstFrameIsInserted = true; } mFirstFrameCondition.notify_one(); } if(mLoop || (mNrOfReplays > 0 && replays != mNrOfReplays || (currentSequence < mImages.size()-1))) { // Restart stream previousTimestamp = 0; previousTimestampTime = std::chrono::high_resolution_clock::time_point::min(); replays++; i = mStartNumber; currentSequence++; // Go to first sequence if looping is enabled if(mLoop && currentSequence == mImages.size()) { currentSequence = 0; } continue; } mHasReachedEnd = true; // Reached end of stream break; } else { throw e; } } } }
void SeededRegionGrowing::executeOnHost(T* input, Image::pointer output) { ImageAccess::pointer outputAccess = output->getImageAccess(ACCESS_READ_WRITE); uchar* outputData = (uchar*)outputAccess->get(); // initialize output to all zero memset(outputData, 0, output->getWidth()*output->getHeight()*output->getDepth()); std::stack<Vector3ui> queue; // Add seeds to queue for(int i = 0; i < mSeedPoints.size(); i++) { Vector3ui pos = mSeedPoints[i]; // Check if seed point is in bounds if(pos.x() < 0 || pos.y() < 0 || pos.z() < 0 || pos.x() >= output->getWidth() || pos.y() >= output->getHeight() || pos.z() >= output->getDepth()) throw Exception("One of the seed points given to SeededRegionGrowing was out of bounds."); queue.push(pos); } // Process queue while(!queue.empty()) { Vector3ui pos = queue.top(); queue.pop(); // Add neighbors to queue for(int a = -1; a < 2; a++) { for(int b = -1; b < 2; b++) { for(int c = -1; c < 2; c++) { if(abs(a)+abs(b)+abs(c) != 1) // connectivity continue; Vector3ui neighbor(pos.x()+a,pos.y()+b,pos.z()+c); // Check for out of bounds if(neighbor.x() < 0 || neighbor.y() < 0 || neighbor.z() < 0 || neighbor.x() >= output->getWidth() || neighbor.y() >= output->getHeight() || neighbor.z() >= output->getDepth()) continue; // Check that voxel is not already segmented if(outputData[neighbor.x()+neighbor.y()*output->getWidth()+neighbor.z()*output->getWidth()*output->getHeight()] == 1) continue; // Check condition T value = input[neighbor.x()+neighbor.y()*output->getWidth()+neighbor.z()*output->getWidth()*output->getHeight()]; if(value >= mMinimumIntensity && value <= mMaximumIntensity) { // add it to segmentation outputData[neighbor.x()+neighbor.y()*output->getWidth()+neighbor.z()*output->getWidth()*output->getHeight()] = 1; // Add to queue queue.push(neighbor); } }}} } }
void SeededRegionGrowing::execute() { if(mSeedPoints.size() == 0) throw Exception("No seed points supplied to SeededRegionGrowing"); Image::pointer input = getStaticInputData<Image>(); if(input->getNrOfComponents() != 1) throw Exception("Seeded region growing currently doesn't support images with several components."); Segmentation::pointer output = getStaticOutputData<Segmentation>(); // Initialize output image output->createFromImage(input, getMainDevice()); if(getMainDevice()->isHost()) { ImageAccess::pointer inputAccess = input->getImageAccess(ACCESS_READ); void* inputData = inputAccess->get(); switch(input->getDataType()) { fastSwitchTypeMacro(executeOnHost<FAST_TYPE>((FAST_TYPE*)inputData, output)); } } else { OpenCLDevice::pointer device = getMainDevice(); recompileOpenCLCode(input); ImageAccess::pointer access = output->getImageAccess(ACCESS_READ_WRITE); uchar* outputData = (uchar*)access->get(); // Initialize to all 0s memset(outputData,0,sizeof(uchar)*output->getWidth()*output->getHeight()*output->getDepth()); // Add sedd points for(int i = 0; i < mSeedPoints.size(); i++) { Vector3ui pos = mSeedPoints[i]; // Check if seed point is in bounds if(pos.x() < 0 || pos.y() < 0 || pos.z() < 0 || pos.x() >= output->getWidth() || pos.y() >= output->getHeight() || pos.z() >= output->getDepth()) throw Exception("One of the seed points given to SeededRegionGrowing was out of bounds."); outputData[pos.x() + pos.y()*output->getWidth() + pos.z()*output->getWidth()*output->getHeight()] = 2; } access->release(); cl::NDRange globalSize; if(output->getDimensions() == 2) { globalSize = cl::NDRange(input->getWidth(),input->getHeight()); OpenCLImageAccess2D::pointer inputAccess = input->getOpenCLImageAccess2D(ACCESS_READ, device); mKernel.setArg(0, *inputAccess->get()); } else { globalSize = cl::NDRange(input->getWidth(),input->getHeight(), input->getDepth()); OpenCLImageAccess3D::pointer inputAccess = input->getOpenCLImageAccess3D(ACCESS_READ, device); mKernel.setArg(0, *inputAccess->get()); } OpenCLBufferAccess::pointer outputAccess = output->getOpenCLBufferAccess(ACCESS_READ_WRITE, device); cl::Buffer stopGrowingBuffer = cl::Buffer( device->getContext(), CL_MEM_READ_WRITE, sizeof(char)); cl::CommandQueue queue = device->getCommandQueue(); mKernel.setArg(1, *outputAccess->get()); mKernel.setArg(2, stopGrowingBuffer); mKernel.setArg(3, mMinimumIntensity); mKernel.setArg(4, mMaximumIntensity); bool stopGrowing = false; char stopGrowingInit = 1; char * stopGrowingResult = new char; int iterations = 0; do { iterations++; queue.enqueueWriteBuffer(stopGrowingBuffer, CL_TRUE, 0, sizeof(char), &stopGrowingInit); queue.enqueueNDRangeKernel( mKernel, cl::NullRange, globalSize, cl::NullRange ); queue.enqueueReadBuffer(stopGrowingBuffer, CL_TRUE, 0, sizeof(char), stopGrowingResult); if(*stopGrowingResult == 1) stopGrowing = true; } while(!stopGrowing); } }