boostorg / histogram

Fast multi-dimensional generalized histogram with convenient interface for C++14
Boost Software License 1.0
316 stars 70 forks source link

Accessing items in bins #197

Closed nuhash closed 5 years ago

nuhash commented 5 years ago

I'm creating histograms of colours within a patch of an image. I am using a 3D histogram (each axis is a colour channel) and I want to find the colours inside the most populated bin.

I haven't been able to find any way to do this. But since you can rebin, I assume there must be away to do it.

The alternative is that I take the bounds of the most populated bin and see which of the pixels fall within in it.

HDembinski commented 5 years ago

Hi, you can use the indexed range generator. See https://www.boost.org/doc/libs/develop/libs/histogram/doc/html/histogram/guide.html#histogram.guide.fill_a_histogram_and_access_cell

#include <boost/histogram.hpp>

using namespace boost::histogram;
using namespace boost::histogram::literals;

int main() {
    auto h = make_histogram(
        axis::integer<>(0, 255, "r"),
        axis::integer<>(0, 255, "g"),
        axis::integer<>(0, 255, "b")
    );

    // fill ...

    // find colors for max element
    double max = 0;
    struct rgb_t { int r, g, b; };
    rgb_t color = {-1, -1, -1};
    for (auto&& x : indexed(h)) {
        if (*x < max) continue;
        max = *x;
        color = { x.bin(0_c), x.bin(1_c), x.bin(2_c) };
    }
    // color contains now the rgb values for the bin with the highest count
}

It would be nice to use std::max_element here, but that doesn't work with the current version of the library, since std::max_element requires forward iterators, while indexed returns input iterators. There is an open issue to fix that, see #198

HDembinski commented 5 years ago

This seems like a useful item for the "Getting Started" section to showcase indexed. Thank you for reporting!

nuhash commented 5 years ago

Thank you for that. I was using bins which spanned across more than one colour but this would actually work better.

However, if someone was using bins which span multiple values then how would they find the entries? I imagine this might be something of interest to quite a few usages of histograms.

HDembinski commented 5 years ago

However, if someone was using bins which span multiple values then how would they find the entries? I imagine this might be something of interest to quite a few usages of histograms.

Could you please send a minimal code example? I don't know what you mean.

nuhash commented 5 years ago
auto h = make_histogram(axis::regular<>(nBins,0.0,1.0,"R"),axis::regular<>(nBins,0.0,1.0,"G"),axis::regular<>(nBins,0.0,1.0,"B"));`
//fill
int modeCount = -1;
int modeIndex0;
int modeIndex1;
int modeIndex2;

for(auto item : indexed(h)){
    int c = item.bin();
    if(*item>modeCount)
    {
         modeCount = *item;
         modeIndex0 = item.bin(0_c);
         modeIndex1 = item.bin(1_c);
         modeIndex2 = item.bin(2_c);
     }
}

auto itemsInModeBin = h.ItemsInBin(modeIndex0,modeIndex1,modeIndex2);

ColorStruct meanColorInModeBin
for(auto item : itemsInModeBin)
{
//compute average of colors in bin
}

Hope this helps you understand my question

HDembinski commented 5 years ago

I think there is a misunderstanding then. To access the cell for modeIndex0, modeIndex1, modeIndex2 , you use histogram::at. In a standard histogram, the cell just contains a counter. Whenever you fill the histogram, it looks up the cell and increments the counter. The counter is just a number, so there is nothing to iterate over in the last loop of your example.

You can - however - make a generalized histogram, where you pass something to the cell during filling and where you can then do something with those cell contents. Please read https://www.boost.org/doc/libs/develop/libs/histogram/doc/html/histogram/guide.html#histogram.guide.expert.user_defined_accumulators The last example shows how to make a custom accumulator.

HDembinski commented 5 years ago

With the current develop branch, you can now do

#include <boost/histogram.hpp>
#include <algorithm>
#include <iostream>

using namespace boost::histogram;
using namespace boost::histogram::literals;

int main() {
    auto h = make_histogram(
        axis::regular<>(100, 0, 1, "r"),
        axis::regular<>(100, 0, 1, "g"),
        axis::regular<>(100, 0, 1, "b")
    );

    // fill ...

    // find colors for max element
    auto ind = indexed(h);
    auto max_it = std::max_element(ind.begin(), ind.end());
    // access colors
    std::cout << "count=" << **max_it 
              << ", r=" << max_it->bin(0)
              << ", g=" << max_it->bin(1)
              << ", b=" << max_it->bin(2) << std::endl;
}
HDembinski commented 5 years ago

Since there is no response, I am closing this.