OpenCV中的findContours与Matlab中的bwboundaries不匹配?

时间:2019-06-11 18:44:13

标签: c++ matlab opencv

我正在寻找可以提供与Matlab bwboundaries命令完全等效的结果的C ++代码(不必在OpenCV中)。我看到OpenCV中有findContours,但是它给出的结果与bwboundaries相同

我用于findContours的代码是:

cv::Mat mat = cv::imread("lennabin.bmp");
vector<vector<cv::Point> > contours;
vector<cv::Vec4i> hierarchy;
vector<vector<cv::Point> > contours0;
cv::cvtColor(mat, mat, cv::COLOR_BGR2GRAY);

cv::Mat tMat;
cv::transpose(mat, tMat);
//findContours(mat, contours0, hierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);
findContours(tMat, contours0, cv::RETR_LIST, cv::CHAIN_APPROX_NONE);
//findContours(mat, contours0, hierarchy, cv::RETR_CCOMP, cv::CHAIN_APPROX_SIMPLE);

std::cout << "\nopenCV findcontours L:"<< contours0.size()<<"\n";
for (int i = 0; i < contours0.size(); i++) {
    std::cout << "\ni: "<<i<<" points: "<< contours0[i].size();
    int jsize;
    if (contours0[i].size() >= 5) {
        jsize = 5;
    }
    else {
        jsize = contours0[i].size();
    }
    for (int j = 0; j < jsize; j++)
    {
        std::cout << "\n"<<contours0[i][j].x << " " << contours0[i][j].y;
    }
}

bwboundaries的代码为:

[B,~,~] = bwboundaries(im);
disp(['Length(B): ', num2str(length(B))])
for i=1:3
    disp(['Length(B{i}): ', num2str(length(B{i}))])
    disp(['i: ',num2str(i)])
    boundary=B{i};
    [r,c]=size(boundary);
    if r<5
        jL=r;
    else
        jL=5;
    end
    disp('xy')
    for j=1:jL
        disp([num2str(boundary(j,1)), ...
            ' ',num2str(boundary(j,2))])
    end
end


for i=1:length(B)
    if length(B{i})==17
        disp(['Length(B{i}): ', num2str(length(B{i}))])
        disp(['i: ',num2str(i)])
        boundary=B{i};
        disp('xy')
        for j=1:length(B{i})
            disp([num2str(boundary(j,1)), ...
                ' ',num2str(boundary(j,2))])
        end
    end
end

我为C ++获得的输出是:

openCV findcontours L:220

i:0 points 1
188 206
i:1 points:17
218 202
217 203
216 204
215 205
214 206
i:2 points: 4
8 194
9 193
10 194
9 195

和Matlab:

run_bwboundaries(lennabind);
Length(B): 220
Length(B{i}): 583
i: 1
xy
1 1
1 2
1 3
1 4
1 5
Length(B{i}): 107
i: 2
xy
172 1
172 2
173 3
174 4
175 5
Length(B{i}): 11
i: 3
xy
205 29
206 29
207 29
208 29
209 29

Length(B{i}): 17
i: 211
xy
139 127
139 128
139 129
139 130
140 130
140 131
140 132
141 132
141 133
141 132
141 131
140 131
140 130
140 129
140 128
140 127
139 127

即使对于长度为17的轮廓,轮廓的x,y坐标的输出也不匹配

我如何才能使它们匹配?还是有其他C ++代码可以获得与bwboundaries相同的结果?

编辑

我尝试通过以下方式在OpenCV中显示轮廓:

int indx=0;
for(; idx>=0; idx=hierarchy[idx][0])
{
    cv::Scalar color(255,255,0);
    drawContours(mat, contours0, idx, color, cv::FILLED, 8, hierarchy);
}
cv::namedWindow("Components",1);
cv::imshow("Components", mat);
cv::waitKey(0);

但是我只是看到没有轮廓的原始图像

EDIT2

我使用了以下C ++代码:

#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/core/core.hpp>

using namespace std;
using namespace cv;

std::vector<double> matToArr(cv::Mat mat);

void csvwriteMat(std::string str1, std::vector<std::vector<double>> vec);
std::vector<std::vector<double>> matTo2Dvec(const cv::Mat& mat, int rows);
std::string type2str1(int type);
std::vector<std::vector<std::vector<double>>> bwboundariesOpenCV(cv::Mat mat);

