1 | initial version |
on the given image on the question it seems there is a big closed contour and open contours around it. like this image as a solution i tried to find edges of open contours and nearest points of closed contour and connect them. as result image :
althougt it is not perfect i tested your image and it seems desired result is OK.
i hope it will be useful for you.
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
using namespace cv;
using namespace std;
/// Global Variables
Point pt0,pt1;
int shift=0; // optional value for drawing scaled
Scalar color = Scalar(0,0,0);
// calculates distance between two points
static double distanceBtwPoints(const cv::Point a, const cv::Point b)
{
double xDiff = a.x - b.x;
double yDiff = a.y - b.y;
return std::sqrt((xDiff * xDiff) + (yDiff * yDiff));
}
static int findNearestPointIndex(const cv::Point pt, const vector<Point> points)
{
int nearestpointindex = 0;
double distance;
double mindistance = 1e+9;
for ( size_t i = 0; i < points.size(); i++)
{
distance = distanceBtwPoints(pt,points[i]);
if( distance < mindistance )
{
mindistance = distance;
nearestpointindex = i;
}
}
return nearestpointindex;
}
// draws point vector on given image
int static drawPoints( vector<Point> source_points,int start_index,int end_index, Mat m )
{
vector<Point> result;
int c = start_index;
start_index = min( start_index , end_index );
end_index = max( end_index, c );
for ( int i = start_index; i < end_index; i++)
{
result.push_back(source_points[i]);
}
if( start_index == 0 || result.size() < source_points.size()/2)
{
polylines(m,result,false,color,1,LINE_8,shift);
}
else
{
result.clear();
for ( int i = 0; i < start_index; i++)
result.push_back(source_points[i]);
polylines(m,result,false,color,1,LINE_8,shift);
result.clear();
for ( int i = end_index; i < source_points.size(); i++)
{
result.push_back(source_points[i]);
polylines(m,result,false,color,1,LINE_8,shift);
}
}
return 0;
}
bool testPoints(vector<Point> pts)
{
Point pt = pts[0];
for ( size_t i = 1; i < pts.size(); i++)
if( pts[i] == pt ) return false;
return true;
}
int main( int argc, char** argv )
{
char* filename = argc >= 2 ? argv[1] : (char*)"test.png";
Mat img = imread(filename);
if (img.empty())
return -1;
Mat src = img;
Mat bw;
cvtColor( src, bw, COLOR_BGR2GRAY );
bw = bw < 127;
// Find contours
vector<vector<Point> > contours;
vector<Point> contour;
findContours( bw, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE );
// assuming the closed contour have biggest size
contour = contours[0];
for ( size_t i = 0; i < contours.size(); i++)
{
if( contour.size() < contours[i].size() )
contour = contours[i];
}
src = Scalar(255,255,255); // clears source image to redraw
for ( size_t i = 0; i < contours.size(); i++)
{
if( contour != contours[i] && contours[i].size() > 10 )
{
pt0 = contours[i][0];
int ptscount=0;
for ( size_t j = 0; j < contours[i].size(); j++)
if( contours[i][j] == contours[i][j-2] )
{
ptscount++;
pt1 = pt0;
pt0 = contours[i][j-1];
}
if(testPoints(contours[i]) && ptscount > 1 )
pt0 = contours[i][0];
// find nearest points of closed contour
int nearestpointindex_start = findNearestPointIndex(pt0,contour);
int nearestpointindex_end = findNearestPointIndex(pt1,contour);
// redrawing
line(src,pt1,contour[nearestpointindex_end],color,1,LINE_8,shift);
line(src,pt0,contour[nearestpointindex_start],color,1,LINE_8,shift);
drawPoints(contours[i],0,contours[i].size(),src);
drawPoints(contour,nearestpointindex_start,nearestpointindex_end,src);
}
}
imwrite("result.png",src);
imshow("result", src);
waitKey(0);
return 0;
}
2 | No.2 Revision |
on the given image on the question it seems there is a big closed contour and open contours around it. like this image as a solution i tried to find edges of open contours and nearest points of closed contour and connect them. as result image :
althougt it is not perfect i tested your image and it seems desired result is OK.
i hope it will be useful for you.
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
using namespace cv;
using namespace std;
/// Global Variables
Point pt0,pt1;
int shift=0; // optional value for drawing scaled
Scalar color = Scalar(0,0,0);
// calculates distance between two points
static double distanceBtwPoints(const cv::Point a, const cv::Point b)
{
double xDiff = a.x - b.x;
double yDiff = a.y - b.y;
return std::sqrt((xDiff * xDiff) + (yDiff * yDiff));
}
static int findNearestPointIndex(const cv::Point pt, const vector<Point> points)
{
int nearestpointindex = 0;
double distance;
double mindistance = 1e+9;
for ( size_t i = 0; i < points.size(); i++)
{
distance = distanceBtwPoints(pt,points[i]);
if( distance < mindistance )
{
mindistance = distance;
nearestpointindex = i;
}
}
return nearestpointindex;
}
// draws point vector on given image
int static drawPoints( vector<Point> source_points,int start_index,int end_index, Mat m )
{
vector<Point> result;
int c = start_index;
start_index = min( start_index , end_index );
end_index = max( end_index, c );
for ( int i = start_index; i < end_index; i++)
{
result.push_back(source_points[i]);
}
if( start_index == 0 || result.size() < source_points.size()/2)
{
polylines(m,result,false,color,1,LINE_8,shift);
}
else
{
result.clear();
for ( int i = 0; i < start_index; i++)
result.push_back(source_points[i]);
polylines(m,result,false,color,1,LINE_8,shift);
result.clear();
for ( int i = end_index; i < source_points.size(); i++)
{
result.push_back(source_points[i]);
polylines(m,result,false,color,1,LINE_8,shift);
}
}
return 0;
}
bool testPoints(vector<Point> pts)
{
Point pt = pts[0];
for ( size_t i = 1; i < pts.size(); i++)
if( pts[i] == pt ) return false;
return true;
}
int main( int argc, char** argv )
{
char* filename = argc >= 2 ? argv[1] : (char*)"test.png";
Mat img = imread(filename);
if (img.empty())
return -1;
Mat src = img;
Mat bw;
cvtColor( src, bw, COLOR_BGR2GRAY );
bw = bw < 127;
// Find contours
vector<vector<Point> > contours;
vector<Point> contour;
findContours( bw, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE );
// assuming the closed contour have biggest size
contour = contours[0];
for ( size_t i = 0; i < contours.size(); i++)
{
if( contour.size() < contours[i].size() )
contour = contours[i];
}
src = Scalar(255,255,255); // clears source image to redraw
for ( size_t i = 0; i < contours.size(); i++)
{
if( contour != contours[i] && contours[i].size() > 10 )
{
pt0 = contours[i][0];
int ptscount=0;
for ( size_t j = 0; j < contours[i].size(); j++)
if( contours[i][j] == contours[i][j-2] )
{
ptscount++;
pt1 = pt0;
pt0 = contours[i][j-1];
}
if(testPoints(contours[i]) && ptscount > 1 )
pt0 = contours[i][0];
// find nearest points of closed contour
int nearestpointindex_start = findNearestPointIndex(pt0,contour);
int nearestpointindex_end = findNearestPointIndex(pt1,contour);
// redrawing
line(src,pt1,contour[nearestpointindex_end],color,1,LINE_8,shift);
line(src,pt0,contour[nearestpointindex_start],color,1,LINE_8,shift);
drawPoints(contours[i],0,contours[i].size(),src);
drawPoints(contour,nearestpointindex_start,nearestpointindex_end,src);
}
}
imwrite("result.png",src);
imshow("result", src);
waitKey(0);
return 0;
}
Second trial code gives this result image
IMHO this code is easier to implement but results is different.
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
using namespace cv;
using namespace std;
// calculates distance between two points
static double distanceBtwPoints(const cv::Point a, const cv::Point b)
{
double xDiff = a.x - b.x;
double yDiff = a.y - b.y;
return std::sqrt((xDiff * xDiff) + (yDiff * yDiff));
}
static int findNearestPointIndex(const cv::Point pt, const vector<Point> points)
{
int nearestpointindex = 0;
double distance;
double mindistance = 1e+9;
for ( size_t i = 0; i < points.size(); i++)
{
distance = distanceBtwPoints(pt,points[i]);
if( distance < mindistance )
{
mindistance = distance;
nearestpointindex = i;
}
}
return nearestpointindex;
}
int main( int argc, char** argv )
{
Point pt0;
int shift=0; // optional value for drawing scaled
Scalar color = Scalar(0,0,0);
char* filename = argc >= 2 ? argv[1] : (char*)"test.png";
Mat img = imread(filename);
if (img.empty())
return -1;
Mat src = img;
Mat bw;
cvtColor( src, bw, COLOR_BGR2GRAY );
bw = bw < 127;
// Find contours
vector<vector<Point> > contours;
vector<Point> contour;
findContours( bw, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE );
// assuming the closed contour have biggest size
contour = contours[0];
for ( size_t i = 0; i < contours.size(); i++)
{
if( contour.size() < contours[i].size() )
contour = contours[i];
}
for ( size_t i = 0; i < contours.size(); i++)
{
if( contour != contours[i] && contours[i].size() > 10 )
{
for ( size_t j = 0; j < contours[i].size(); j++)
{
pt0 = contours[i][j];
line(src,pt0,contour[findNearestPointIndex(pt0,contour)],color,1,LINE_8,shift);
}
}
}
cvtColor( src, src, COLOR_BGR2GRAY );
src = src < 127;
vector<vector<Point> > contours1;
findContours( src, contours1, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE );
src = 255; // clears source image to redraw
for ( size_t i = 0; i < contours1.size(); i++)
{
drawContours(src,contours1,i,color);
}
Mat m_xor(src.size(),CV_8UC1,255);
polylines(m_xor,contour,false,color,1,LINE_8);
m_xor = 255 - (src ^ m_xor) ;
imwrite("result.png",m_xor);
imshow("result", m_xor);
waitKey(0);
return 0;
}
3 | No.3 Revision |
on the given image on the question it seems there is a big closed contour and open contours around it. like this image as a solution i tried to find edges of open contours and nearest points of closed contour and connect them. as result image :
althougt it is not perfect i tested your image and it seems desired result is OK.
i hope it will be useful for you.
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
using namespace cv;
using namespace std;
/// Global Variables
Point pt0,pt1;
int shift=0; // optional value for drawing scaled
Scalar color = Scalar(0,0,0);
// calculates distance between two points
static double distanceBtwPoints(const cv::Point a, const cv::Point b)
{
double xDiff = a.x - b.x;
double yDiff = a.y - b.y;
return std::sqrt((xDiff * xDiff) + (yDiff * yDiff));
}
static int findNearestPointIndex(const cv::Point pt, const vector<Point> points)
{
int nearestpointindex = 0;
double distance;
double mindistance = 1e+9;
for ( size_t i = 0; i < points.size(); i++)
{
distance = distanceBtwPoints(pt,points[i]);
if( distance < mindistance )
{
mindistance = distance;
nearestpointindex = i;
}
}
return nearestpointindex;
}
// draws point vector on given image
int static drawPoints( vector<Point> source_points,int start_index,int end_index, Mat m )
{
vector<Point> result;
int c = start_index;
start_index = min( start_index , end_index );
end_index = max( end_index, c );
for ( int i = start_index; i < end_index; i++)
{
result.push_back(source_points[i]);
}
if( start_index == 0 || result.size() < source_points.size()/2)
{
polylines(m,result,false,color,1,LINE_8,shift);
}
else
{
result.clear();
for ( int i = 0; i < start_index; i++)
result.push_back(source_points[i]);
polylines(m,result,false,color,1,LINE_8,shift);
result.clear();
for ( int i = end_index; i < source_points.size(); i++)
{
result.push_back(source_points[i]);
polylines(m,result,false,color,1,LINE_8,shift);
}
}
return 0;
}
bool testPoints(vector<Point> pts)
{
Point pt = pts[0];
for ( size_t i = 1; i < pts.size(); i++)
if( pts[i] == pt ) return false;
return true;
}
int main( int argc, char** argv )
{
char* filename = argc >= 2 ? argv[1] : (char*)"test.png";
Mat img = imread(filename);
if (img.empty())
return -1;
Mat src = img;
Mat bw;
cvtColor( src, bw, COLOR_BGR2GRAY );
bw = bw < 127;
// Find contours
vector<vector<Point> > contours;
vector<Point> contour;
findContours( bw, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE );
// assuming the closed contour have biggest size
area
contour = contours[0];
for ( size_t i = 0; i < contours.size(); i++)
{
if( contour.size() < contours[i].size() contourArea(contour) < contourArea(contours[i]) )
contour = contours[i];
}
src = Scalar(255,255,255); // clears source image to redraw
for ( size_t i = 0; i < contours.size(); i++)
{
if( contour != contours[i] && contours[i].size() > 10 )
{
pt0 = contours[i][0];
int ptscount=0;
for ( size_t j = 0; j < contours[i].size(); j++)
if( contours[i][j] == contours[i][j-2] )
{
ptscount++;
pt1 = pt0;
pt0 = contours[i][j-1];
}
if(testPoints(contours[i]) && ptscount > 1 )
pt0 = contours[i][0];
// find nearest points of closed contour
int nearestpointindex_start = findNearestPointIndex(pt0,contour);
int nearestpointindex_end = findNearestPointIndex(pt1,contour);
// redrawing
line(src,pt1,contour[nearestpointindex_end],color,1,LINE_8,shift);
line(src,pt0,contour[nearestpointindex_start],color,1,LINE_8,shift);
drawPoints(contours[i],0,contours[i].size(),src);
drawPoints(contour,nearestpointindex_start,nearestpointindex_end,src);
}
}
imwrite("result.png",src);
imshow("result", src);
waitKey(0);
return 0;
}
Second trial code gives this result image
IMHO this code is easier to implement but results is different.
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
using namespace cv;
using namespace std;
// calculates distance between two points
static double distanceBtwPoints(const cv::Point a, const cv::Point b)
{
double xDiff = a.x - b.x;
double yDiff = a.y - b.y;
return std::sqrt((xDiff * xDiff) + (yDiff * yDiff));
}
static int findNearestPointIndex(const cv::Point pt, const vector<Point> points)
{
int nearestpointindex = 0;
double distance;
double mindistance = 1e+9;
for ( size_t i = 0; i < points.size(); i++)
{
distance = distanceBtwPoints(pt,points[i]);
if( distance < mindistance )
{
mindistance = distance;
nearestpointindex = i;
}
}
return nearestpointindex;
}
int main( int argc, char** argv )
{
Point pt0;
int shift=0; // optional value for drawing scaled
Scalar color = Scalar(0,0,0);
char* filename = argc >= 2 ? argv[1] : (char*)"test.png";
Mat img = imread(filename);
if (img.empty())
return -1;
Mat src = img;
Mat bw;
cvtColor( src, bw, COLOR_BGR2GRAY );
bw = bw < 127;
// Find contours
vector<vector<Point> > contours;
vector<Point> contour;
findContours( bw, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE );
// assuming the closed contour have biggest size
area
contour = contours[0];
for ( size_t i = 0; i < contours.size(); i++)
{
if( contour.size() < contours[i].size() contourArea(contour) < contourArea(contours[i]) )
contour = contours[i];
}
for ( size_t i = 0; i < contours.size(); i++)
{
if( contour != contours[i] && contours[i].size() > 10 )
{
for ( size_t j = 0; j < contours[i].size(); j++)
{
pt0 = contours[i][j];
line(src,pt0,contour[findNearestPointIndex(pt0,contour)],color,1,LINE_8,shift);
}
}
}
cvtColor( src, src, COLOR_BGR2GRAY );
src = src < 127;
vector<vector<Point> > contours1;
findContours( src, contours1, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE );
src = 255; // clears source image to redraw
for ( size_t i = 0; i < contours1.size(); i++)
{
drawContours(src,contours1,i,color);
}
Mat m_xor(src.size(),CV_8UC1,255);
polylines(m_xor,contour,false,color,1,LINE_8);
m_xor = 255 - (src ^ m_xor) ;
imwrite("result.png",m_xor);
imshow("result", m_xor);
waitKey(0);
return 0;
}