parent
2b64abdbed
commit
b754372ce5
6 changed files with 627 additions and 3 deletions
@ -0,0 +1,124 @@ |
|||||||
|
/*
|
||||||
|
By downloading, copying, installing or using the software you agree to this |
||||||
|
license. If you do not agree to this license, do not download, install, |
||||||
|
copy or use the software. |
||||||
|
License Agreement |
||||||
|
For Open Source Computer Vision Library |
||||||
|
(3-clause BSD License) |
||||||
|
Copyright (C) 2013, OpenCV Foundation, all rights reserved. |
||||||
|
Third party copyrights are property of their respective owners. |
||||||
|
Redistribution and use in source and binary forms, with or without modification, |
||||||
|
are permitted provided that the following conditions are met: |
||||||
|
* Redistributions of source code must retain the above copyright notice, |
||||||
|
this list of conditions and the following disclaimer. |
||||||
|
* Redistributions in binary form must reproduce the above copyright notice, |
||||||
|
this list of conditions and the following disclaimer in the documentation |
||||||
|
and/or other materials provided with the distribution. |
||||||
|
* Neither the names of the copyright holders nor the names of the contributors |
||||||
|
may be used to endorse or promote products derived from this software |
||||||
|
without specific prior written permission. |
||||||
|
This software is provided by the copyright holders and contributors "as is" and |
||||||
|
any express or implied warranties, including, but not limited to, the implied |
||||||
|
warranties of merchantability and fitness for a particular purpose are |
||||||
|
disclaimed. In no event shall copyright holders or contributors be liable for |
||||||
|
any direct, indirect, incidental, special, exemplary, or consequential damages |
||||||
|
(including, but not limited to, procurement of substitute goods or services; |
||||||
|
loss of use, data, or profits; or business interruption) however caused |
||||||
|
and on any theory of liability, whether in contract, strict liability, |
||||||
|
or tort (including negligence or otherwise) arising in any way out of |
||||||
|
the use of this software, even if advised of the possibility of such damage. |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef __OPENCV_XIMGPROC_SEGMENTATION_HPP__ |
||||||
|
#define __OPENCV_XIMGPROC_SEGMENTATION_HPP__ |
||||||
|
|
||||||
|
#include <opencv2/core.hpp> |
||||||
|
|
||||||
|
namespace cv { |
||||||
|
namespace ximgproc { |
||||||
|
namespace segmentation { |
||||||
|
//! @addtogroup ximgproc_segmentation
|
||||||
|
//! @{
|
||||||
|
|
||||||
|
/** @brief Graph Based Segmentation Algorithm.
|
||||||
|
The class implements the algorithm described in @cite PFF2004 . |
||||||
|
*/ |
||||||
|
class CV_EXPORTS_W GraphSegmentation : public Algorithm { |
||||||
|
public: |
||||||
|
/** @brief Segment an image and store output in dst
|
||||||
|
@param src The input image. Any number of channel (1 (Eg: Gray), 3 (Eg: RGB), 4 (Eg: RGB-D)) can be provided |
||||||
|
@param dst The output segmentation. It's a CV_32SC1 Mat with the same number of cols and rows as input image, with an unique, sequential, id for each pixel. |
||||||
|
*/ |
||||||
|
CV_WRAP virtual void processImage(InputArray src, OutputArray dst) = 0; |
||||||
|
|
||||||
|
CV_WRAP virtual void setSigma(double sigma) = 0; |
||||||
|
CV_WRAP virtual double getSigma() = 0; |
||||||
|
|
||||||
|
CV_WRAP virtual void setK(float k) = 0; |
||||||
|
CV_WRAP virtual float getK() = 0; |
||||||
|
|
||||||
|
CV_WRAP virtual void setMinSize(int min_size) = 0; |
||||||
|
CV_WRAP virtual int getMinSize() = 0; |
||||||
|
}; |
||||||
|
|
||||||
|
/** @brief Creates a graph based segmentor
|
||||||
|
@param simga The sigma parameter, used to smooth image |
||||||
|
@param k The k parameter of the algorythm |
||||||
|
@param min_size The minimum size of segments |
||||||
|
*/ |
||||||
|
CV_EXPORTS_W Ptr<GraphSegmentation> createGraphSegmentation(double sigma=0.5, float k=300, int min_size=100); |
||||||
|
//! @}
|
||||||
|
|
||||||
|
// Represent an edge between two pixels
|
||||||
|
class Edge { |
||||||
|
public: |
||||||
|
int from; |
||||||
|
int to; |
||||||
|
float weight; |
||||||
|
|
||||||
|
bool operator <(const Edge& e) const { |
||||||
|
return weight < e.weight; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
// A point in the sets of points
|
||||||
|
class PointSetElement { |
||||||
|
public: |
||||||
|
int p; |
||||||
|
int size; |
||||||
|
|
||||||
|
PointSetElement() { } |
||||||
|
|
||||||
|
PointSetElement(int p_) { |
||||||
|
p = p_; |
||||||
|
size = 1; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
// An object to manage set of points, who can be fusionned
|
||||||
|
class PointSet { |
||||||
|
public: |
||||||
|
PointSet(int nb_elements_); |
||||||
|
~PointSet(); |
||||||
|
|
||||||
|
int nb_elements; |
||||||
|
|
||||||
|
// Return the main point of the point's set
|
||||||
|
int getBasePoint(int p); |
||||||
|
|
||||||
|
// Join two sets of points, based on their main point
|
||||||
|
void joinPoints(int p_a, int p_b); |
||||||
|
|
||||||
|
// Return the set size of a set (based on the main point)
|
||||||
|
int size(unsigned int p) { return mapping[p].size; } |
||||||
|
|
||||||
|
private: |
||||||
|
PointSetElement* mapping; |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,151 @@ |
|||||||
|
/*
|
||||||
|
By downloading, copying, installing or using the software you agree to this |
||||||
|
license. If you do not agree to this license, do not download, install, |
||||||
|
copy or use the software. |
||||||
|
License Agreement |
||||||
|
For Open Source Computer Vision Library |
||||||
|
(3-clause BSD License) |
||||||
|
Copyright (C) 2013, OpenCV Foundation, all rights reserved. |
||||||
|
Third party copyrights are property of their respective owners. |
||||||
|
Redistribution and use in source and binary forms, with or without modification, |
||||||
|
are permitted provided that the following conditions are met: |
||||||
|
* Redistributions of source code must retain the above copyright notice, |
||||||
|
this list of conditions and the following disclaimer. |
||||||
|
* Redistributions in binary form must reproduce the above copyright notice, |
||||||
|
this list of conditions and the following disclaimer in the documentation |
||||||
|
and/or other materials provided with the distribution. |
||||||
|
* Neither the names of the copyright holders nor the names of the contributors |
||||||
|
may be used to endorse or promote products derived from this software |
||||||
|
without specific prior written permission. |
||||||
|
This software is provided by the copyright holders and contributors "as is" and |
||||||
|
any express or implied warranties, including, but not limited to, the implied |
||||||
|
warranties of merchantability and fitness for a particular purpose are |
||||||
|
disclaimed. In no event shall copyright holders or contributors be liable for |
||||||
|
any direct, indirect, incidental, special, exemplary, or consequential damages |
||||||
|
(including, but not limited to, procurement of substitute goods or services; |
||||||
|
loss of use, data, or profits; or business interruption) however caused |
||||||
|
and on any theory of liability, whether in contract, strict liability, |
||||||
|
or tort (including negligence or otherwise) arising in any way out of |
||||||
|
the use of this software, even if advised of the possibility of such damage. |
||||||
|
*/ |
||||||
|
|
||||||
|
|
||||||
|
#include "opencv2/ximgproc/segmentation.hpp" |
||||||
|
#include "opencv2/highgui.hpp" |
||||||
|
#include <opencv2/core/utility.hpp> |
||||||
|
#include <opencv2/opencv.hpp> |
||||||
|
#include <iostream> |
||||||
|
|
||||||
|
using namespace cv; |
||||||
|
using namespace cv::ximgproc::segmentation; |
||||||
|
|
||||||
|
static void help() { |
||||||
|
std::cout << std::endl << |
||||||
|
"A program demonstrating the use and capabilities of a particular graph based image" << std::endl << |
||||||
|
"segmentation algorithm described in P. Felzenszwalb, D. Huttenlocher," << std::endl << |
||||||
|
" \"Efficient Graph-Based Image Segmentation\"" << std::endl << |
||||||
|
"International Journal of Computer Vision, Vol. 59, No. 2, September 2004" << std::endl << std::endl << |
||||||
|
"Usage:" << std::endl << |
||||||
|
"./graphsegmentation_demo input_image output_image [simga=0.5] [k=300] [min_size=100]" << std::endl; |
||||||
|
} |
||||||
|
|
||||||
|
Scalar hsv_to_rgb(Scalar c) { |
||||||
|
Mat in(1, 1, CV_32FC3); |
||||||
|
Mat out(1, 1, CV_32FC3); |
||||||
|
|
||||||
|
float * p = in.ptr<float>(0); |
||||||
|
|
||||||
|
p[0] = c[0] * 360; |
||||||
|
p[1] = c[1]; |
||||||
|
p[2] = c[2]; |
||||||
|
|
||||||
|
cvtColor(in, out, COLOR_HSV2RGB); |
||||||
|
|
||||||
|
Scalar t; |
||||||
|
|
||||||
|
Vec3f p2 = out.at<Vec3f>(0, 0); |
||||||
|
|
||||||
|
t[0] = (int)(p2[0] * 255); |
||||||
|
t[1] = (int)(p2[1] * 255); |
||||||
|
t[2] = (int)(p2[2] * 255); |
||||||
|
|
||||||
|
return t; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
Scalar color_mapping(int segment_id) { |
||||||
|
|
||||||
|
double base = (double)(segment_id) * 0.618033988749895 + 0.24443434; |
||||||
|
|
||||||
|
return hsv_to_rgb(Scalar(fmod(base, 1.2), 0.95, 0.80)); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
int main(int argc, char** argv) { |
||||||
|
|
||||||
|
if (argc < 2 || argc > 6) { |
||||||
|
help(); |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
setUseOptimized(true); |
||||||
|
setNumThreads(8); |
||||||
|
|
||||||
|
Ptr<GraphSegmentation> gs = createGraphSegmentation(); |
||||||
|
|
||||||
|
if (argc > 3) |
||||||
|
gs->setSigma(atof(argv[3])); |
||||||
|
|
||||||
|
if (argc > 4) |
||||||
|
gs->setK(atoi(argv[4])); |
||||||
|
|
||||||
|
if (argc > 5) |
||||||
|
gs->setMinSize(atoi(argv[5])); |
||||||
|
|
||||||
|
if (!gs) { |
||||||
|
std::cerr << "Failed to create GraphSegmentation Algorithm." << std::endl; |
||||||
|
return -2; |
||||||
|
} |
||||||
|
|
||||||
|
Mat input, output, output_image; |
||||||
|
|
||||||
|
input = imread(argv[1]); |
||||||
|
|
||||||
|
if (!input.data) { |
||||||
|
std::cerr << "Failed to load input image" << std::endl; |
||||||
|
return -3; |
||||||
|
} |
||||||
|
|
||||||
|
gs->processImage(input, output); |
||||||
|
|
||||||
|
double min, max; |
||||||
|
minMaxLoc(output, &min, &max); |
||||||
|
|
||||||
|
int nb_segs = (int)max + 1; |
||||||
|
|
||||||
|
std::cout << nb_segs << " segments" << std::endl; |
||||||
|
|
||||||
|
output_image = Mat::zeros(output.rows, output.cols, CV_8UC3); |
||||||
|
|
||||||
|
uint* p; |
||||||
|
uchar* p2; |
||||||
|
|
||||||
|
for (int i = 0; i < output.rows; i++) { |
||||||
|
|
||||||
|
p = output.ptr<uint>(i); |
||||||
|
p2 = output_image.ptr<uchar>(i); |
||||||
|
|
||||||
|
for (int j = 0; j < output.cols; j++) { |
||||||
|
Scalar color = color_mapping(p[j]); |
||||||
|
p2[j*3] = color[0]; |
||||||
|
p2[j*3 + 1] = color[1]; |
||||||
|
p2[j*3 + 2] = color[2]; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
imwrite(argv[2], output_image); |
||||||
|
|
||||||
|
std::cout << "Image written to " << argv[2] << std::endl; |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
@ -0,0 +1,332 @@ |
|||||||
|
/*
|
||||||
|
By downloading, copying, installing or using the software you agree to this |
||||||
|
license. If you do not agree to this license, do not download, install, |
||||||
|
copy or use the software. |
||||||
|
License Agreement |
||||||
|
For Open Source Computer Vision Library |
||||||
|
(3-clause BSD License) |
||||||
|
Copyright (C) 2013, OpenCV Foundation, all rights reserved. |
||||||
|
Third party copyrights are property of their respective owners. |
||||||
|
Redistribution and use in source and binary forms, with or without modification, |
||||||
|
are permitted provided that the following conditions are met: |
||||||
|
* Redistributions of source code must retain the above copyright notice, |
||||||
|
this list of conditions and the following disclaimer. |
||||||
|
* Redistributions in binary form must reproduce the above copyright notice, |
||||||
|
this list of conditions and the following disclaimer in the documentation |
||||||
|
and/or other materials provided with the distribution. |
||||||
|
* Neither the names of the copyright holders nor the names of the contributors |
||||||
|
may be used to endorse or promote products derived from this software |
||||||
|
without specific prior written permission. |
||||||
|
This software is provided by the copyright holders and contributors "as is" and |
||||||
|
any express or implied warranties, including, but not limited to, the implied |
||||||
|
warranties of merchantability and fitness for a particular purpose are |
||||||
|
disclaimed. In no event shall copyright holders or contributors be liable for |
||||||
|
any direct, indirect, incidental, special, exemplary, or consequential damages |
||||||
|
(including, but not limited to, procurement of substitute goods or services; |
||||||
|
loss of use, data, or profits; or business interruption) however caused |
||||||
|
and on any theory of liability, whether in contract, strict liability, |
||||||
|
or tort (including negligence or otherwise) arising in any way out of |
||||||
|
the use of this software, even if advised of the possibility of such damage. |
||||||
|
*/ |
||||||
|
|
||||||
|
/******************************************************************************\
|
||||||
|
* Graph based segmentation * |
||||||
|
* This code implements the segmentation method described in: * |
||||||
|
* P. Felzenszwalb, D. Huttenlocher: "Graph-Based Image Segmentation" * |
||||||
|
* International Journal of Computer Vision, Vol. 59, No. 2, September 2004 * |
||||||
|
* * |
||||||
|
* Author: Maximilien Cuony / LTS2 / EPFL / 2015 * |
||||||
|
*******************************************************************************/ |
||||||
|
|
||||||
|
#include "precomp.hpp" |
||||||
|
#include "opencv2/ximgproc/segmentation.hpp" |
||||||
|
|
||||||
|
#include <iostream> |
||||||
|
|
||||||
|
namespace cv { |
||||||
|
namespace ximgproc { |
||||||
|
namespace segmentation { |
||||||
|
|
||||||
|
class GraphSegmentationImpl : public GraphSegmentation { |
||||||
|
public: |
||||||
|
GraphSegmentationImpl() { |
||||||
|
sigma = 0.5; |
||||||
|
k = 300; |
||||||
|
min_size = 100; |
||||||
|
name_ = "GraphSegmentation"; |
||||||
|
} |
||||||
|
|
||||||
|
~GraphSegmentationImpl() { |
||||||
|
}; |
||||||
|
|
||||||
|
virtual void processImage(InputArray src, OutputArray dst); |
||||||
|
|
||||||
|
virtual void setSigma(double sigma_) { if (sigma_ <= 0) { sigma_ = 0.001; } sigma = sigma_; } |
||||||
|
virtual double getSigma() { return sigma; } |
||||||
|
|
||||||
|
virtual void setK(float k_) { k = k_; } |
||||||
|
virtual float getK() { return k; } |
||||||
|
|
||||||
|
virtual void setMinSize(int min_size_) { min_size = min_size_; } |
||||||
|
virtual int getMinSize() { return min_size; } |
||||||
|
|
||||||
|
virtual void write(FileStorage& fs) const { |
||||||
|
fs << "name" << name_ |
||||||
|
<< "sigma" << sigma |
||||||
|
<< "k" << k |
||||||
|
<< "min_size" << (int)min_size; |
||||||
|
} |
||||||
|
|
||||||
|
virtual void read(const FileNode& fn) { |
||||||
|
CV_Assert( (String)fn["name"] == name_ ); |
||||||
|
|
||||||
|
sigma = (double)fn["sigma"]; |
||||||
|
k = (float)fn["k"]; |
||||||
|
min_size = (int)(int)fn["min_size"]; |
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
double sigma; |
||||||
|
float k; |
||||||
|
int min_size; |
||||||
|
String name_; |
||||||
|
|
||||||
|
// Pre-filter the image
|
||||||
|
void filter(const Mat &img, Mat &img_filtered); |
||||||
|
|
||||||
|
// Build the graph between each pixels
|
||||||
|
void buildGraph(Edge **edges, int &nb_edges, const Mat &img_filtered); |
||||||
|
|
||||||
|
// Segment the graph
|
||||||
|
void segmentGraph(Edge * edges, const int &nb_edges, const Mat & img_filtered, PointSet **es); |
||||||
|
|
||||||
|
// Remove areas too small
|
||||||
|
void filterSmallAreas(Edge *edges, const int &nb_edges, PointSet *es); |
||||||
|
|
||||||
|
// Map the segemented graph to a Mat with uniques, sequentials ids
|
||||||
|
void finalMapping(PointSet *es, Mat &output); |
||||||
|
}; |
||||||
|
|
||||||
|
void GraphSegmentationImpl::filter(const Mat &img, Mat &img_filtered) { |
||||||
|
|
||||||
|
Mat img_converted; |
||||||
|
|
||||||
|
// Switch to float
|
||||||
|
img.convertTo(img_converted, CV_32F); |
||||||
|
|
||||||
|
// Apply gaussian filter
|
||||||
|
GaussianBlur(img_converted, img_filtered, Size(0, 0), sigma, sigma); |
||||||
|
} |
||||||
|
|
||||||
|
void GraphSegmentationImpl::buildGraph(Edge **edges, int &nb_edges, const Mat &img_filtered) { |
||||||
|
|
||||||
|
*edges = new Edge[img_filtered.rows * img_filtered.cols * 4]; |
||||||
|
|
||||||
|
nb_edges = 0; |
||||||
|
|
||||||
|
int nb_channels = img_filtered.channels(); |
||||||
|
|
||||||
|
for (int i = 0; i < (int)img_filtered.rows; i++) { |
||||||
|
const float* p = img_filtered.ptr<float>(i); |
||||||
|
|
||||||
|
for (int j = 0; j < (int)img_filtered.cols; j++) { |
||||||
|
|
||||||
|
//Take the right, left, top and down pixel
|
||||||
|
for (int delta = -1; delta <= 1; delta += 2) { |
||||||
|
for (int delta_j = 0, delta_i = 1; delta_j <= 1; delta_j++ || delta_i--) { |
||||||
|
|
||||||
|
int i2 = i + delta * delta_i; |
||||||
|
int j2 = j + delta * delta_j; |
||||||
|
|
||||||
|
if (i2 >= 0 && i2 < img_filtered.rows && j2 >= 0 && j2 < img_filtered.cols) { |
||||||
|
const float* p2 = img_filtered.ptr<float>(i2); |
||||||
|
|
||||||
|
float tmp_total = 0; |
||||||
|
|
||||||
|
for ( int channel = 0; channel < nb_channels; channel++) { |
||||||
|
tmp_total += pow(p[j * nb_channels + channel] - p2[j2 * nb_channels + channel], 2); |
||||||
|
} |
||||||
|
|
||||||
|
float diff = 0; |
||||||
|
diff = sqrt(tmp_total); |
||||||
|
|
||||||
|
(*edges)[nb_edges].weight = diff; |
||||||
|
(*edges)[nb_edges].from = i * img_filtered.cols + j; |
||||||
|
(*edges)[nb_edges].to = i2 * img_filtered.cols + j2; |
||||||
|
|
||||||
|
nb_edges++; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void GraphSegmentationImpl::segmentGraph(Edge *edges, const int &nb_edges, const Mat &img_filtered, PointSet **es) { |
||||||
|
|
||||||
|
int total_points = ( int)(img_filtered.rows * img_filtered.cols); |
||||||
|
|
||||||
|
// Sort edges
|
||||||
|
std::sort(edges, edges + nb_edges); |
||||||
|
|
||||||
|
// Create a set with all point (by default mapped to themselfs)
|
||||||
|
*es = new PointSet(img_filtered.cols * img_filtered.rows); |
||||||
|
|
||||||
|
// Thresholds
|
||||||
|
float* thresholds = new float[total_points]; |
||||||
|
|
||||||
|
for (int i = 0; i < total_points; i++) |
||||||
|
thresholds[i] = k; |
||||||
|
|
||||||
|
for ( int i = 0; i < nb_edges; i++) { |
||||||
|
|
||||||
|
int p_a = (*es)->getBasePoint(edges[i].from); |
||||||
|
int p_b = (*es)->getBasePoint(edges[i].to); |
||||||
|
|
||||||
|
if (p_a != p_b) { |
||||||
|
if (edges[i].weight <= thresholds[p_a] && edges[i].weight <= thresholds[p_b]) { |
||||||
|
(*es)->joinPoints(p_a, p_b); |
||||||
|
p_a = (*es)->getBasePoint(p_a); |
||||||
|
thresholds[p_a] = edges[i].weight + k / (*es)->size(p_a); |
||||||
|
|
||||||
|
edges[i].weight = 0; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void GraphSegmentationImpl::filterSmallAreas(Edge *edges, const int &nb_edges, PointSet *es) { |
||||||
|
|
||||||
|
for ( int i = 0; i < nb_edges; i++) { |
||||||
|
|
||||||
|
if (edges[i].weight > 0) { |
||||||
|
|
||||||
|
int p_a = es->getBasePoint(edges[i].from); |
||||||
|
int p_b = es->getBasePoint(edges[i].to); |
||||||
|
|
||||||
|
if (p_a != p_b && (es->size(p_a) < min_size || es->size(p_b) < min_size)) { |
||||||
|
es->joinPoints(p_a, p_b); |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
void GraphSegmentationImpl::finalMapping(PointSet *es, Mat &output) { |
||||||
|
|
||||||
|
int maximum_size = ( int)(output.rows * output.cols); |
||||||
|
|
||||||
|
int last_id = 0; |
||||||
|
int * mapped_id = new int[maximum_size]; |
||||||
|
|
||||||
|
for ( int i = 0; i < maximum_size; i++) |
||||||
|
mapped_id[i] = -1; |
||||||
|
|
||||||
|
int rows = output.rows; |
||||||
|
int cols = output.cols; |
||||||
|
|
||||||
|
if (output.isContinuous()) { |
||||||
|
cols *= rows; |
||||||
|
rows = 1; |
||||||
|
} |
||||||
|
|
||||||
|
for (int i = 0; i < rows; i++) { |
||||||
|
|
||||||
|
int* p = output.ptr<int>(i); |
||||||
|
|
||||||
|
for (int j = 0; j < cols; j++) { |
||||||
|
|
||||||
|
int point = es->getBasePoint(i * cols + j); |
||||||
|
|
||||||
|
if (mapped_id[point] == -1) { |
||||||
|
mapped_id[point] = last_id; |
||||||
|
last_id++; |
||||||
|
} |
||||||
|
|
||||||
|
p[j] = mapped_id[point]; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void GraphSegmentationImpl::processImage(InputArray src, OutputArray dst) { |
||||||
|
|
||||||
|
Mat img = src.getMat(); |
||||||
|
|
||||||
|
dst.create(img.rows, img.cols, CV_32SC1); |
||||||
|
Mat output = dst.getMat(); |
||||||
|
output.setTo(0); |
||||||
|
|
||||||
|
// Filter graph
|
||||||
|
Mat img_filtered; |
||||||
|
filter(img, img_filtered); |
||||||
|
|
||||||
|
// Build graph
|
||||||
|
Edge *edges; |
||||||
|
int nb_edges; |
||||||
|
|
||||||
|
buildGraph(&edges, nb_edges, img_filtered); |
||||||
|
|
||||||
|
// Segment graph
|
||||||
|
PointSet *es; |
||||||
|
|
||||||
|
segmentGraph(edges, nb_edges, img_filtered, &es); |
||||||
|
|
||||||
|
// Remove small areas
|
||||||
|
filterSmallAreas(edges, nb_edges, es); |
||||||
|
|
||||||
|
// Map to final output
|
||||||
|
finalMapping(es, output); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
Ptr<GraphSegmentation> createGraphSegmentation(double sigma, float k, int min_size) { |
||||||
|
|
||||||
|
Ptr<GraphSegmentation> graphseg = makePtr<GraphSegmentationImpl>(); |
||||||
|
|
||||||
|
graphseg->setSigma(sigma); |
||||||
|
graphseg->setK(k); |
||||||
|
graphseg->setMinSize(min_size); |
||||||
|
|
||||||
|
return graphseg; |
||||||
|
} |
||||||
|
|
||||||
|
PointSet::PointSet(int nb_elements_) { |
||||||
|
nb_elements = nb_elements_; |
||||||
|
|
||||||
|
mapping = new PointSetElement[nb_elements]; |
||||||
|
|
||||||
|
for ( int i = 0; i < nb_elements; i++) { |
||||||
|
mapping[i] = PointSetElement(i); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
int PointSet::getBasePoint( int p) { |
||||||
|
|
||||||
|
int base_p = p; |
||||||
|
|
||||||
|
while (base_p != mapping[base_p].p) { |
||||||
|
base_p = mapping[base_p].p; |
||||||
|
} |
||||||
|
|
||||||
|
// Save mapping for faster acces later
|
||||||
|
mapping[p].p = base_p; |
||||||
|
|
||||||
|
return base_p; |
||||||
|
} |
||||||
|
|
||||||
|
void PointSet::joinPoints(int p_a, int p_b) { |
||||||
|
|
||||||
|
// Always target smaller set, to avoid redirection in getBasePoint
|
||||||
|
if (mapping[p_a].size < mapping[p_b].size) |
||||||
|
swap(p_a, p_b); |
||||||
|
|
||||||
|
mapping[p_b].p = p_a; |
||||||
|
mapping[p_a].size += mapping[p_b].size; |
||||||
|
|
||||||
|
nb_elements--; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
Loading…
Reference in new issue