Bug de composition sous ICE et Hugin
ICE et Hugin souffrent d’un problème de composition lorsqu’ils doivent traiter des colonnes composées de beaucoup d’image.
Si la lumière n’est pas parfaitement homogène (ce qui est souvent le cas quand on utilise un microscope) et forme un léger gradient, alors ce gradient va être amplifié sur la composition finale, ce qui va donner un résultat désastreux.

ICE: Gradient correction error
© Boris Marmontel
Pour régler ce problème, il faut faire une correction manuelle du gradient sur chaque image.
Pour cela, on prend une photographie “unie” d’un fond blanc, qui nous servira de référence du gradient.

Maintenant l’idée est de coder un programme qui va soustraire ce gradient.
Image im2("light_reference.png");
Image im1("input_image.png");
std::array<Layer64f, 3> data1;
std::array<Layer64f, 3> data2;
std::array<Channel, 3> channels = {
Channel::Red,
Channel::Green,
Channel::Blue
};
for(unsigned i=0; i<3; ++i)
{
Layer64f& l1 = data1[i];
Layer64f& l2 = data2[i];
l1 = extractChannel(im1, channels[i]);
l2 = extractChannel(im2, channels[i]);
double min1 = *std::min_element(l1.data.begin(), l1.data.end());
double max1 = *std::max_element(l1.data.begin(), l1.data.end());
double delta1 = max1 - min1;
auto it1 = l1.data.begin();
auto it2 = l2.data.begin();
double factor = 0.3;
while(it1 != l1.data.end() && it2 != l2.data.end())
{
*it1 -= *it2 * factor;
++it1;
++it2;
}
// normalize
double min = *std::min_element(l1.data.begin(), l1.data.end());
double max = *std::max_element(l1.data.begin(), l1.data.end());
double delta = max - min;
// [0-1]
for(double& x: l1.data)
{
x = (x - min) / delta;
}
// restaure previous histogram state
// [min1-max1]
for(double& x: l1.data)
{
x = min1 + delta1*x;
}
}
Layer64f est juste une image représentée avec des nombres flottants à double précision.
struct Layer64f
{
std::vector<double> data;
od::Sizeu size;
Layer64f() {}
Layer64f(od::Sizeu size):
data(size.wid * size.hei), size(size) {}
void set(od::Posu p, double c) { data[p.x + p.y * size.wid] = c; }
double get(od::Posu p) const { return data[p.x + p.y * size.wid]; }
};
Une fois les layers calculés, on recompose simplement l’image.
Voici une correction de luminosité avec factor = 0.6 puis factor = 0.3

Left: input image, right: light corrected with factor = 0.6

Left: input image, right: light corrected with factor = 0.3
Comme on peut le voir, avec 0.6 la correction est trop forte et le logiciel de panorama aura un bug similaire mais cette fois avec la partie trop claire en bas. Avec la correction en 0.3 le panorama sera parfaitement uniforme.


0.6 0.3
La valeur idéale du coefficient de correction dépend de la hauteur en pixels de la colonne. Avant de faire un panorama complet, il est donc conseillé d’essayer différentes valeurs sur une seule colonne pour vérifier que tout va bien.