Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convert cv::Mat to vtkImageData?

Tags:

c++

opencv

vtk

How can I convert efficiently from a cv::Mat to a vtkImageData in C++? I search for a method that works for BW and COLOR images.

like image 422
lucasahli Avatar asked Aug 20 '18 13:08

lucasahli


2 Answers

Below is a simplified version of the answer above by @lucasahli. It uses an efficient memcpy instead of a double for loop.

NOTE: For color images, you may need to flip the image channels from bgr to rgb ordering, which i used mixChannels to achieve.

vtkSmartPointer<vtkImageData> OpenCVToVtkConverter::convertCVMatToVtkImageData(const cv::Mat &sourceCVImage, bool flipOverXAxis) {
  vtkSmartPointer<vtkImageData> outputVtkImage = vtkSmartPointer<vtkImageData>::New();

  int numOfChannels = sourceCVImage.channels();

  // dimension set to 1 for z since it's 2D
  outputVtkImage->SetDimensions(sourceCVImage.cols, sourceCVImage.rows, 1);

  // NOTE: if your image isn't uchar for some reason you'll need to change this type
  outputVtkImage->AllocateScalars(VTK_UNSIGNED_CHAR, numOfChannels);

  // the flipped image data gets put into tempCVImage
  cv::Mat tempCVImage;
  if(flipOverXAxis){ // Normally you should flip the image!
    cv::flip(sourceCVImage, tempCVImage, 0);
  }
  else {
    tempCVImage = sourceCVImage;
  }

  // the number of byes in the cv::Mat, assuming the data type is uchar
  size_t byte_count = sourceCVImage.cols * sourceCVImage.rows * numOfChannels * sizeof(unsigned char);

  // copy the internal cv::Mat data into the vtkImageData pointer
  memcpy(outputVtkImage->GetScalarPointer(), tempCVImage.data, byte_count);

  outputVtkImage->Modified();
  return outputVtkImage;
}
like image 160
enotad Avatar answered Oct 22 '22 10:10

enotad


vtkSmartPointer<vtkImageData> OpenCVToVtkConverter::convertCVMatToVtkImageData(const cv::Mat &sourceCVImage, bool flipOverXAxis) {
  vtkSmartPointer<vtkImageData> outputVtkImage = vtkSmartPointer<vtkImageData>::New();
  double spacing[3] = {1, 1, 1};
  double origin[3] = {0, 0, 0};
  int extent[6] = {0, sourceCVImage.cols - 1, 0, sourceCVImage.rows - 1, 0, 0};
  auto numOfChannels = sourceCVImage.channels();
  outputVtkImage->SetSpacing(spacing);
  outputVtkImage->SetOrigin(origin);
  outputVtkImage->SetExtent(extent);
  outputVtkImage->SetDimensions(sourceCVImage.cols, sourceCVImage.rows, 1);
  outputVtkImage->AllocateScalars(VTK_UNSIGNED_CHAR, numOfChannels);

  cv::Mat tempCVImage;
  if(flipOverXAxis){ // Normaly you should flip the image!
    cv::flip(sourceCVImage, tempCVImage, 0);
  }
  else {
    tempCVImage = sourceCVImage;
  }
  for (int imgHeightPos = 0; imgHeightPos < sourceCVImage.rows; ++imgHeightPos) {
    for (int imgWidthPos = 0; imgWidthPos < sourceCVImage.cols; ++imgWidthPos){
      switch(numOfChannels){
        case 1:{
          auto pixel = tempCVImage.at<unsigned char>(imgHeightPos, imgWidthPos);
          outputVtkImage->SetScalarComponentFromDouble(imgWidthPos, imgHeightPos, 0, 0, pixel); //red
          break;
        }
        case 3: {
          auto pixel2 = tempCVImage.at<cv::Vec3b>(imgHeightPos, imgWidthPos);
          outputVtkImage->SetScalarComponentFromDouble(imgWidthPos, imgHeightPos, 0, 0, pixel2[2]); //red
          outputVtkImage->SetScalarComponentFromDouble(imgWidthPos, imgHeightPos, 0, 1, pixel2[1]); //green
          outputVtkImage->SetScalarComponentFromDouble(imgWidthPos, imgHeightPos, 0, 2, pixel2[0]); //blue
          break;
        }
        case 4:{
          auto pixel3 = tempCVImage.at<cv::Vec4b>(imgHeightPos, imgWidthPos);
          outputVtkImage->SetScalarComponentFromDouble(imgWidthPos, imgHeightPos, 0, 0, pixel3[2]); //red
          outputVtkImage->SetScalarComponentFromDouble(imgWidthPos, imgHeightPos, 0, 1, pixel3[1]); //green
          outputVtkImage->SetScalarComponentFromDouble(imgWidthPos, imgHeightPos, 0, 2, pixel3[0]); //blue
          outputVtkImage->SetScalarComponentFromDouble(imgWidthPos, imgHeightPos, 0, 3, pixel3[3]); //alpha
          break;
        }
        default:
          std::cout << "unknown number of channels" << std::endl;
      }
    }
  }
  outputVtkImage->Modified();
  return outputVtkImage;
}
like image 2
lucasahli Avatar answered Oct 22 '22 11:10

lucasahli