SegmentList WaterShedDecomposer::watershed(ImageGray const & gradient, ImageColor const & image) const { SegmentList segments; std::unique_ptr<int[]> labels(new int[image.area()]); for (int i=0; i<image.area(); ++i) labels[i] = -1; int offsets[]{-image.width(), -1, 1, image.width()}; QList<GradPixelRef> queue; for (int i=0; i<gradient.area(); ++i) { queue << GradPixelRef{gradient.at(i).l, i}; } std::sort(queue.begin(), queue.end(), lessThan); int label; int lastLabel = -1; int i, j; QList<int> neighLbls; Pixel * pixel; Segment * segment; foreach (GradPixelRef const & gradPix, queue) { i = gradPix.index; pixel = new Pixel(Position(i%image.width(), i/image.width()), image.at(i)); // gather neighbours neighLbls.clear(); for (int o=0; o<4; ++o) { j = i + offsets[o]; if (image.areNeighbours(i, j) && labels[j] > -1 && !neighLbls.contains(labels[j])) { neighLbls << labels[j]; } } // treat pixel according to neighbour count switch (neighLbls.size()) { case 0: // new marker labels[i] = ++lastLabel; segment = new Segment(); segment->addPixel(pixel); segments << segment; break; case 1: // add to basin label = neighLbls.first(); labels[i] = label; segments.at(label)->addPixel(pixel); break; default: // new watershed // add pixel the segment of the nearest neighbour in color double distMin = std::numeric_limits<double>::max(); double dist; int jMin = 0; for (int o=0; o<4; ++o) { j = i + offsets[o]; if (image.areNeighbours(i, j) && labels[j] > -1) { dist = (image.at(i)-image.at(j)).magnitudeSquared(); if (dist < distMin) { distMin = dist; jMin = j; } } } labels[i] = labels[jMin]; segments.at(labels[jMin])->addPixel(pixel); // beneighbour the segments for (int k=0; k<neighLbls.count()-1; ++k) { for (int l=k+1; l<neighLbls.count(); ++l) { segments.at(neighLbls.at(k))->addNeighbour(segments.at(neighLbls.at(l))); segments.at(neighLbls.at(l))->addNeighbour(segments.at(neighLbls.at(k))); } } break; } }