69 uint8 inBorderWidth = 0) :
71 intensities_(inIntensityArrayPtr)
73 if (xcds_->shape() != intensities_->shape())
75 THROW_INVALID_ARGUMENT_ERROR(
"input xcd and intensity arrays must be the same shape.");
78 shape_ = xcds_->shape();
81 for (
uint32 row = 0; row < shape_.rows; ++row)
83 for (
uint32 col = 0; col < shape_.cols; ++col)
85 if (xcds_->operator()(row, col))
87 const Pixel<dtype> thePixel(row, col, intensities_->operator()(row, col));
88 xcdsVec_.push_back(thePixel);
95 for (
uint8 i = 0; i < inBorderWidth; ++i)
109 return static_cast<uint32>(clusters_.size());
122 return clusters_[inIndex];
135 if (inIndex >= clusters_.size())
139 return clusters_[inIndex];
150 return clusters_.cbegin();
161 return clusters_.cend();
168 std::vector<Pixel<dtype>> xcdsVec_{};
172 std::vector<Cluster<dtype>> clusters_{};
183 Pixel<dtype> makePixel(
int32 inRow,
int32 inCol)
noexcept
187 const uint32 row = std::min(
static_cast<uint32>(std::max<int32>(inRow, 0)), shape_.rows - 1);
188 const uint32 col = std::min(
static_cast<uint32>(std::max<int32>(inCol, 0)), shape_.cols - 1);
189 const dtype intensity = intensities_->operator()(row, col);
191 return Pixel<dtype>(row, col, intensity);
202 void findNeighbors(
const Pixel<dtype>& inPixel, std::set<Pixel<dtype>>& outNeighbors)
207 const auto row =
static_cast<int32>(inPixel.row);
208 const auto col =
static_cast<int32>(inPixel.col);
210 outNeighbors.insert(outNeighbors.end(), makePixel(row - 1, col - 1));
211 outNeighbors.insert(outNeighbors.end(), makePixel(row - 1, col));
212 outNeighbors.insert(outNeighbors.end(), makePixel(row - 1, col + 1));
213 outNeighbors.insert(outNeighbors.end(), makePixel(row, col - 1));
214 outNeighbors.insert(outNeighbors.end(), makePixel(row, col + 1));
215 outNeighbors.insert(outNeighbors.end(), makePixel(row + 1, col - 1));
216 outNeighbors.insert(outNeighbors.end(), makePixel(row + 1, col));
217 outNeighbors.insert(outNeighbors.end(), makePixel(row + 1, col + 1));
229 void findNeighborNotXcds(
const Pixel<dtype>& inPixel, std::vector<Pixel<dtype>>& outNeighbors)
231 std::set<Pixel<dtype>> neighbors;
232 findNeighbors(inPixel, neighbors);
235 for (
auto& pixel : neighbors)
237 if (!xcds_->operator()(pixel.row, pixel.col))
239 outNeighbors.push_back(pixel);
253 void findNeighborXcds(
const Pixel<dtype>& inPixel, std::vector<uint32>& outNeighbors)
255 std::set<Pixel<dtype>> neighbors;
256 findNeighbors(inPixel, neighbors);
257 std::vector<Pixel<dtype>> neighborXcds;
260 for (
auto& pixel : neighbors)
262 if (xcds_->operator()(pixel.row, pixel.col))
264 neighborXcds.push_back(pixel);
269 for (
auto& pixel : neighborXcds)
271 auto theExceedanceIter = std::find(xcdsVec_.begin(), xcdsVec_.end(), pixel);
272 outNeighbors.push_back(
static_cast<uint32>(theExceedanceIter - xcdsVec_.begin()));
280 void runClusterMaker()
284 for (
auto& currentPixel : xcdsVec_)
287 if (currentPixel.clusterId == -1)
289 Cluster<dtype> newCluster(clusterId);
290 currentPixel.clusterId = clusterId;
291 newCluster.addPixel(currentPixel);
294 std::vector<uint32> neighborIds;
295 findNeighborXcds(currentPixel, neighborIds);
296 if (neighborIds.empty())
298 clusters_.push_back(newCluster);
304 for (
uint32 neighborsIdx = 0; neighborsIdx < neighborIds.size(); ++neighborsIdx)
306 Pixel<dtype>& currentNeighborPixel = xcdsVec_[neighborIds[neighborsIdx]];
309 std::vector<uint32> newNeighborIds;
310 findNeighborXcds(currentNeighborPixel, newNeighborIds);
313 for (
auto newNeighborId : newNeighborIds)
316 if (std::find(neighborIds.begin(), neighborIds.end(), newNeighborId) == neighborIds.end())
318 neighborIds.push_back(newNeighborId);
323 if (currentNeighborPixel.clusterId == -1)
325 currentNeighborPixel.clusterId = clusterId;
326 newCluster.addPixel(currentNeighborPixel);
330 clusters_.push_back(std::move(newCluster));
340 void expandClusters()
343 for (
auto& theCluster : clusters_)
346 for (
auto& thePixel : theCluster)
348 std::vector<Pixel<dtype>> neighborsNotXcds;
349 findNeighborNotXcds(thePixel, neighborsNotXcds);
352 for (
auto& newPixel : neighborsNotXcds)
354 if (std::find(theCluster.begin(), theCluster.end(), newPixel) == theCluster.end())
356 theCluster.addPixel(newPixel);