首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在C++中结合OpenCV的k均值聚类和Vigra

在C++中结合OpenCV的k均值聚类和Vigra
EN

Stack Overflow用户
提问于 2021-01-13 18:55:19
回答 1查看 77关注 0票数 0

当我想要合并两个计算机图形库,即OpenCV和Vigra时,我遇到了一个问题。我想使用OpenCVs的k-means聚类算法进行灰度图像二值化。我的图像处理框架是在较早的时候构建的,并且非常依赖于Vigra,这就是为什么我必须结合这两个库的原因。

因此,基本上,我使用Vigra功能加载图像,然后将Vigra对象转换为OpenCV矩阵,运行k均值聚类,重新将矩阵对象转换为vigra对象,最后通过使用Vigra功能再次保存图像。下面是一个代码示例:

代码语言:javascript
复制
#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集群工作得很好,当我直接用

代码语言:javascript
复制
cv::imwrite()

一切都很好。但当我将cv::Mat重新转换为vigra::FImage对象并保存它时,图像已损坏。看起来对象(在图像中)被镜像或复制了四次,尽管图像的宽度和高度保持不变。我附上了图片(InputImg,OutputImg和OutputMat)。此外,如果我将InputMat重新转换为OutputImg (在k-means之后),并保存此图像,则一切正常(此图像也已附加)。

最后,我不明白为什么在从vigra::FImage转换为cv::Mat时必须切换索引,反之亦然:

代码语言:javascript
复制
InputMat.at<float>(j,i) = InputImg(i,j);

但如果我不这样做,生成的图像就会旋转。

好吧,所以我不太确定是否有人使用Vigra和OpenCV,我猜OpenCV肯定比Vigra更常见。但不管怎样,如果有人能帮上忙,那就太好了。

顺便说一下:我在OpenSuSE 15.1上运行Code::Blocks中的所有代码。任何库都是通过官方OpenSuSE存储库安装的。

EN

回答 1

Stack Overflow用户

发布于 2021-01-20 19:07:14

好的,首先,我不知道为什么会发生这种情况。但我现在知道的是,如果我使用的是类型定义版本的Mat_ (例如Mat1f...)我可以正确地处理所有事情,保存的结果如预期的那样。

对于转换,我写了两个方法:

代码语言:javascript
复制
cv::Mat1f convertImg2Mat(vigra::FImage &img){
    int b = img.width();
    int h = img.height();

    cv::Mat1f mat(h, b);

    for(unsigned int j=0; j<h; j++){
        for(unsigned int i=0; i<b; i++){
            mat(j,i) = img(i,j);
        }
    }
    return mat;
}

代码语言:javascript
复制
vigra::FImage convertMat2Img(cv::Mat mat){
    int b = mat.rows;
    int h = mat.cols;
    cv::Mat1f tmp = mat.clone();

    vigra::FImage img(h, b);

    for(unsigned int j=0; j<h; j++){
        for(unsigned int i=0; i<b; i++){
            img(i,j) = tmp(j,i);
        }
    }
    return img;
}

两者都工作得很好。

一个愚蠢的初学者错误是索引,因为vigra遵循fortran顺序,即

代码语言:javascript
复制
img(cols, rows)

而OpenCV使用另一种约定,即

代码语言:javascript
复制
mat(rows, cols).

因此,在我看来,这个问题还没有得到恰当的回答,但我无论如何都找到了一个可行的解决方案。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65700478

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档