From 16d70c83fad185fdc498e78b6a32881d714ee794 Mon Sep 17 00:00:00 2001 From: berak Date: Tue, 23 Dec 2014 12:59:39 +0100 Subject: [PATCH 1/6] updated to cv::Mat, works with 3.0 --- slic.cpp | 135 ++++++++++++++++++++++++-------------------------- slic.h | 21 ++++---- test_slic.cpp | 23 ++++----- 3 files changed, 86 insertions(+), 93 deletions(-) diff --git a/slic.cpp b/slic.cpp index acebf31..e2d6f0a 100644 --- a/slic.cpp +++ b/slic.cpp @@ -31,15 +31,15 @@ void Slic::clear_data() { * Initialize the cluster centers and initial values of the pixel-wise cluster * assignment and distance values. * - * Input : The image (IplImage*). + * Input : The image (cv::Mat). * Output: - */ -void Slic::init_data(IplImage *image) { +void Slic::init_data(const cv::Mat &image) { /* Initialize the cluster and distance matrices. */ - for (int i = 0; i < image->width; i++) { + for (int i = 0; i < image.cols; i++) { vector cr; vector dr; - for (int j = 0; j < image->height; j++) { + for (int j = 0; j < image.rows; j++) { cr.push_back(-1); dr.push_back(FLT_MAX); } @@ -48,12 +48,12 @@ void Slic::init_data(IplImage *image) { } /* Initialize the centers and counters. */ - for (int i = step; i < image->width - step/2; i += step) { - for (int j = step; j < image->height - step/2; j += step) { + for (int i = step; i < image.cols - step/2; i += step) { + for (int j = step; j < image.rows - step/2; j += step) { vector center; /* Find the local minimum (gradient-wise). */ - CvPoint nc = find_local_minimum(image, cvPoint(i,j)); - CvScalar colour = cvGet2D(image, nc.y, nc.x); + cv::Point nc = find_local_minimum(image, cv::Point(i,j)); + cv::Scalar colour = image.at(nc.y, nc.x); /* Generate the center vector. */ center.push_back(colour.val[0]); @@ -72,11 +72,11 @@ void Slic::init_data(IplImage *image) { /* * Compute the distance between a cluster center and an individual pixel. * - * Input : The cluster index (int), the pixel (CvPoint), and the Lab values of - * the pixel (CvScalar). + * Input : The cluster index (int), the pixel (cv::Point), and the Lab values of + * the pixel (cv::Scalar). * Output: The distance (double). */ -double Slic::compute_dist(int ci, CvPoint pixel, CvScalar colour) { +double Slic::compute_dist(int ci, cv::Point pixel, cv::Scalar colour) { double dc = sqrt(pow(centers[ci][0] - colour.val[0], 2) + pow(centers[ci][1] - colour.val[1], 2) + pow(centers[ci][2] - colour.val[2], 2)); double ds = sqrt(pow(centers[ci][3] - pixel.x, 2) + pow(centers[ci][4] - pixel.y, 2)); @@ -91,18 +91,18 @@ double Slic::compute_dist(int ci, CvPoint pixel, CvScalar colour) { * Find a local gradient minimum of a pixel in a 3x3 neighbourhood. This * method is called upon initialization of the cluster centers. * - * Input : The image (IplImage*) and the pixel center (CvPoint). - * Output: The local gradient minimum (CvPoint). + * Input : The image (cv::Mat &) and the pixel center (cv::Point). + * Output: The local gradient minimum (cv::Point). */ -CvPoint Slic::find_local_minimum(IplImage *image, CvPoint center) { +cv::Point Slic::find_local_minimum(const cv::Mat &image, cv::Point center) { double min_grad = FLT_MAX; - CvPoint loc_min = cvPoint(center.x, center.y); + cv::Point loc_min = cv::Point(center.x, center.y); for (int i = center.x-1; i < center.x+2; i++) { for (int j = center.y-1; j < center.y+2; j++) { - CvScalar c1 = cvGet2D(image, j+1, i); - CvScalar c2 = cvGet2D(image, j, i+1); - CvScalar c3 = cvGet2D(image, j, i); + cv::Scalar c1 = image.at(j+1, i); + cv::Scalar c2 = image.at(j, i+1); + cv::Scalar c3 = image.at(j, i); /* Convert colour values to grayscale values. */ double i1 = c1.val[0]; double i2 = c2.val[0]; @@ -131,7 +131,7 @@ CvPoint Slic::find_local_minimum(IplImage *image, CvPoint center) { * Input : The Lab image (IplImage*), the stepsize (int), and the weight (int). * Output: - */ -void Slic::generate_superpixels(IplImage *image, int step, int nc) { +void Slic::generate_superpixels(const cv::Mat &image, int step, int nc) { this->step = step; this->nc = nc; this->ns = step; @@ -143,20 +143,20 @@ void Slic::generate_superpixels(IplImage *image, int step, int nc) { /* Run EM for 10 iterations (as prescribed by the algorithm). */ for (int i = 0; i < NR_ITERATIONS; i++) { /* Reset distance values. */ - for (int j = 0; j < image->width; j++) { - for (int k = 0;k < image->height; k++) { + for (int j = 0; j < image.cols; j++) { + for (int k = 0;k < image.rows; k++) { distances[j][k] = FLT_MAX; } } for (int j = 0; j < (int) centers.size(); j++) { /* Only compare to pixels in a 2 x step by 2 x step region. */ - for (int k = centers[j][3] - step; k < centers[j][3] + step; k++) { - for (int l = centers[j][4] - step; l < centers[j][4] + step; l++) { + for (int k = int(centers[j][3]) - step; k < int(centers[j][3]) + step; k++) { + for (int l = int(centers[j][4]) - step; l < int(centers[j][4]) + step; l++) { - if (k >= 0 && k < image->width && l >= 0 && l < image->height) { - CvScalar colour = cvGet2D(image, l, k); - double d = compute_dist(j, cvPoint(k,l), colour); + if (k >= 0 && k < image.cols && l >= 0 && l < image.rows) { + cv::Scalar colour = image.at(l, k); + double d = compute_dist(j, cv::Point(k,l), colour); /* Update cluster allocation if the cluster minimizes the distance. */ @@ -176,12 +176,12 @@ void Slic::generate_superpixels(IplImage *image, int step, int nc) { } /* Compute the new cluster centers. */ - for (int j = 0; j < image->width; j++) { - for (int k = 0; k < image->height; k++) { + for (int j = 0; j < image.cols; j++) { + for (int k = 0; k < image.rows; k++) { int c_id = clusters[j][k]; if (c_id != -1) { - CvScalar colour = cvGet2D(image, k, j); + cv::Scalar colour = image.at(k, j); centers[c_id][0] += colour.val[0]; centers[c_id][1] += colour.val[1]; @@ -210,37 +210,37 @@ void Slic::generate_superpixels(IplImage *image, int step, int nc) { * in the paper, but forms an active part of the implementation of the authors * of the paper. * - * Input : The image (IplImage*). + * Input : The image (cv::Mat). * Output: - */ -void Slic::create_connectivity(IplImage *image) { +void Slic::create_connectivity(const cv::Mat &image) { int label = 0, adjlabel = 0; - const int lims = (image->width * image->height) / ((int)centers.size()); + const int lims = (image.cols * image.rows) / ((int)centers.size()); const int dx4[4] = {-1, 0, 1, 0}; const int dy4[4] = { 0, -1, 0, 1}; /* Initialize the new cluster matrix. */ vec2di new_clusters; - for (int i = 0; i < image->width; i++) { + for (int i = 0; i < image.cols; i++) { vector nc; - for (int j = 0; j < image->height; j++) { + for (int j = 0; j < image.rows; j++) { nc.push_back(-1); } new_clusters.push_back(nc); } - for (int i = 0; i < image->width; i++) { - for (int j = 0; j < image->height; j++) { + for (int i = 0; i < image.cols; i++) { + for (int j = 0; j < image.rows; j++) { if (new_clusters[i][j] == -1) { - vector elements; - elements.push_back(cvPoint(i, j)); + vector elements; + elements.push_back(cv::Point(i, j)); /* Find an adjacent label, for possible use later. */ for (int k = 0; k < 4; k++) { int x = elements[0].x + dx4[k], y = elements[0].y + dy4[k]; - if (x >= 0 && x < image->width && y >= 0 && y < image->height) { + if (x >= 0 && x < image.cols && y >= 0 && y < image.rows) { if (new_clusters[x][y] >= 0) { adjlabel = new_clusters[x][y]; } @@ -252,9 +252,9 @@ void Slic::create_connectivity(IplImage *image) { for (int k = 0; k < 4; k++) { int x = elements[c].x + dx4[k], y = elements[c].y + dy4[k]; - if (x >= 0 && x < image->width && y >= 0 && y < image->height) { + if (x >= 0 && x < image.cols && y >= 0 && y < image.rows) { if (new_clusters[x][y] == -1 && clusters[i][j] == clusters[x][y]) { - elements.push_back(cvPoint(x, y)); + elements.push_back(cv::Point(x, y)); new_clusters[x][y] = label; count += 1; } @@ -279,47 +279,47 @@ void Slic::create_connectivity(IplImage *image) { /* * Display the cluster centers. * - * Input : The image to display upon (IplImage*) and the colour (CvScalar). + * Input : The image to display upon (IplImage*) and the colour (cv::Scalar). * Output: - */ -void Slic::display_center_grid(IplImage *image, CvScalar colour) { +void Slic::display_center_grid(cv::Mat &image, cv::Vec3b colour) { for (int i = 0; i < (int) centers.size(); i++) { - cvCircle(image, cvPoint(centers[i][3], centers[i][4]), 2, colour, 2); + cv::circle(image, cv::Point2d(centers[i][3], centers[i][4]), 2, colour, 2); } } /* * Display a single pixel wide contour around the clusters. * - * Input : The target image (IplImage*) and contour colour (CvScalar). + * Input : The target image (cv::Mat) and contour colour (cv::Scalar). * Output: - */ -void Slic::display_contours(IplImage *image, CvScalar colour) { +void Slic::display_contours(cv::Mat &image, cv::Vec3b colour) { const int dx8[8] = {-1, -1, 0, 1, 1, 1, 0, -1}; const int dy8[8] = { 0, -1, -1, -1, 0, 1, 1, 1}; /* Initialize the contour vector and the matrix detailing whether a pixel * is already taken to be a contour. */ - vector contours; + vector contours; vec2db istaken; - for (int i = 0; i < image->width; i++) { + for (int i = 0; i < image.cols; i++) { vector nb; - for (int j = 0; j < image->height; j++) { + for (int j = 0; j < image.rows; j++) { nb.push_back(false); } istaken.push_back(nb); } /* Go through all the pixels. */ - for (int i = 0; i < image->width; i++) { - for (int j = 0; j < image->height; j++) { + for (int i = 0; i < image.cols; i++) { + for (int j = 0; j < image.rows; j++) { int nr_p = 0; /* Compare the pixel to its 8 neighbours. */ for (int k = 0; k < 8; k++) { int x = i + dx8[k], y = j + dy8[k]; - if (x >= 0 && x < image->width && y >= 0 && y < image->height) { + if (x >= 0 && x < image.cols && y >= 0 && y < image.rows) { if (istaken[x][y] == false && clusters[i][j] != clusters[x][y]) { nr_p += 1; } @@ -328,7 +328,7 @@ void Slic::display_contours(IplImage *image, CvScalar colour) { /* Add the pixel to the contour list if desired. */ if (nr_p >= 2) { - contours.push_back(cvPoint(i,j)); + contours.push_back(cv::Point(i,j)); istaken[i][j] = true; } } @@ -336,7 +336,7 @@ void Slic::display_contours(IplImage *image, CvScalar colour) { /* Draw the contour pixels. */ for (int i = 0; i < (int)contours.size(); i++) { - cvSet2D(image, contours[i].y, contours[i].x, colour); + image.at(contours[i].y, contours[i].x) = colour; } } @@ -344,36 +344,29 @@ void Slic::display_contours(IplImage *image, CvScalar colour) { * Give the pixels of each cluster the same colour values. The specified colour * is the mean RGB colour per cluster. * - * Input : The target image (IplImage*). + * Input : The target image (cv::Mat). * Output: - */ -void Slic::colour_with_cluster_means(IplImage *image) { - vector colours(centers.size()); +void Slic::colour_with_cluster_means(cv::Mat &image) { + vector colours(centers.size()); /* Gather the colour values per cluster. */ - for (int i = 0; i < image->width; i++) { - for (int j = 0; j < image->height; j++) { + for (int i = 0; i < image.cols; i++) { + for (int j = 0; j < image.rows; j++) { int index = clusters[i][j]; - CvScalar colour = cvGet2D(image, j, i); - - colours[index].val[0] += colour.val[0]; - colours[index].val[1] += colour.val[1]; - colours[index].val[2] += colour.val[2]; + colours[index] += image.at(j, i); } } /* Divide by the number of pixels per cluster to get the mean colour. */ for (int i = 0; i < (int)colours.size(); i++) { - colours[i].val[0] /= center_counts[i]; - colours[i].val[1] /= center_counts[i]; - colours[i].val[2] /= center_counts[i]; + colours[i] /= center_counts[i]; } /* Fill in. */ - for (int i = 0; i < image->width; i++) { - for (int j = 0; j < image->height; j++) { - CvScalar ncolour = colours[clusters[i][j]]; - cvSet2D(image, j, i, ncolour); + for (int i = 0; i < image.cols; i++) { + for (int j = 0; j < image.rows; j++) { + image.at(j, i) = colours[clusters[i][j]];; } } } diff --git a/slic.h b/slic.h index 5e1785e..7798b2c 100644 --- a/slic.h +++ b/slic.h @@ -13,14 +13,15 @@ * over-segmentations in an OpenCV-based environment. */ -#include -#include #include #include #include #include using namespace std; +#include +using namespace cv; + /* 2d matrices are handled by 2d vectors. */ #define vec2dd vector > #define vec2di vector > @@ -51,13 +52,13 @@ class Slic { int step, nc, ns; /* Compute the distance between a center and an individual pixel. */ - double compute_dist(int ci, CvPoint pixel, CvScalar colour); + double compute_dist(int ci, cv::Point pixel, cv::Scalar colour); /* Find the pixel with the lowest gradient in a 3x3 surrounding. */ - CvPoint find_local_minimum(IplImage *image, CvPoint center); + cv::Point find_local_minimum(const cv::Mat &image, cv::Point center); /* Remove and initialize the 2d vectors. */ void clear_data(); - void init_data(IplImage *image); + void init_data(const cv::Mat &image); public: /* Class constructors and deconstructors. */ @@ -65,14 +66,14 @@ class Slic { ~Slic(); /* Generate an over-segmentation for an image. */ - void generate_superpixels(IplImage *image, int step, int nc); + void generate_superpixels(const cv::Mat &image, int step, int nc); /* Enforce connectivity for an image. */ - void create_connectivity(IplImage *image); + void create_connectivity(const cv::Mat &image); /* Draw functions. Resp. displayal of the centers and the contours. */ - void display_center_grid(IplImage *image, CvScalar colour); - void display_contours(IplImage *image, CvScalar colour); - void colour_with_cluster_means(IplImage *image); + void display_center_grid(cv::Mat &image, cv::Vec3b colour); + void display_contours(cv::Mat &image, cv::Vec3b colour); + void colour_with_cluster_means(cv::Mat &image); }; #endif diff --git a/test_slic.cpp b/test_slic.cpp index 36662e4..c461675 100644 --- a/test_slic.cpp +++ b/test_slic.cpp @@ -7,26 +7,26 @@ * superpixel algorithm, as implemented in slic.h and slic.cpp. */ -#include -#include #include #include #include #include using namespace std; +#include #include "slic.h" +using namespace cv; int main(int argc, char *argv[]) { /* Load the image and convert to Lab colour space. */ - IplImage *image = cvLoadImage(argv[1], 1); - IplImage *lab_image = cvCloneImage(image); - cvCvtColor(image, lab_image, CV_BGR2Lab); + Mat image = imread("dog.png", 1); + Mat lab_image; + cvtColor(image, lab_image, COLOR_BGR2Lab); /* Yield the number of superpixels and weight-factors from the user. */ - int w = image->width, h = image->height; - int nr_superpixels = atoi(argv[2]); - int nc = atoi(argv[3]); + int w = image.cols, h = image.rows; + int nr_superpixels = 400; + int nc = 40; double step = sqrt((w * h) / (double) nr_superpixels); @@ -36,8 +36,7 @@ int main(int argc, char *argv[]) { slic.create_connectivity(lab_image); /* Display the contours and show the result. */ - slic.display_contours(image, CV_RGB(255,0,0)); - cvShowImage("result", image); - cvWaitKey(0); - cvSaveImage(argv[4], image); + slic.display_contours(image, Vec3b(0,0,255)); + imshow("result", image); + waitKey(0); } From f9435a69abea09f5be760d1f17b1c8289a580c5b Mon Sep 17 00:00:00 2001 From: berak Date: Tue, 23 Dec 2014 15:30:11 +0100 Subject: [PATCH 2/6] swapped most Scalars to Vec3b --- slic.cpp | 48 ++++++++++++++++++++++++------------------------ slic.h | 4 ++-- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/slic.cpp b/slic.cpp index e2d6f0a..8379e95 100644 --- a/slic.cpp +++ b/slic.cpp @@ -53,7 +53,7 @@ void Slic::init_data(const cv::Mat &image) { vector center; /* Find the local minimum (gradient-wise). */ cv::Point nc = find_local_minimum(image, cv::Point(i,j)); - cv::Scalar colour = image.at(nc.y, nc.x); + cv::Vec3b colour = image.at(nc.y, nc.x); /* Generate the center vector. */ center.push_back(colour.val[0]); @@ -76,13 +76,12 @@ void Slic::init_data(const cv::Mat &image) { * the pixel (cv::Scalar). * Output: The distance (double). */ -double Slic::compute_dist(int ci, cv::Point pixel, cv::Scalar colour) { - double dc = sqrt(pow(centers[ci][0] - colour.val[0], 2) + pow(centers[ci][1] - - colour.val[1], 2) + pow(centers[ci][2] - colour.val[2], 2)); +double Slic::compute_dist(int ci, cv::Point pixel, cv::Vec3b colour) { + double dc = sqrt(pow(centers[ci][0] - colour[0], 2) + pow(centers[ci][1] + - colour[1], 2) + pow(centers[ci][2] - colour[2], 2)); double ds = sqrt(pow(centers[ci][3] - pixel.x, 2) + pow(centers[ci][4] - pixel.y, 2)); return sqrt(pow(dc / nc, 2) + pow(ds / ns, 2)); - //double w = 1.0 / (pow(ns / nc, 2)); //return sqrt(dc) + sqrt(ds * w); } @@ -94,19 +93,19 @@ double Slic::compute_dist(int ci, cv::Point pixel, cv::Scalar colour) { * Input : The image (cv::Mat &) and the pixel center (cv::Point). * Output: The local gradient minimum (cv::Point). */ -cv::Point Slic::find_local_minimum(const cv::Mat &image, cv::Point center) { - double min_grad = FLT_MAX; - cv::Point loc_min = cv::Point(center.x, center.y); +cv::Point Slic::find_local_minimum(const cv::Mat_ &image, cv::Point center) { + double min_grad = DBL_MAX; + cv::Point loc_min(center.x, center.y); for (int i = center.x-1; i < center.x+2; i++) { for (int j = center.y-1; j < center.y+2; j++) { - cv::Scalar c1 = image.at(j+1, i); - cv::Scalar c2 = image.at(j, i+1); - cv::Scalar c3 = image.at(j, i); + cv::Vec3b c1 = image(j+1, i); + cv::Vec3b c2 = image(j, i+1); + cv::Vec3b c3 = image(j, i); /* Convert colour values to grayscale values. */ - double i1 = c1.val[0]; - double i2 = c2.val[0]; - double i3 = c3.val[0]; + double i1 = c1[0]; + double i2 = c2[0]; + double i3 = c3[0]; /*double i1 = c1.val[0] * 0.11 + c1.val[1] * 0.59 + c1.val[2] * 0.3; double i2 = c2.val[0] * 0.11 + c2.val[1] * 0.59 + c2.val[2] * 0.3; double i3 = c3.val[0] * 0.11 + c3.val[1] * 0.59 + c3.val[2] * 0.3;*/ @@ -131,11 +130,14 @@ cv::Point Slic::find_local_minimum(const cv::Mat &image, cv::Point center) { * Input : The Lab image (IplImage*), the stepsize (int), and the weight (int). * Output: - */ -void Slic::generate_superpixels(const cv::Mat &image, int step, int nc) { +void Slic::generate_superpixels(const cv::Mat &img, int step, int nc) { this->step = step; this->nc = nc; this->ns = step; + /* make a new Mat header, that allows us to iterate the image more efficiently. */ + Mat_ image(img); + /* Clear previous data (if any), and re-initialize it. */ clear_data(); init_data(image); @@ -155,7 +157,7 @@ void Slic::generate_superpixels(const cv::Mat &image, int step, int nc) { for (int l = int(centers[j][4]) - step; l < int(centers[j][4]) + step; l++) { if (k >= 0 && k < image.cols && l >= 0 && l < image.rows) { - cv::Scalar colour = image.at(l, k); + cv::Vec3b colour = image(l, k); double d = compute_dist(j, cv::Point(k,l), colour); /* Update cluster allocation if the cluster minimizes the @@ -181,15 +183,13 @@ void Slic::generate_superpixels(const cv::Mat &image, int step, int nc) { int c_id = clusters[j][k]; if (c_id != -1) { - cv::Scalar colour = image.at(k, j); + cv::Vec3b colour = image(k, j); - centers[c_id][0] += colour.val[0]; - centers[c_id][1] += colour.val[1]; - centers[c_id][2] += colour.val[2]; + centers[c_id][0] += colour[0]; + centers[c_id][1] += colour[1]; + centers[c_id][2] += colour[2]; centers[c_id][3] += j; centers[c_id][4] += k; - - center_counts[c_id] += 1; } } } @@ -279,7 +279,7 @@ void Slic::create_connectivity(const cv::Mat &image) { /* * Display the cluster centers. * - * Input : The image to display upon (IplImage*) and the colour (cv::Scalar). + * Input : The image to display upon (cv::Mat) and the colour (cv::Vec3b). * Output: - */ void Slic::display_center_grid(cv::Mat &image, cv::Vec3b colour) { @@ -291,7 +291,7 @@ void Slic::display_center_grid(cv::Mat &image, cv::Vec3b colour) { /* * Display a single pixel wide contour around the clusters. * - * Input : The target image (cv::Mat) and contour colour (cv::Scalar). + * Input : The target image (cv::Mat) and contour colour (cv::Vec3b). * Output: - */ void Slic::display_contours(cv::Mat &image, cv::Vec3b colour) { diff --git a/slic.h b/slic.h index 7798b2c..c926b46 100644 --- a/slic.h +++ b/slic.h @@ -52,9 +52,9 @@ class Slic { int step, nc, ns; /* Compute the distance between a center and an individual pixel. */ - double compute_dist(int ci, cv::Point pixel, cv::Scalar colour); + double compute_dist(int ci, cv::Point pixel, cv::Vec3b colour); /* Find the pixel with the lowest gradient in a 3x3 surrounding. */ - cv::Point find_local_minimum(const cv::Mat &image, cv::Point center); + cv::Point find_local_minimum(const cv::Mat_ &image, cv::Point center); /* Remove and initialize the 2d vectors. */ void clear_data(); From ba5a0ac7f8b20ece704165f2a82e6f383ae106ad Mon Sep 17 00:00:00 2001 From: berak Date: Tue, 23 Dec 2014 15:30:11 +0100 Subject: [PATCH 3/6] cleanup --- slic.cpp | 10 +++++----- slic.h | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/slic.cpp b/slic.cpp index 8379e95..c81993e 100644 --- a/slic.cpp +++ b/slic.cpp @@ -53,7 +53,7 @@ void Slic::init_data(const cv::Mat &image) { vector center; /* Find the local minimum (gradient-wise). */ cv::Point nc = find_local_minimum(image, cv::Point(i,j)); - cv::Vec3b colour = image.at(nc.y, nc.x); + cv::Vec3b colour = image.at(nc.y, nc.x); /* Generate the center vector. */ center.push_back(colour.val[0]); @@ -136,7 +136,7 @@ void Slic::generate_superpixels(const cv::Mat &img, int step, int nc) { this->ns = step; /* make a new Mat header, that allows us to iterate the image more efficiently. */ - Mat_ image(img); + cv::Mat_ image(img); /* Clear previous data (if any), and re-initialize it. */ clear_data(); @@ -336,7 +336,7 @@ void Slic::display_contours(cv::Mat &image, cv::Vec3b colour) { /* Draw the contour pixels. */ for (int i = 0; i < (int)contours.size(); i++) { - image.at(contours[i].y, contours[i].x) = colour; + image.at(contours[i].y, contours[i].x) = colour; } } @@ -354,7 +354,7 @@ void Slic::colour_with_cluster_means(cv::Mat &image) { for (int i = 0; i < image.cols; i++) { for (int j = 0; j < image.rows; j++) { int index = clusters[i][j]; - colours[index] += image.at(j, i); + colours[index] += image.at(j, i); } } @@ -366,7 +366,7 @@ void Slic::colour_with_cluster_means(cv::Mat &image) { /* Fill in. */ for (int i = 0; i < image.cols; i++) { for (int j = 0; j < image.rows; j++) { - image.at(j, i) = colours[clusters[i][j]];; + image.at(j, i) = colours[clusters[i][j]];; } } } diff --git a/slic.h b/slic.h index c926b46..69d5a8d 100644 --- a/slic.h +++ b/slic.h @@ -20,7 +20,7 @@ using namespace std; #include -using namespace cv; +//using namespace cv; /* 2d matrices are handled by 2d vectors. */ #define vec2dd vector > @@ -54,7 +54,7 @@ class Slic { /* Compute the distance between a center and an individual pixel. */ double compute_dist(int ci, cv::Point pixel, cv::Vec3b colour); /* Find the pixel with the lowest gradient in a 3x3 surrounding. */ - cv::Point find_local_minimum(const cv::Mat_ &image, cv::Point center); + cv::Point find_local_minimum(const cv::Mat_ &image, cv::Point center); /* Remove and initialize the 2d vectors. */ void clear_data(); From e40dab2fa430400f8a6d05aaebb550d52597e2c3 Mon Sep 17 00:00:00 2001 From: berak Date: Tue, 23 Dec 2014 18:53:31 +0100 Subject: [PATCH 4/6] Scalar trouble on 2.4.9 --- slic.cpp | 2 +- slic.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/slic.cpp b/slic.cpp index c81993e..e9f1ae6 100644 --- a/slic.cpp +++ b/slic.cpp @@ -282,7 +282,7 @@ void Slic::create_connectivity(const cv::Mat &image) { * Input : The image to display upon (cv::Mat) and the colour (cv::Vec3b). * Output: - */ -void Slic::display_center_grid(cv::Mat &image, cv::Vec3b colour) { +void Slic::display_center_grid(cv::Mat &image, cv::Scalar colour) { for (int i = 0; i < (int) centers.size(); i++) { cv::circle(image, cv::Point2d(centers[i][3], centers[i][4]), 2, colour, 2); } diff --git a/slic.h b/slic.h index 69d5a8d..807d295 100644 --- a/slic.h +++ b/slic.h @@ -71,7 +71,7 @@ class Slic { void create_connectivity(const cv::Mat &image); /* Draw functions. Resp. displayal of the centers and the contours. */ - void display_center_grid(cv::Mat &image, cv::Vec3b colour); + void display_center_grid(cv::Mat &image, cv::Scalar colour); void display_contours(cv::Mat &image, cv::Vec3b colour); void colour_with_cluster_means(cv::Mat &image); }; From 3e78dab5ed9de3fdcd5a8e4f98fe1685b2f9e055 Mon Sep 17 00:00:00 2001 From: berak Date: Tue, 23 Dec 2014 14:04:44 +0100 Subject: [PATCH 5/6] reduced 30% time by changing 2d vectors to cv::Mat --- slic.cpp | 130 +++++++++++++++++++------------------------------- slic.h | 13 +++-- test_slic.cpp | 7 +-- 3 files changed, 59 insertions(+), 91 deletions(-) diff --git a/slic.cpp b/slic.cpp index e9f1ae6..dd21f4e 100644 --- a/slic.cpp +++ b/slic.cpp @@ -1,5 +1,7 @@ #include "slic.h" + + /* * Constructor. Nothing is done here. */ @@ -21,9 +23,10 @@ Slic::~Slic() { * Output: - */ void Slic::clear_data() { - clusters.clear(); - distances.clear(); - centers.clear(); + clusters.release(); + distances.release(); + centers.release(); + //centers.clear(); center_counts.clear(); } @@ -36,31 +39,19 @@ void Slic::clear_data() { */ void Slic::init_data(const cv::Mat &image) { /* Initialize the cluster and distance matrices. */ - for (int i = 0; i < image.cols; i++) { - vector cr; - vector dr; - for (int j = 0; j < image.rows; j++) { - cr.push_back(-1); - dr.push_back(FLT_MAX); - } - clusters.push_back(cr); - distances.push_back(dr); - } - + + clusters = cv::Mat_(image.cols,image.rows,-1); + distances = cv::Mat_(image.cols,image.rows,DBL_MAX); + /* Initialize the centers and counters. */ for (int i = step; i < image.cols - step/2; i += step) { for (int j = step; j < image.rows - step/2; j += step) { - vector center; /* Find the local minimum (gradient-wise). */ cv::Point nc = find_local_minimum(image, cv::Point(i,j)); cv::Vec3b colour = image.at(nc.y, nc.x); /* Generate the center vector. */ - center.push_back(colour.val[0]); - center.push_back(colour.val[1]); - center.push_back(colour.val[2]); - center.push_back(nc.x); - center.push_back(nc.y); + Vec5d center(colour[0], colour[1], colour[2], nc.x, nc.y); /* Append to vector of centers. */ centers.push_back(center); @@ -77,11 +68,13 @@ void Slic::init_data(const cv::Mat &image) { * Output: The distance (double). */ double Slic::compute_dist(int ci, cv::Point pixel, cv::Vec3b colour) { - double dc = sqrt(pow(centers[ci][0] - colour[0], 2) + pow(centers[ci][1] - - colour[1], 2) + pow(centers[ci][2] - colour[2], 2)); - double ds = sqrt(pow(centers[ci][3] - pixel.x, 2) + pow(centers[ci][4] - pixel.y, 2)); + Vec5d cen(centers(ci)); + double dc = sqrt(pow(cen[0] - colour[0], 2) + pow(cen[1] + - colour[1], 2) + pow(cen[2] - colour[2], 2)); + double ds = sqrt(pow(cen[3] - pixel.x, 2) + pow(cen[4] - pixel.y, 2)); return sqrt(pow(dc / nc, 2) + pow(ds / ns, 2)); + //double w = 1.0 / (pow(ns / nc, 2)); //return sqrt(dc) + sqrt(ds * w); } @@ -127,7 +120,7 @@ cv::Point Slic::find_local_minimum(const cv::Mat_ &image, cv::Point c * Compute the over-segmentation based on the step-size and relative weighting * of the pixel and colour values. * - * Input : The Lab image (IplImage*), the stepsize (int), and the weight (int). + * Input : The Lab image (cv::Mat), the stepsize (int), and the weight (int). * Output: - */ void Slic::generate_superpixels(const cv::Mat &img, int step, int nc) { @@ -145,16 +138,13 @@ void Slic::generate_superpixels(const cv::Mat &img, int step, int nc) { /* Run EM for 10 iterations (as prescribed by the algorithm). */ for (int i = 0; i < NR_ITERATIONS; i++) { /* Reset distance values. */ - for (int j = 0; j < image.cols; j++) { - for (int k = 0;k < image.rows; k++) { - distances[j][k] = FLT_MAX; - } - } + distances = FLT_MAX; - for (int j = 0; j < (int) centers.size(); j++) { + for (int j = 0; j < centers.rows; j++) { + Vec5d cen(centers(j)); /* Only compare to pixels in a 2 x step by 2 x step region. */ - for (int k = int(centers[j][3]) - step; k < int(centers[j][3]) + step; k++) { - for (int l = int(centers[j][4]) - step; l < int(centers[j][4]) + step; l++) { + for (int k = int(cen[3]) - step; k < int(cen[3]) + step; k++) { + for (int l = int(cen[4]) - step; l < int(cen[4]) + step; l++) { if (k >= 0 && k < image.cols && l >= 0 && l < image.rows) { cv::Vec3b colour = image(l, k); @@ -162,9 +152,9 @@ void Slic::generate_superpixels(const cv::Mat &img, int step, int nc) { /* Update cluster allocation if the cluster minimizes the distance. */ - if (d < distances[k][l]) { - distances[k][l] = d; - clusters[k][l] = j; + if (d < distances(k,l)) { + distances(k,l) = d; + clusters(k,l) = j; } } } @@ -172,35 +162,27 @@ void Slic::generate_superpixels(const cv::Mat &img, int step, int nc) { } /* Clear the center values. */ - for (int j = 0; j < (int) centers.size(); j++) { - centers[j][0] = centers[j][1] = centers[j][2] = centers[j][3] = centers[j][4] = 0; + for (int j = 0; j < centers.rows; j++) { + centers(j) = 0; center_counts[j] = 0; } /* Compute the new cluster centers. */ for (int j = 0; j < image.cols; j++) { for (int k = 0; k < image.rows; k++) { - int c_id = clusters[j][k]; + int c_id = clusters(j,k); if (c_id != -1) { - cv::Vec3b colour = image(k, j); - - centers[c_id][0] += colour[0]; - centers[c_id][1] += colour[1]; - centers[c_id][2] += colour[2]; - centers[c_id][3] += j; - centers[c_id][4] += k; + cv::Vec3b colour = image(k, j); + centers(c_id) += Vec5d(colour[0], colour[1], colour[2], j, k); + center_counts[c_id] += 1; } } } /* Normalize the clusters. */ - for (int j = 0; j < (int) centers.size(); j++) { - centers[j][0] /= center_counts[j]; - centers[j][1] /= center_counts[j]; - centers[j][2] /= center_counts[j]; - centers[j][3] /= center_counts[j]; - centers[j][4] /= center_counts[j]; + for (int j = 0; j < centers.rows; j++) { + centers(j) /= center_counts[j]; } } } @@ -215,24 +197,17 @@ void Slic::generate_superpixels(const cv::Mat &img, int step, int nc) { */ void Slic::create_connectivity(const cv::Mat &image) { int label = 0, adjlabel = 0; - const int lims = (image.cols * image.rows) / ((int)centers.size()); + const int lims = (image.cols * image.rows) / (centers.rows); const int dx4[4] = {-1, 0, 1, 0}; const int dy4[4] = { 0, -1, 0, 1}; /* Initialize the new cluster matrix. */ - vec2di new_clusters; - for (int i = 0; i < image.cols; i++) { - vector nc; - for (int j = 0; j < image.rows; j++) { - nc.push_back(-1); - } - new_clusters.push_back(nc); - } + cv::Mat_ new_clusters(image.cols,image.rows,-1); for (int i = 0; i < image.cols; i++) { for (int j = 0; j < image.rows; j++) { - if (new_clusters[i][j] == -1) { + if (new_clusters(i,j) == -1) { vector elements; elements.push_back(cv::Point(i, j)); @@ -241,8 +216,8 @@ void Slic::create_connectivity(const cv::Mat &image) { int x = elements[0].x + dx4[k], y = elements[0].y + dy4[k]; if (x >= 0 && x < image.cols && y >= 0 && y < image.rows) { - if (new_clusters[x][y] >= 0) { - adjlabel = new_clusters[x][y]; + if (new_clusters(x,y) >= 0) { + adjlabel = new_clusters(x,y); } } } @@ -253,9 +228,9 @@ void Slic::create_connectivity(const cv::Mat &image) { int x = elements[c].x + dx4[k], y = elements[c].y + dy4[k]; if (x >= 0 && x < image.cols && y >= 0 && y < image.rows) { - if (new_clusters[x][y] == -1 && clusters[i][j] == clusters[x][y]) { + if (new_clusters(x,y) == -1 && clusters(i,j) == clusters(x,y)) { elements.push_back(cv::Point(x, y)); - new_clusters[x][y] = label; + new_clusters(x,y) = label; count += 1; } } @@ -266,7 +241,7 @@ void Slic::create_connectivity(const cv::Mat &image) { smaller than a limit. */ if (count <= lims >> 2) { for (int c = 0; c < count; c++) { - new_clusters[elements[c].x][elements[c].y] = adjlabel; + new_clusters(elements[c].x, elements[c].y) = adjlabel; } label -= 1; } @@ -283,8 +258,8 @@ void Slic::create_connectivity(const cv::Mat &image) { * Output: - */ void Slic::display_center_grid(cv::Mat &image, cv::Scalar colour) { - for (int i = 0; i < (int) centers.size(); i++) { - cv::circle(image, cv::Point2d(centers[i][3], centers[i][4]), 2, colour, 2); + for (int i = 0; i < centers.rows; i++) { + cv::circle(image, cv::Point2d(centers(i)[3], centers(i)[4]), 2, colour, 2); } } @@ -301,14 +276,7 @@ void Slic::display_contours(cv::Mat &image, cv::Vec3b colour) { /* Initialize the contour vector and the matrix detailing whether a pixel * is already taken to be a contour. */ vector contours; - vec2db istaken; - for (int i = 0; i < image.cols; i++) { - vector nb; - for (int j = 0; j < image.rows; j++) { - nb.push_back(false); - } - istaken.push_back(nb); - } + cv::Mat_ istaken(image.cols, image.rows, uchar(0)); /* Go through all the pixels. */ for (int i = 0; i < image.cols; i++) { @@ -320,7 +288,7 @@ void Slic::display_contours(cv::Mat &image, cv::Vec3b colour) { int x = i + dx8[k], y = j + dy8[k]; if (x >= 0 && x < image.cols && y >= 0 && y < image.rows) { - if (istaken[x][y] == false && clusters[i][j] != clusters[x][y]) { + if (istaken(x,y) == false && clusters(i,j) != clusters(x,y)) { nr_p += 1; } } @@ -329,7 +297,7 @@ void Slic::display_contours(cv::Mat &image, cv::Vec3b colour) { /* Add the pixel to the contour list if desired. */ if (nr_p >= 2) { contours.push_back(cv::Point(i,j)); - istaken[i][j] = true; + istaken(i,j) = true; } } } @@ -348,12 +316,12 @@ void Slic::display_contours(cv::Mat &image, cv::Vec3b colour) { * Output: - */ void Slic::colour_with_cluster_means(cv::Mat &image) { - vector colours(centers.size()); + vector colours(centers.rows); /* Gather the colour values per cluster. */ for (int i = 0; i < image.cols; i++) { for (int j = 0; j < image.rows; j++) { - int index = clusters[i][j]; + int index = clusters(i,j); colours[index] += image.at(j, i); } } @@ -366,7 +334,7 @@ void Slic::colour_with_cluster_means(cv::Mat &image) { /* Fill in. */ for (int i = 0; i < image.cols; i++) { for (int j = 0; j < image.rows; j++) { - image.at(j, i) = colours[clusters[i][j]];; + image.at(j, i) = colours[clusters(i,j)];; } } } diff --git a/slic.h b/slic.h index 807d295..eeabe8b 100644 --- a/slic.h +++ b/slic.h @@ -22,13 +22,12 @@ using namespace std; #include //using namespace cv; -/* 2d matrices are handled by 2d vectors. */ -#define vec2dd vector > -#define vec2di vector > -#define vec2db vector > /* The number of iterations run by the clustering algorithm. */ #define NR_ITERATIONS 10 +typedef cv::Vec Vec5d; + + /* * class Slic. * @@ -39,11 +38,11 @@ using namespace std; class Slic { private: /* The cluster assignments and distance values for each pixel. */ - vec2di clusters; - vec2dd distances; + cv::Mat_ clusters; + cv::Mat_ distances; /* The LAB and xy values of the centers. */ - vec2dd centers; + cv::Mat_ centers; /* The number of occurences of each center. */ vector center_counts; diff --git a/test_slic.cpp b/test_slic.cpp index c461675..eca21c8 100644 --- a/test_slic.cpp +++ b/test_slic.cpp @@ -17,6 +17,7 @@ using namespace std; #include "slic.h" using namespace cv; + int main(int argc, char *argv[]) { /* Load the image and convert to Lab colour space. */ Mat image = imread("dog.png", 1); @@ -29,14 +30,14 @@ int main(int argc, char *argv[]) { int nc = 40; double step = sqrt((w * h) / (double) nr_superpixels); - + /* Perform the SLIC superpixel algorithm. */ Slic slic; - slic.generate_superpixels(lab_image, step, nc); + slic.generate_superpixels(lab_image, int(step), nc); slic.create_connectivity(lab_image); + slic.display_contours(image, Vec3b(0,0,255)); /* Display the contours and show the result. */ - slic.display_contours(image, Vec3b(0,0,255)); imshow("result", image); waitKey(0); } From 983c3c1975538ca578aceb2098c870fea6a56732 Mon Sep 17 00:00:00 2001 From: Ryohei Ueda Date: Mon, 19 Jan 2015 19:52:15 +0900 Subject: [PATCH 6/6] Use cv::Vec3i to compute mean color --- slic.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/slic.cpp b/slic.cpp index dd21f4e..77d5d22 100644 --- a/slic.cpp +++ b/slic.cpp @@ -316,13 +316,19 @@ void Slic::display_contours(cv::Mat &image, cv::Vec3b colour) { * Output: - */ void Slic::colour_with_cluster_means(cv::Mat &image) { - vector colours(centers.rows); - + vector colours(centers.rows); + /* fill */ + for (size_t i = 0; i < colours.size(); i++) { + colours[i] = cv::Vec3i(0, 0, 0); + } /* Gather the colour values per cluster. */ for (int i = 0; i < image.cols; i++) { for (int j = 0; j < image.rows; j++) { int index = clusters(i,j); - colours[index] += image.at(j, i); + cv::Vec3b c = image.at(j, i); + colours[index][0] += (c[0]); + colours[index][1] += (c[1]); + colours[index][2] += (c[2]); } } @@ -334,7 +340,8 @@ void Slic::colour_with_cluster_means(cv::Mat &image) { /* Fill in. */ for (int i = 0; i < image.cols; i++) { for (int j = 0; j < image.rows; j++) { - image.at(j, i) = colours[clusters(i,j)];; + cv::Vec3i c = colours[clusters(i,j)]; + image.at(j, i) = cv::Vec3b(c[0], c[1], c[2]); } } }