问题描述
对不起,这更多是算法问题,而不是编码问题,但是我不确定该放在哪里。为简单起见,假设您有一个二进制图像(白色背景,前景中为纯黑色物体)
示例: sample input
我想将此对象(仅表示黑色像素)划分为N个部分,所有部分均具有相同的像素数(因此每个部分应包含(1 / N)*(黑色像素总数)。) >
使用我当前使用的算法,我(1)找到黑色像素的总数,然后(2)除以N。然后(3)逐行扫描图像,标记所有黑色像素。结果看起来像这样:
问题是最后一个(黄色)部分,该部分不是连续的。我想以一种更有意义的方式来划分图像,像这样:
基本上,我希望各部分之间的边界尽可能短。
我已经为此感到困惑了一段时间,但是我的旧代码不再适用了。我只需要一种识别部分的方法,最终将每个部分输出为单独的图像,并输入图像的灰度副本,其中每个像素的值对应于其部分编号(这些我不需要帮助。与)。有什么想法吗?
解决方法
我只需要一种方法来识别部分
因此,我尝试了几种方法,这些方法可能有助于指导原则:
- 查找图像轮廓
- 找到轮廓的moments并检测重心。
- 对于外角,您只需使用convex hull
- 找到最靠近轮廓线的点(将是内角)
- 然后您可以通过使用这些要点将其分离到所需区域
以下是结果和代码:
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
vector<Point>innerCorners;
bool isClose(Point test);
int main()
{
Mat src_gray;
int thresh = 100;
Mat src = imread("image/dir/star.png");
cvtColor( src,src_gray,COLOR_BGR2GRAY );
namedWindow( "Source",WINDOW_NORMAL );
Mat canny_output;
Canny( src_gray,canny_output,thresh,thresh*2 );
vector<vector<Point> > contours;
findContours( canny_output,contours,RETR_TREE,CHAIN_APPROX_SIMPLE );
vector<Vec4i> hierarchy;
vector<vector<Point> >hull( contours.size() );
vector<Moments> mu(contours.size() );
for( int i = 0; i <(int)contours.size(); i++ )
{ mu[i] = moments( contours[i],false ); }
for( size_t i = 0; i < contours.size(); i++ )
{
if(contours[i].size()>20)
convexHull( contours[i],hull[i] );
}
vector<Point2f> mc( contours.size() );
for( int i = 0; i <(int)contours.size(); i++ )
{ mc[i] = Point2f( mu[i].m10/mu[i].m00,mu[i].m01/mu[i].m00 ); }
Mat drawing = Mat::zeros( canny_output.size(),CV_8UC3 );
int onlyOne = 1;
for( size_t i = 0; i< contours.size(); i++ )
{
if(contours[i].size()>20 && onlyOne)
{
circle( src,mc[i],4,Scalar(0,255,255),-1,8,0 );
Scalar color = Scalar(255,0);
drawContours( drawing,(int)i,color );
drawContours( src,hull,color,5 );
Point centerMass = mc[i];
for(int a=0; a<(int)contours[i].size();a++)
{
if(cv::norm(cv::Mat(contours[i][a]),Mat(centerMass))<200 && isClose(contours[i][a]))
{
circle(src,contours[i][a],5,10);
innerCorners.push_back(contours[i][a]);
line(src,centerMass,5);
}
}
onlyOne = 0;
}
}
namedWindow( "Hull demo",WINDOW_NORMAL );
imshow( "Hull demo",drawing );
imshow("Source",src );
waitKey();
return 0;
}
bool isClose(Point test){
if(innerCorners.size()==0)
return 1;
for(Point a:innerCorners)
if((cv::norm(cv::Mat(a),cv::Mat(test)))<70)
return 0;
return 1;
}