void Difference::ComputeMinAndMaxInAllChannels() { std::cout << "ComputeMinAndMaxInAllChannels()" << std::endl; this->MinimumOfChannels.SetSize(this->Image->GetNumberOfComponentsPerPixel()); this->MaximumOfChannels.SetSize(this->Image->GetNumberOfComponentsPerPixel()); for(unsigned int i = 0; i < this->Image->GetNumberOfComponentsPerPixel(); ++i) { typedef itk::VectorIndexSelectionCastImageFilter<ImageType, FloatScalarImageType> IndexSelectionType; IndexSelectionType::Pointer indexSelectionFilter = IndexSelectionType::New(); indexSelectionFilter->SetIndex(i); indexSelectionFilter->SetInput(this->Image); indexSelectionFilter->Update(); typedef itk::MinimumMaximumImageCalculator <FloatScalarImageType> ImageCalculatorFilterType; ImageCalculatorFilterType::Pointer imageCalculatorFilter = ImageCalculatorFilterType::New(); imageCalculatorFilter->SetImage(indexSelectionFilter->GetOutput()); imageCalculatorFilter->Compute(); this->MinimumOfChannels[i] = imageCalculatorFilter->GetMinimum(); this->MaximumOfChannels[i] = imageCalculatorFilter->GetMaximum(); } }
bool AppITKImage::LoadAndValidate(const std::string& imagePath) { typedef itk::ImageFileReader<AppImageITKType> ReaderType; ReaderType::Pointer reader = ReaderType::New(); reader->SetFileName(imagePath); reader->Update(); if(!m_image) { m_image = AppImageITKType::New(); } // Deep copy m_image->SetRegions(reader->GetOutput()->GetLargestPossibleRegion()); m_image->SetNumberOfComponentsPerPixel(LfnIc::Image::Pixel::NUM_CHANNELS); m_image->Allocate(); itk::ImageRegionConstIterator<AppImageITKType> inputIterator(reader->GetOutput(), reader->GetOutput()->GetLargestPossibleRegion()); itk::ImageRegionIterator<AppImageITKType> outputIterator(m_image, m_image->GetLargestPossibleRegion()); while(!inputIterator.IsAtEnd()) { outputIterator.Set(inputIterator.Get()); ++inputIterator; ++outputIterator; } #if USE_CHANNEL_WEIGHTING // Setup channel weights - Uniform weighting - set the weight of each channel so it has the perceived range of 255 // If a channel already has the range 255, the weight is set to 1. If a channel has a range smaller // than 255, its weight will be > 1. If a channel has a weight larger than 255, its weight will be set to < 1. // A weight should never be negative. There is no magic to scaling to 255, it is just that usually there will be some // RGB type channels so 255 should make several of the weights close to 1. std::cout << "Weights: "; for (int c = 0; c < LfnIc::Image::Pixel::NUM_CHANNELS; c++) { typedef itk::Image<LfnIc::Image::Pixel::ChannelType, 2> ScalarImageType; typedef itk::VectorIndexSelectionCastImageFilter<AppImageITKType, ScalarImageType> IndexSelectionType; IndexSelectionType::Pointer indexSelectionFilter = IndexSelectionType::New(); indexSelectionFilter->SetIndex(c); indexSelectionFilter->SetInput(m_image); indexSelectionFilter->Update(); typedef itk::MinimumMaximumImageCalculator <ScalarImageType> ImageCalculatorFilterType; ImageCalculatorFilterType::Pointer imageCalculatorFilter = ImageCalculatorFilterType::New(); imageCalculatorFilter->SetImage(indexSelectionFilter->GetOutput()); imageCalculatorFilter->Compute(); // If there is no variation in a channel (take an image with only red (255,0,0) and blue (0,0,255) pixels for example), // then computing the weight doesn't make sense (and causes a divide by zero). if( (imageCalculatorFilter->GetMaximum() - imageCalculatorFilter->GetMinimum()) <= 0) { m_channelWeights[c] = 1.0f; } else { m_channelWeights[c] = 255.0f / (imageCalculatorFilter->GetMaximum() - imageCalculatorFilter->GetMinimum()); } std::cout << m_channelWeights[c] << " "; } std::cout << std::endl; // Now that the weights have been calculated, apply them directly to the image data. LfnIc::Image::Pixel* pixelPtr = AppITKImage::GetData(); for (int i = 0, n = GetWidth() * GetHeight(); i < n; ++i, ++pixelPtr) { LfnIc::Image::Pixel& pixel = *pixelPtr; for (int c = 0; c < LfnIc::Image::Pixel::NUM_CHANNELS; ++c) { pixel.channel[c] *= m_channelWeights[c]; } } #endif // USE_CHANNEL_WEIGHTING return true; }
void LidarSegmentationWidget::GenerateNeighborSinks() { Mask::Pointer sourcesImage = Mask::New(); sourcesImage->SetRegions(this->ImageRegion); ITKHelpers::IndicesToBinaryImage(this->Sources, sourcesImage); ITKHelpers::WriteImage(sourcesImage.GetPointer(), "sourcesImage.png"); // Dilate the mask std::cout << "Dilating mask..." << std::endl; typedef itk::BinaryBallStructuringElement<Mask::PixelType, 2> StructuringElementType; StructuringElementType structuringElement; structuringElement.SetRadius(1); structuringElement.CreateStructuringElement(); typedef itk::BinaryDilateImageFilter<Mask, Mask, StructuringElementType> BinaryDilateImageFilterType; BinaryDilateImageFilterType::Pointer dilateFilter = BinaryDilateImageFilterType::New(); dilateFilter->SetInput(sourcesImage); dilateFilter->SetKernel(structuringElement); dilateFilter->Update(); // Binary XOR the images to get the difference image //std::cout << "XORing masks..." << std::endl; typedef itk::XorImageFilter<Mask> XorImageFilterType; XorImageFilterType::Pointer xorFilter = XorImageFilterType::New(); xorFilter->SetInput1(dilateFilter->GetOutput()); xorFilter->SetInput2(sourcesImage); xorFilter->Update(); ITKHelpers::WriteImage(xorFilter->GetOutput(), "boundaryOfSegmentation.png"); // Iterate over the border pixels. If the closest pixel in the original segmentation has // a depth greater than a threshold, mark it as a new sink. Else, do not. std::cout << "Determining which boundary pixels should be declared background..." << std::endl; //std::cout << "There should be " << Helpers::CountNonZeroPixels(xorFilter->GetOutput()) // << " considered." << std::endl; typedef std::vector<itk::Index<2> > VectorOfPixelsType; VectorOfPixelsType newSinks; typedef itk::VectorIndexSelectionCastImageFilter<ImageType, FloatScalarImageType> IndexSelectionType; IndexSelectionType::Pointer indexSelectionFilter = IndexSelectionType::New(); indexSelectionFilter->SetIndex(3); indexSelectionFilter->SetInput(this->Image); indexSelectionFilter->Update(); FloatScalarImageType::Pointer depthImage = indexSelectionFilter->GetOutput(); //float sameObjectThreshold = 0.1f; VectorOfPixelsType consideredPixels; itk::ImageRegionIterator<Mask> imageIterator(xorFilter->GetOutput(), xorFilter->GetOutput()->GetLargestPossibleRegion()); while(!imageIterator.IsAtEnd()) { if(imageIterator.Get()) // If the current pixel is in question { consideredPixels.push_back(imageIterator.GetIndex()); } ++imageIterator; } std::cout << "There are " << consideredPixels.size() << " potential new sink pixels." << std::endl; for(VectorOfPixelsType::const_iterator iter = consideredPixels.begin(); iter != consideredPixels.end(); ++iter) { //std::cout << "Considering pixel " << consideredCounter << " (index " // << imageIterator.GetIndex() << ")" << std::endl; ImageType::PixelType currentPixel = this->Image->GetPixel(*iter); unsigned int radius = this->txtBackgroundCheckRadius->text().toUInt(); ImageType::RegionType desiredRegion = ITKHelpers::GetRegionInRadiusAroundPixel(*iter, radius); //std::cout << "desiredRegion: " << desiredRegion << std::endl; itk::ImageRegionIterator<Mask> sourcesImageIterator(sourcesImage, desiredRegion); std::vector<float> nonForegroundDepths; std::vector<float> foregroundDepths; while(!sourcesImageIterator.IsAtEnd()) { if(sourcesImageIterator.Get()) { foregroundDepths.push_back(depthImage->GetPixel(sourcesImageIterator.GetIndex())); } else { nonForegroundDepths.push_back(depthImage->GetPixel(sourcesImageIterator.GetIndex())); } ++sourcesImageIterator; } if(nonForegroundDepths.size() < 1) { } float nonForegroundMedian = Helpers::VectorMedian(nonForegroundDepths); float foregroundMedian = Helpers::VectorMedian(foregroundDepths); float difference = fabs(foregroundMedian - nonForegroundMedian); if(difference > this->txtBackgroundThreshold->text().toFloat()) { //std::cout << "Difference was " << difference << " so this is a sink pixel." << std::endl; newSinks.push_back(*iter); } else { //std::cout << "Difference was " << difference << " so this is NOT a sink pixel." << std::endl; } } // end loop over considered pixels unsigned char blue[3] = {0, 0, 255}; // ImageType::PixelType blue(3); // blue[0] = 0; // blue[1] = 0; // blue[2] = 255; ITKVTKHelpers::SetPixels(this->SourceSinkImageData.GetPointer(), consideredPixels, blue); this->SourceSinkImageData->Modified(); this->Refresh(); // Save the new sink pixels for inspection UnsignedCharScalarImageType::Pointer newSinksImage = UnsignedCharScalarImageType::New(); newSinksImage->SetRegions(this->Image->GetLargestPossibleRegion()); newSinksImage->Allocate(); ITKHelpers::IndicesToBinaryImage(newSinks, newSinksImage); ITKHelpers::WriteImage(newSinksImage.GetPointer(), "newSinks.png"); //std::cout << "Out of " << consideredCounter << " pixels considered, " // << backgroundCounter << " were declared background." << std::endl; // Set the new sinks std::cout << "Setting " << newSinks.size() << " new sinks." << std::endl; // Modify the list of sinks so it can be retrieved by the MainWindow after the segmentation is finished this->Sinks.insert(this->Sinks.end(), newSinks.begin(), newSinks.end()); UpdateSelections(); }