cv::Mat performSuperpixelSegmentation_VariableSandM(std::vector<std::vector<double> > &kseeds, std::vector<double> &kseedsx, std::vector<double> &kseedsy, const std::vector<cv::Mat> &vec, const cv::Size &size, const int &STEP, const int &NUMITR = 10) { int sz = size.width*size.height; const int numk = (int) kseedsx.size(); int numitr = 0; int offset = (STEP < 10) ? STEP*1.5 : STEP; cv::Mat klabels = cv::Mat(size, cv::DataType<int>::type); klabels = -1; std::vector<std::vector<double> > sigmac(0); for (int c = 0; c < vec.size(); c++) { sigmac.push_back(std::vector<double>(numk, 0)); } std::vector<double> sigmax(numk, 0); std::vector<double> sigmay(numk, 0); std::vector<int> clustersize(numk, 0); std::vector<double> inv(numk, 0);//to store 1/clustersize[k] values std::vector<double> distxy(sz, DBL_MAX); std::vector<double> distc(sz, DBL_MAX); std::vector<double> distvec(sz, DBL_MAX); std::vector<double> maxc(numk, 10*10);//THIS IS THE VARIABLE VALUE OF M, just start with 10 std::vector<double> maxxy(numk, STEP*STEP);//THIS IS THE VARIABLE VALUE OF M, just start with 10 double invxywt = 1.0/(STEP*STEP);//NOTE: this is different from how usual SLIC/LKM works while( numitr < NUMITR ) { //------ //cumerr = 0; numitr++; //------ distvec.assign(sz, DBL_MAX); for( int n = 0; n < numk; n++ ) { int y1 = std::max(double(0), kseedsy[n]-offset); int y2 = std::min(double(size.height), kseedsy[n]+offset); int x1 = std::max(double(0), kseedsx[n]-offset); int x2 = std::min(double(size.width), kseedsx[n]+offset); for( int y = y1; y < y2; y++ ) { for( int x = x1; x < x2; x++ ) { int i = y*size.width + x; if( !(y < size.height && x < size.width && y >= 0 && x >= 0) ) { throw cv::Exception(); } distc[i] = 0; for (int c = 0; c < vec.size(); c++) { distc[i] += (vec[c].ptr<double>()[i] - kseeds[c][n]) * (vec[c].ptr<double>()[i] - kseeds[c][n]); } distxy[i] = (x - kseedsx[n])*(x - kseedsx[n]) + (y - kseedsy[n])*(y - kseedsy[n]); double dist = distc[i]/maxc[n] + distxy[i]*invxywt;//only varying m, prettier superpixels if( dist < distvec[i] ) { distvec[i] = dist; klabels.ptr<int>()[i] = n; } } } } //----------------------------------------------------------------- // Assign the max color distance for a cluster //----------------------------------------------------------------- if(0 == numitr) { maxc.assign(numk,1); maxxy.assign(numk,1); } {for( int i = 0; i < sz; i++ ) { if(maxc[klabels.ptr<int>()[i]] < distc[i]) maxc[klabels.ptr<int>()[i]] = distc[i]; if(maxxy[klabels.ptr<int>()[i]] < distxy[i]) maxxy[klabels.ptr<int>()[i]] = distxy[i]; }} //----------------------------------------------------------------- // Recalculate the centroid and store in the seed values //----------------------------------------------------------------- for (int c = 0; c < sigmac.size(); c++) { sigmac[c].assign(numk, 0); } sigmax.assign(numk, 0); sigmay.assign(numk, 0); clustersize.assign(numk, 0); for( int j = 0; j < sz; j++ ) { if(!(klabels.ptr<int>()[j] >= 0)) throw cv::Exception(); for (int c = 0; c < sigmac.size(); c++) { sigmac[c][klabels.ptr<int>()[j]] += vec[c].ptr<double>()[j]; } sigmax[klabels.ptr<int>()[j]] += (j%size.width); sigmay[klabels.ptr<int>()[j]] += (j/size.width); clustersize[klabels.ptr<int>()[j]]++; } {for( int k = 0; k < numk; k++ ) { if( clustersize[k] <= 0 ) clustersize[k] = 1; inv[k] = 1.0/double(clustersize[k]);//computing inverse now to multiply, than divide later }} {for( int k = 0; k < numk; k++ ) { for (int c = 0; c < kseeds.size(); c++) { kseeds[c][k] = sigmac[c][k] * inv[k]; } kseedsx[k] = sigmax[k]*inv[k]; kseedsy[k] = sigmay[k]*inv[k]; }} } return klabels; }
//=========================================================================== /// PerformSuperpixelSegmentation_VariableSandM /// /// Magic SLIC - no parameters /// /// Performs k mean segmentation. It is fast because it looks locally, not /// over the entire image. /// This function picks the maximum value of color distance as compact factor /// M and maximum pixel distance as grid step size S from each cluster (13 April 2011). /// So no need to input a constant value of M and S. There are two clear /// advantages: /// /// [1] The algorithm now better handles both textured and non-textured regions /// [2] There is not need to set any parameters!!! /// /// SLICO (or SLIC Zero) dynamically varies only the compactness factor S, /// not the step size S. //=========================================================================== void SLIC::PerformSuperpixelSegmentation_VariableSandM( vector<double>& kseedsl, vector<double>& kseedsa, vector<double>& kseedsb, vector<double>& kseedsx, vector<double>& kseedsy, int* klabels, const int& STEP, const int& NUMITR) { int sz = m_width*m_height; const int numk = kseedsl.size(); //double cumerr(99999.9); int numitr(0); //---------------- int offset = STEP; if(STEP < 10) offset = STEP*1.5; //---------------- vector<double> sigmal(numk, 0); vector<double> sigmaa(numk, 0); vector<double> sigmab(numk, 0); vector<double> sigmax(numk, 0); vector<double> sigmay(numk, 0); vector<int> clustersize(numk, 0); vector<double> inv(numk, 0);//to store 1/clustersize[k] values vector<double> distxy(sz, DBL_MAX); vector<double> distlab(sz, DBL_MAX); vector<double> distvec(sz, DBL_MAX); vector<double> maxlab(numk, 10*10);//THIS IS THE VARIABLE VALUE OF M, just start with 10 vector<double> maxxy(numk, STEP*STEP);//THIS IS THE VARIABLE VALUE OF M, just start with 10 double invxywt = 1.0/(STEP*STEP);//NOTE: this is different from how usual SLIC/LKM works while( numitr < NUMITR ) { //------ //cumerr = 0; numitr++; //------ distvec.assign(sz, DBL_MAX); for( int n = 0; n < numk; n++ ) { int y1 = max(0, static_cast<int>(kseedsy[n])-offset); int y2 = min(m_height, static_cast<int>(kseedsy[n])+offset); int x1 = max(0, static_cast<int>(kseedsx[n])-offset); int x2 = min(m_width, static_cast<int>(kseedsx[n])+offset); for( int y = y1; y < y2; y++ ) { for( int x = x1; x < x2; x++ ) { int i = y*m_width + x; _ASSERT( y < m_height && x < m_width && y >= 0 && x >= 0 ); double l = m_lvec[i]; double a = m_avec[i]; double b = m_bvec[i]; distlab[i] = (l - kseedsl[n])*(l - kseedsl[n]) + (a - kseedsa[n])*(a - kseedsa[n]) + (b - kseedsb[n])*(b - kseedsb[n]); distxy[i] = (x - kseedsx[n])*(x - kseedsx[n]) + (y - kseedsy[n])*(y - kseedsy[n]); //------------------------------------------------------------------------ double dist = distlab[i]/maxlab[n] + distxy[i]*invxywt;//only varying m, prettier superpixels //double dist = distlab[i]/maxlab[n] + distxy[i]/maxxy[n];//varying both m and S //------------------------------------------------------------------------ if( dist < distvec[i] ) { distvec[i] = dist; klabels[i] = n; } } } } //----------------------------------------------------------------- // Assign the max color distance for a cluster //----------------------------------------------------------------- if(0 == numitr) { maxlab.assign(numk,1); maxxy.assign(numk,1); } {for( int i = 0; i < sz; i++ ) { if(maxlab[klabels[i]] < distlab[i]) maxlab[klabels[i]] = distlab[i]; if(maxxy[klabels[i]] < distxy[i]) maxxy[klabels[i]] = distxy[i]; }} //----------------------------------------------------------------- // Recalculate the centroid and store in the seed values //----------------------------------------------------------------- sigmal.assign(numk, 0); sigmaa.assign(numk, 0); sigmab.assign(numk, 0); sigmax.assign(numk, 0); sigmay.assign(numk, 0); clustersize.assign(numk, 0); for( int j = 0; j < sz; j++ ) { int temp = klabels[j]; _ASSERT(klabels[j] >= 0); sigmal[klabels[j]] += m_lvec[j]; sigmaa[klabels[j]] += m_avec[j]; sigmab[klabels[j]] += m_bvec[j]; sigmax[klabels[j]] += (j%m_width); sigmay[klabels[j]] += (j/m_width); clustersize[klabels[j]]++; } {for( int k = 0; k < numk; k++ ) { //_ASSERT(clustersize[k] > 0); if( clustersize[k] <= 0 ) clustersize[k] = 1; inv[k] = 1.0/double(clustersize[k]);//computing inverse now to multiply, than divide later }} {for( int k = 0; k < numk; k++ ) { kseedsl[k] = sigmal[k]*inv[k]; kseedsa[k] = sigmaa[k]*inv[k]; kseedsb[k] = sigmab[k]*inv[k]; kseedsx[k] = sigmax[k]*inv[k]; kseedsy[k] = sigmay[k]*inv[k]; }} } }
int main() { std::mt19937 rng; rng.seed(std::random_device()()); std::uniform_int_distribution<std::mt19937_64::result_type> distxy(-25, 25); std::uniform_int_distribution<std::mt19937_64::result_type> distz(1, DEPTH); for (int i = 0; i < NUM_STARS; i++) { stars[i].x = distxy(rng); stars[i].y = distxy(rng); stars[i].z = distz(rng); } sf::RenderWindow window(sf::VideoMode(WINDOW_WIDTH, WINDOW_HEIGHT), "SFML Starfield"); window.setFramerateLimit(FRAMES_PER_SECOND); sf::Texture texture; if (!texture.loadFromFile("res/sprites/star_flare_default.png")) { return 1; } sf::Sprite sprite; sprite.setTexture(texture); sprite.setOrigin(256, 256); window.clear(sf::Color::Black); window.display(); while (window.isOpen()) { sf::Event event; while (window.pollEvent(event)) { if (event.type == sf::Event::Closed) { window.close(); } } window.clear(sf::Color::Black); for (int i = 0; i < NUM_STARS; i++) { stars[i].z -= 0.1; if (stars[i].z <= 0) { stars[i].x = distxy(rng); stars[i].y = distxy(rng); stars[i].z = DEPTH; } float k = 256 / stars[i].z; float xPos = (stars[i].x * k) + WINDOW_HALF_WIDTH; float yPos = (stars[i].y * k) + WINDOW_HALF_HEIGHT; if (xPos >= 0 && xPos < WINDOW_WIDTH && yPos >= 0 && yPos < WINDOW_HEIGHT) { sprite.setPosition(sf::Vector2f(xPos, yPos)); sprite.setScale(sf::Vector2f((float)(1 - stars[i].z / DEPTH) * .03, (float)(1 - stars[i].z / DEPTH) * .03)); window.draw(sprite); } } window.display(); } return 0; }