int main() {

    cv::Mat sampleMat = cv::imread("sample.bmp");

    std::vector<std::vector<double>> sample = matTo2Dvec(sampleMat, sampleMat.rows);
    std::cout << "\n sample 2d vec \n";
    for (int i = 0; i < sample.size(); i++)
    {
        std::cout << "\n";
        for (int j = 0; j < sample[0].size(); j++)
        {
            std::cout << sample[i][j] << " ";
        }
    }

    cv::cvtColor(sampleMat, sampleMat, cv::COLOR_BGR2GRAY);
    sampleMat.convertTo(sampleMat, CV_32F);
    cv::Scalar s = 255;
    divide(sampleMat, s, sampleMat);

    std::string ty = type2str1(sampleMat.type());
    printf("Matrix: %s %dx%d \n", ty.c_str(), sampleMat.cols, sampleMat.rows);

    sampleMat.convertTo(sampleMat, CV_8U);
    ty = type2str1(sampleMat.type());
    printf("Matrix: %s %dx%d \n", ty.c_str(), sampleMat.cols, sampleMat.rows);

    std::vector<std::vector<std::vector<double>>> B = bwboundariesOpenCV(sampleMat);
    for (int k = 1; k <= B.size(); k++) {
        std::vector<std::vector<double>> boundary = B[k - 1];
        std::string outputDir1 = "C:/Users/me/output";
        std::string out1 = outputDir1 + "/" + "OpenCV-bwboundaries" + "/" +
            "contour" + "-" + std::to_string(k) + ".csv";
        csvwriteMat(out1, boundary);
    }

    return 0;
}

std::vector<double> matToArr(cv::Mat mat)
{
    cv::cvtColor(mat, mat, cv::COLOR_BGR2GRAY);
    mat.convertTo(mat, CV_32F);
    cv::Scalar s = 255;
    divide(mat, s, mat);
    std::vector<double> array;
    if (mat.isContinuous()) {
        array.assign((float*)mat.data, (float*)mat.data + mat.total());
    }
    else {
        for (int i = 0; i < mat.rows; ++i) {
            array.insert(array.end(), mat.ptr<float>(i), mat.ptr<float>(i) + mat.cols);
        }
    }
    return array;
}


void csvwriteMat(std::string str1, std::vector<std::vector<double>> vec)
{
    const char *str = str1.c_str();
    std::ofstream out(str);
    for (auto& row : vec) {
        for (auto col : row)
            out << col << ',';
        out << '\n';
    }
    out.close();
}

std::vector<std::vector<double>> matTo2Dvec(const cv::Mat& mat, int rows)
{
    std::vector<double> arr = matToArr(mat);
    std::vector < std::vector<double>> vec2D;
    for (int i = 0; i < rows; i++) {
        auto first = arr.begin() + (rows * i);
        auto last = arr.begin() + (rows * i) + rows;
        std::vector<double> vec0(first, last);
        vec2D.push_back(vec0);
    }
    return vec2D;
}

std::string type2str1(int type) {
    std::string r;

    uchar depth = type & CV_MAT_DEPTH_MASK;
    uchar chans = 1 + (type >> CV_CN_SHIFT);

    switch (depth) {
    case CV_8U:  r = "8U"; break;
    case CV_8S:  r = "8S"; break;
    case CV_16U: r = "16U"; break;
    case CV_16S: r = "16S"; break;
    case CV_32S: r = "32S"; break;
    case CV_32F: r = "32F"; break;
    case CV_64F: r = "64F"; break;
    default:     r = "User"; break;
    }

    r += "C";
    r += (chans + '0');

    return r;
}


std::vector<std::vector<std::vector<double>>> bwboundariesOpenCV(cv::Mat mat) {
    vector<vector<cv::Point> > contours;
    vector<cv::Vec4i> hierarchy;
    vector<vector<cv::Point> > contours0;
    cv::Mat tMat;
    cv::transpose(mat, tMat);
    findContours(tMat, contours0, cv::RETR_LIST, cv::CHAIN_APPROX_NONE);

    std::vector<std::vector<std::vector<double>>> B;

    std::cout << "\nopenCV findcontours L:" << contours0.size() << "\n";
    for (int i = 0; i < contours0.size(); i++) {
        std::vector<std::vector<double>>contourVec;
        for (int j = 0; j < contours0[i].size(); j++) {
            std::vector<double>contourXY;
            contourXY.push_back(contours0[i][j].x);
            contourXY.push_back(contours0[i][j].y);
            contourVec.push_back(contourXY);
        }
        B.push_back(contourVec);
    }
    return B;
}

和下面的Matlab代码显示从OpenCV到Matlab的轮廓(因为当我在C ++中的OpenCV中使用drawContours时,看不到绘制的轮廓)

function plotOpenCVcontours(pth, boundarypth,BW1)

close all;
fig=figure(2);imshow(BW1);hold on;
boundarypath = fullfile(pth, boundarypth);
allboundary = dir(fullfile(boundarypath, '*csv'));

for x = 1:length(allboundary)
    thisBoundary=csvread(fullfile(pth, boundarypth, allboundary(x).name));
    sz=size(thisBoundary);
    for j=1:1:sz(1)
        plot(thisBoundary(j,2), thisBoundary(j,1), '.g','MarkerSize',5);
    end
end

然后在Matlab中将这些轮廓与bwboundaries进行比较:

figure(81); imshow(I); hold on; [B,L,N] = bwboundaries(I); 
[B,L,N] = bwboundaries(I);
for k=1:length(B),
    boundary = B{k};
    if k>N %hole boundaries
        plot(boundary(:,2), boundary(:,1), '.g','MarkerSize',5);
    else
        plot(boundary(:,2), boundary(:,1), '.r','MarkerSize',5);

    end
end

示例图像为: enter image description here

OpenCV结果:

enter image description here

Matlab结果:

enter image description here

如图所示,轮廓不匹配

0 个答案:

没有答案