Разделить объект изображения на N секций с равными пикселями (приближение)

#algorithm #matlab #opencv #image-processing #theory

#алгоритм #matlab #opencv #обработка изображений #теория

Вопрос:

Заранее извините, это скорее алгоритмическая проблема, чем проблема кодирования, но я не был уверен, куда ее поместить. Для простоты предположим, что у вас есть двоичное изображение (белый фон, сплошной черный объект на переднем плане)

Пример: пример ввода

Я хочу разделить этот объект (имея в виду только черные пиксели) на N секций, все с одинаковым количеством пикселей (поэтому каждая секция должна содержать (1 / N) * (общее количество черных пикселей)).

С текущим алгоритмом, который я использую, я (1) нахожу общее количество черных пикселей и (2) делю на N. Затем я (3) сканирую изображение строка за строкой, отмечая все черные пиксели. Результат выглядит примерно так:

текущий эскиз вывода

Проблема с этим заключается в последней (желтой) секции, которая не является непрерывной. Я хочу разделить изображение таким образом, чтобы оно имело больше смысла, вот так:

идеальный результат

В принципе, я бы хотел, чтобы граница между секциями была как можно короче.

Я некоторое время был в тупике по этому поводу, но мой старый код просто больше не сокращает его. Мне нужен только подход к идентификации разделов, в конечном итоге я буду выводить каждый раздел в виде отдельных изображений, а также копию входного изображения в оттенках серого, где значение каждого пикселя соответствует его номеру раздела (с этими вещами мне не нужна помощь). Есть идеи?

Комментарии:

1. Значит, номер секции будет 6? Или изменяемый?

2. @YunusTemurlenk изменяемый

Ответ №1:

Мне нужен только подход к идентификации разделов

В соответствии с этим я попробовал несколько подходов, они могут помочь для рекомендаций:

  • Найти контур изображения
  • Найдите моменты контура и определите центр масс.
  • Для внешних углов вы можете просто использовать выпуклую оболочку
  • Найдите ближайшие точки контура (которые будут внутренними углами) к центру масс
  • Затем вы можете разделить его на нужные области, используя эти важные точки

Вот результат и код:

введите описание изображения здесь

 #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 amp;amp; 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 amp;amp; 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;
}
  

Комментарии:

1. Спасибо за идею! Мне нравятся аспекты контура и центра масс. Однако я не уверен, что понимаю, как выпуклая оболочка будет надежной для любого другого ввода, который не является звездой. Например, если я вставлю прямоугольник, секции не будут иметь равные пиксели. Есть ли другой способ обойти это?

2. Я не мог думать иначе. Так сложно найти подходы для любой формы.