findContours в OpenCV не соответствует bwboundaries в Matlab? - PullRequest
0 голосов
/ 11 июня 2019

Я ищу код C ++ (не обязательно должен быть в OpenCV), который дает точные эквивалентные результаты для команды Matlab bwboundaries.Я вижу, что в 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

Выходы x, y координаты контуров не совпадают, даже для контура длиной 17

Как я могу получить их для соответствия?Или есть другой код C ++, который может получить те же результаты, что и bwboundaries?

EDIT

Я пытался отобразить контуры в 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 (поскольку, когда я использовал drawContours в OpenCV в C ++, я не мог видеть нарисованные контуры):

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

Затем я сравнил эти контуры с bwboundaries в Matlab:

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

Как показано, контуры не совпадают

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...