当我想组合两个计算机图形库,即 OpenCV 和 Vigra 时,我遇到了问题。我想使用 OpenCVs k-means 聚类算法进行灰度图像二值化。我的图像处理框架是较早构建的,并且强烈依赖于 Vigra,这就是我必须结合这两个库的原因。
所以基本上,我正在使用 Vigra 功能加载图像,而不是将 Vigra 对象转换为 OpenCV 矩阵,运行 k-means 聚类,将矩阵对象重新转换为 vigra 对象,最后通过使用 Vigra 功能再次保存图像。这是一个代码示例:
#include <vigra/impex.hxx>
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
int main()
{
std::string InputFilePath = "path/to/image/image_name.tif";
// Vigra functionality to load an image from path
vigra::FImage InputImg;
const char* cFile = InputFilePath.c_str();
vigra::ImageImportInfo info(cFile);
int b = info.width();
int h = info.height();
InputImg.resize(b,h);
vigra::importImage(info, destImage(InputImg));
vigra::FImage OutputImg(InputImg.width(), InputImg.height());
// Setting up OCV Matrix as an one channel, 32bit float grayscale image
cv::Mat InputMat(InputImg.width(), InputImg.height(), CV_32FC1);
// my workaround to convert vigra::FImage to cv::Mat
for(unsigned int i=0; i<InputImg.width(); i++){
for(unsigned int j=0; j<InputImg.height(); j++){
InputMat.at<float>(j,i) = InputImg(i,j);
}
}
// OCVs k-means clustering
const unsigned int singleLineSize = InputMat.rows*InputMat.cols;
const unsigned int k=2;
cv::Mat data = InputMat.reshape(1, singleLineSize);
std::vector<int> labels;
data.convertTo(data, CV_32FC1);
cv::Mat1f centers;
cv::kmeans(data, k, labels, cv::TermCriteria(cv::TermCriteria::EPS + cv::TermCriteria::COUNT, 10, 1.0), 2, cv::KMEANS_RANDOM_CENTERS, centers);
for (unsigned int i = 0; i < singleLineSize; i++) {
data.at<float>(i) = centers(labels[i]);
}
cv::Mat OutputMat = data.reshape(1, InputMat.rows);
OutputMat.convertTo(OutputMat, CV_8UC1);
// re-convert cv::Mat to vigra::FImage
for(unsigned int i=0; i<InputImg.width(); i++){
for(unsigned int j=0; j<InputImg.height(); j++){
OutputImg(i,j) = OutputMat.at<float>(j,i);
}
}
std::string SaveFileName = "path/to/save_location/save_img_name.tif";
// vigra functionality to save the image
const char* cFile = SaveFileName.c_str();
vigra::ImageExportInfo exinfo(cFile);
vigra::exportImage(srcImageRange(OutputImg), exinfo.setPixelType("FLOAT")); // pixel type could also be "UINT8"
// for the sake of comparability
std::string SaveFileNameOCV = "path/to/save_location/save_mat_name.tif";
cv::imwrite(SaveFileNameOCV, OutputMat);
return 0;
}
k-means 聚类工作正常,当我直接保存 cv::Mat 时
cv::imwrite()
万事皆安。但是当我将 cv::Mat 重新转换为 vigra::FImage 对象并保存时,图像已损坏。看起来好像对象(在图像中)被镜像或复制了四次,尽管图像宽度和高度保持不变。我附上了图像(InputImg、OutputImg 和 OutputMat)。此外,如果我将 InputMat 重新转换为 OutputImg(在 k-means 之后),并保存这个图像,一切都很好(这个图像也附上了)。
最后,我不明白为什么在从 vigra::FImage 转换为 cv::Mat 时必须切换索引,反之亦然:
InputMat.at<float>(j,i) = InputImg(i,j);
但如果我不这样做,则生成的图像会旋转。
好的,所以我不太确定是否有人使用 Vigra 和 OpenCV,我猜 OpenCV 肯定比 Vigra 更常见。但是无论如何,如果有人可以提供帮助,那就太好了。
顺便说一句:我在 OpenSuSE 15.1 上的 Code::Blocks 中运行所有内容。任何库都是通过官方 OpenSuSE 存储库安装的。