2015-11-12 2 views
1

У меня возникла проблема разбиения двоичного изображения на объект с содержимым, связанным с ящиками/субимагами (Примечание: ящики могут быть нерегулярными, когда объект находится в круге любых других примитивных фигур). Это может быть объяснено с изображениями, как показано ниже:Разделение изображений в ящики, содержащие объект

binarized image with objects

Рисунок 1: Изображение с кругом в качестве объектов, представляющих интерес

Partitioned Image

Рисунок 2: Изображение с ящиками произвольного размера, содержащего объекты, представляющие интерес

Таким образом, любое мнение, что это можно сделать?

+0

выглядит как kd-дерево, но не будет работать вообще – Micka

+0

для некоторых объектов созвездий нет никакого решения! – Micka

+0

Привет @Micka, большое спасибо за ваше мнение. Значит, это не реально? – vincent911001

ответ

2

Поскольку вы упомянули, что:

коробки могут быть нерегулярными

вы можете использовать диаграмму Вороного (вычисленную distanceTransform):

enter image description here

Код:

#include <opencv2\opencv.hpp> 
#include <vector> 
using namespace std; 
using namespace cv; 

int main() 
{ 
    Mat1b img = imread("path_to_image", IMREAD_GRAYSCALE); 

    Mat1f dist; 
    Mat1i labels; 
    distanceTransform(img, dist, labels, CV_DIST_L2, 3, DIST_LABEL_CCOMP); 

    // Show result 

    Mat1b labels1b; 
    labels.convertTo(labels1b, CV_8U); 
    normalize(labels1b, labels1b, 0, 255, NORM_MINMAX); 
    Mat3b res; 
    applyColorMap(labels1b, res, COLORMAP_JET); 
    res.setTo(Scalar(0,0,0), ~img); 

    imshow("Result", res); 
    waitKey(); 

    return 0; 
} 

Update

Если вам нужны коробки, чтобы быть прямоугольниками, вы можете посмотреть на рекурсивном XY Cut алгоритма. Вот модифицированная версия алгоритма XY Cut, которая делает прямоугольники не касающимися объектов переднего плана, так что сумма всех прямоугольников охватывает всю область изображения. Здесь я перевернул изображение, так как обычно черный фон, а белый - передний план.

enter image description here

Код:

#include <opencv2\opencv.hpp> 
#include <vector> 
using namespace std; 
using namespace cv; 

vector<Rect> XYCut_projH(const Mat1b& src, Rect roi) 
{ 
    Mat1b projH; 
    reduce(src(roi), projH, 1, CV_REDUCE_MAX); 

    vector<Rect> rects; 

    bool bOut = true; 
    vector<int> coords; 
    coords.push_back(0); 

    for (int i = 0; i < projH.rows; ++i) 
    { 
     if (bOut && projH(i) > 0) 
     { 
      coords.back() = (coords.back() + i)/2; 
      bOut = false; 
     } 
     else if (!bOut && projH(i) == 0) 
     { 
      coords.push_back(i); 
      bOut = true; 
     } 
    } 

    coords.front() = 0; 
    coords.back() = projH.rows; 
    if (coords.size() <= 1) return rects; 

    for (int i = 0; i < coords.size() - 1; ++i) 
    { 
     Rect r(0, coords[i], src.cols, coords[i + 1] - coords[i]); 
     r = (r + roi.tl()) & roi; 
     rects.push_back(r); 
    } 
    return rects; 
} 

vector<Rect> XYCut_projV(const Mat1b& src, Rect roi) 
{ 
    Mat1b projV; 
    reduce(src(roi), projV, 0, CV_REDUCE_MAX); 

    vector<Rect> rects; 

    bool bOut = true; 
    vector<int> coords; 
    coords.push_back(0); 

    for (int i = 0; i < projV.cols; ++i) 
    { 
     if (bOut && projV(i) > 0) 
     { 
      coords.back() = (coords.back() + i)/2; 
      bOut = false; 
     } 
     else if (!bOut && projV(i) == 0) 
     { 
      coords.push_back(i); 
      bOut = true; 
     } 
    } 

    coords.front() = 0; 
    coords.back() = projV.cols; 
    if (coords.size() <= 1) return rects; 

    for (int i = 0; i < coords.size() - 1; ++i) 
    { 
     Rect r(coords[i], 0, coords[i + 1] - coords[i], src.rows); 
     r = (r + roi.tl()) & roi; 
     rects.push_back(r); 
    } 
    return rects; 
} 

void XYCut_step(const Mat1b& src, Rect roi, vector<Rect>& rects, bool bAlternate) 
{ 
    vector<Rect> step; 
    if (bAlternate) 
    { 
     step = XYCut_projH(src, roi); 

     if ((step.size() == 1) && (step[0] == roi) && (XYCut_projV(src, roi).size() == 1)) 
     { 
      rects.push_back(roi); 
      return; 
     } 
    } 
    else 
    { 
     step = XYCut_projV(src, roi); 

     if ((step.size() == 1) && (step[0] == roi) && (XYCut_projH(src, roi).size() == 1)) 
     { 
      rects.push_back(roi); 
      return; 
     } 
    } 

    for (int i = 0; i < step.size(); ++i) 
    { 
     XYCut_step(src, step[i], rects, !bAlternate); 
    } 
} 

void XYCut(const Mat1b& src, vector<Rect>& rects) 
{ 
    bool bAlternate = true; 
    Rect roi(0, 0, src.cols, src.rows); 

    XYCut_step(src, roi, rects, bAlternate); 
} 



int main() 
{ 
    Mat1b img = imread("path_to_image", IMREAD_GRAYSCALE); 

    // invert image, if needed 
    img = ~img; 

    // Apply (modified) XY Cut 
    vector<Rect> rects; 
    XYCut(img, rects); 

    // Show results 
    Mat3b res; 
    cvtColor(img, res, COLOR_GRAY2BGR); 
    for (int i = 0; i < rects.size(); ++i) 
    { 
     rectangle(res, rects[i], Scalar(0,255,0)); 
    } 

    imshow("Result", res); 
    waitKey(); 

    return 0; 
} 

Обратите внимание, что этот алгоритм работает только тогда, когда это можно сделать разрез вдоль X или Y размерности, т.е. существует горизонтальная или вертикальная линия со всех фоновых пикселей. Это означает, что это не будет работать в очень загроможденном изображении.

+1

Мне нравится ваш стиль:) –

+0

Привет @Miki, Большое спасибо. Это именно то, что мне нужно. Благодарю приятеля. – vincent911001

Смежные вопросы