Я ищу код 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
Пример изображения:
Результат OpenCV:
Результат Matlab:
Как показано, контуры не совпадают