将图像对象分成 N 个相等像素的部分(方法)

Posted

技术标签:

【中文标题】将图像对象分成 N 个相等像素的部分(方法)【英文标题】:Separate image object into N sections of equal pixels (Approach) 【发布时间】:2020-12-23 04:50:05 【问题描述】:

抱歉,这更像是一个算法问题而不是编码问题,但我不知道该把它放在哪里。为简单起见,假设您有一个二值图像(白色背景,前景中的纯黑色对象)

示例: sample input

我想将此对象(仅表示黑色像素)分成 N 个部分,所有部分都具有相同数量的像素(因此每个部分应包含 (1/N)*(total # of black pixel))。

使用我正在使用的当前算法,我 (1) 找到黑色像素的总数并 (2) 除以 N。然后我 (3) 逐行扫描图像,标记所有黑色像素。结果如下所示:

current output sketch

问题在于最后一个(黄色)部分,它不是连续的。我想以更有意义的方式划分图像,如下所示:

ideal output

基本上,我希望各部分之间的边界尽可能短。

我已经为此困惑了一段时间,但我的旧代码不再适用了。我只需要一种识别部分的方法,我最终会将每个部分作为单独的图像输出,以及输入图像的灰度副本,其中每个像素的值都对应于它的部分编号(这些东西我不需要帮助和)。有什么想法吗?

【问题讨论】:

所以节数是 6 ?还是可变的? @YunusTemurlenk 可变 【参考方案1】:

我只需要一种方法来识别这些部分

据此,我尝试了几种方法,这些方法可能有助于指导:

寻找图像的轮廓 找到轮廓的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,0);
            drawContours( drawing, contours, (int)i, color );
            drawContours( src, hull, (int)i, 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,Scalar(0,0,255),10);
                    innerCorners.push_back(contours[i][a]);
                    line(src,contours[i][a],centerMass,Scalar(0,255,255),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;

【讨论】:

感谢您的建议!我喜欢轮廓和质心方面。但是,我不确定我是否理解凸包对于任何其他非星形输入的可靠性。例如,如果我在其中放入一个矩形,则这些部分的像素将不会相等。有没有其他办法解决这个问题? 我想不通。很难找到任何形状的方法。

以上是关于将图像对象分成 N 个相等像素的部分(方法)的主要内容,如果未能解决你的问题,请参考以下文章

PHP将jpg图像分成两个相等的图像并保存

如何将数组列表分成相等的部分?

将屏幕分成 4 个相等的部分 - android

在python中创建圆圈以遮盖图像并计算每个圆圈内的像素

使用 MATLAB 将图像分成大小相等的块并使用 Gabor 滤波器

LeetCode 22.将数组分成和相等的三个部分