如何在C ++中有效地从cv::Mat
转换为vtkImageData
?
我寻找一种适用于黑白和彩色图像的方法。
答案 0 :(得分:1)
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;
}
答案 1 :(得分:0)
下面是@lucasahli给出的答案的简化版本。它使用高效的memcpy而不是double for循环。
注意:对于彩色图像,您可能需要将图像通道从bgr切换为rgb顺序,这是我使用mixChannels来实现的。
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;
}