Skip to content
Snippets Groups Projects
vmap.cpp 16.5 KiB
Newer Older
even's avatar
even committed
#include <iostream>
even's avatar
even committed
#include "vmap.h"
#include "math.h"

using namespace std;


const int VMap::TYPE_SOBEL_3X3 = 0;
const int VMap::TYPE_SOBEL_5X5 = 1;
const int VMap::TYPE_TOP_HAT = 2;
const int VMap::TYPE_BLACK_HAT = 3;
const int VMap::TYPE_MORPHO = 4;
even's avatar
even committed
const int VMap::TYPE_FULL_TOP_HAT = 5;
const int VMap::TYPE_FULL_BLACK_HAT = 6;
const int VMap::TYPE_FULL_MORPHO = 7;
even's avatar
even committed

const int VMap::NEAR_SQ_ANGLE = 80;  // 80% (roughly 25 degrees)
const int VMap::DEFAULT_GRADIENT_THRESHOLD = 30;


VMap::VMap (int width, int height, int *data, int type)
{
even's avatar
even committed
  gradientThreshold = DEFAULT_GRADIENT_THRESHOLD;
even's avatar
even committed
  gmagThreshold = gradientThreshold;
even's avatar
even committed
  this->width = width;
  this->height = height;
even's avatar
even committed
  this->gtype = type;
even's avatar
even committed
  imap = new int[width * height];
  if (type == TYPE_TOP_HAT)
  {
    Strucel se (Strucel::TYPE_PLUS_3X3);
    se.tophatGradient (imap, data, width, height);
even's avatar
even committed
    buildSobel5x5Map (data);
  }
  else if (type == TYPE_FULL_TOP_HAT)
  {
    Strucel se (Strucel::TYPE_PLUS_3X3);
    se.tophatGradient (imap, data, width, height);
    int *jmap = new int[width * height];
    Strucel seh (Strucel::TYPE_HOR);
    seh.tophatGradient (jmap, data, width, height);
    int *kmap = new int[width * height];
    Strucel sev (Strucel::TYPE_VER);
    sev.tophatGradient (kmap, data, width, height);
    map = new Vr2i[width * height];
    Vr2i *tmpmap = map;
    for (int i = 0; i < width * height; i ++)
    {
      tmpmap->set (jmap[i], kmap[i]);
      tmpmap ++;
    }
even's avatar
even committed
  }
  else if (type == TYPE_BLACK_HAT)
  {
    Strucel se (Strucel::TYPE_PLUS_3X3);
    se.blackhatGradient (imap, data, width, height);
even's avatar
even committed
    buildSobel5x5Map (data);
  }
  else if (type == TYPE_FULL_BLACK_HAT)
  {
    Strucel se (Strucel::TYPE_PLUS_3X3);
    se.blackhatGradient (imap, data, width, height);
    int *jmap = new int[width * height];
    Strucel seh (Strucel::TYPE_HOR);
    seh.blackhatGradient (jmap, data, width, height);
    int *kmap = new int[width * height];
    Strucel sev (Strucel::TYPE_VER);
    sev.blackhatGradient (kmap, data, width, height);
    map = new Vr2i[width * height];
    Vr2i *tmpmap = map;
    for (int i = 0; i < width * height; i ++)
    {
      tmpmap->set (jmap[i], kmap[i]);
      tmpmap ++;
    }
even's avatar
even committed
  }
  else if (type == TYPE_MORPHO)
  {
    Strucel se (Strucel::TYPE_PLUS_3X3);
    se.morphoGradient (imap, data, width, height);
even's avatar
even committed
    buildSobel5x5Map (data);
even's avatar
even committed
  }
even's avatar
even committed
  else if (type == TYPE_FULL_MORPHO)
  {
    Strucel se (Strucel::TYPE_PLUS_3X3);
    se.morphoGradient (imap, data, width, height);
    int *jmap = new int[width * height];
    Strucel seh (Strucel::TYPE_HOR);
    seh.morphoGradient (jmap, data, width, height);
    int *kmap = new int[width * height];
    Strucel sev (Strucel::TYPE_VER);
    sev.morphoGradient (kmap, data, width, height);
    map = new Vr2i[width * height];
    Vr2i *tmpmap = map;
    for (int i = 0; i < width * height; i ++)
    {
      tmpmap->set (jmap[i], kmap[i]);
      tmpmap ++;
    }
  }
  else if (type == TYPE_SOBEL_5X5)
  {
    buildSobel5x5Map (data);
even's avatar
even committed
    for (int i = 0; i < width * height; i++)
      imap[i] = (int) sqrt (map[i].norm2 ());
even's avatar
even committed
    gmagThreshold *= gradientThreshold;
even's avatar
even committed
  }
  else // type == TYPE_SOBEL_3X3
  {
    buildGradientMap (data);
    for (int i = 0; i < width * height; i++)
      imap[i] = (int) sqrt (map[i].norm2 ());
even's avatar
even committed
    gmagThreshold *= gradientThreshold;
even's avatar
even committed
  mask = new bool[width * height];
  for (int i = 0; i < width * height; i++) mask[i] = false;
  masking = false;
  angleThreshold = NEAR_SQ_ANGLE;
  orientedGradient = false;
}


VMap::VMap (int width, int height, int **data, int type)
{
even's avatar
even committed
  gradientThreshold = DEFAULT_GRADIENT_THRESHOLD;
even's avatar
even committed
  gmagThreshold = gradientThreshold;
even's avatar
even committed
  this->width = width;
  this->height = height;
even's avatar
even committed
  this->gtype = type;
even's avatar
even committed
  imap = new int[width * height];
  if (type == TYPE_TOP_HAT)
  {
    Strucel se (Strucel::TYPE_PLUS_3X3);
    se.tophatGradient (imap, data, width, height);
even's avatar
even committed
    buildSobel5x5Map (data);
  }
  else if (type == TYPE_FULL_TOP_HAT)
  {
    Strucel se (Strucel::TYPE_PLUS_3X3);
    se.tophatGradient (imap, data, width, height);
    int *jmap = new int[width * height];
    Strucel seh (Strucel::TYPE_HOR);
    seh.tophatGradient (jmap, data, width, height);
    int *kmap = new int[width * height];
    Strucel sev (Strucel::TYPE_VER);
    sev.tophatGradient (kmap, data, width, height);
    map = new Vr2i[width * height];
    Vr2i *tmpmap = map;
    for (int i = 0; i < width * height; i ++)
    {
      tmpmap->set (jmap[i], kmap[i]);
      tmpmap ++;
    }
even's avatar
even committed
  }
  else if (type == TYPE_BLACK_HAT)
  {
    Strucel se (Strucel::TYPE_PLUS_3X3);
    se.blackhatGradient (imap, data, width, height);
even's avatar
even committed
    buildSobel5x5Map (data);
  }
  else if (type == TYPE_FULL_BLACK_HAT)
  {
    Strucel se (Strucel::TYPE_PLUS_3X3);
    se.blackhatGradient (imap, data, width, height);
    int *jmap = new int[width * height];
    Strucel seh (Strucel::TYPE_HOR);
    seh.blackhatGradient (jmap, data, width, height);
    int *kmap = new int[width * height];
    Strucel sev (Strucel::TYPE_VER);
    sev.blackhatGradient (kmap, data, width, height);
    map = new Vr2i[width * height];
    Vr2i *tmpmap = map;
    for (int i = 0; i < width * height; i ++)
    {
      tmpmap->set (jmap[i], kmap[i]);
      tmpmap ++;
    }
even's avatar
even committed
  }
  else if (type == TYPE_MORPHO)
  {
    Strucel se (Strucel::TYPE_PLUS_3X3);
    se.morphoGradient (imap, data, width, height);
even's avatar
even committed
    buildSobel5x5Map (data);
  }
  else if (type == TYPE_FULL_MORPHO)
  {
    Strucel se (Strucel::TYPE_PLUS_3X3);
    se.morphoGradient (imap, data, width, height);
    int *jmap = new int[width * height];
    Strucel seh (Strucel::TYPE_HOR);
    seh.morphoGradient (jmap, data, width, height);
    int *kmap = new int[width * height];
    Strucel sev (Strucel::TYPE_VER);
    sev.morphoGradient (kmap, data, width, height);
    map = new Vr2i[width * height];
    Vr2i *tmpmap = map;
    for (int i = 0; i < width * height; i ++)
    {
      tmpmap->set (jmap[i], kmap[i]);
      tmpmap ++;
    }
even's avatar
even committed
  }
even's avatar
even committed
  else if (type == TYPE_SOBEL_5X5)
  {
    buildSobel5x5Map (data);
even's avatar
even committed
    for (int i = 0; i < width * height; i++)
even's avatar
even committed
      imap[i] = (int) sqrt (map[i].norm2 ());
even's avatar
even committed
    gmagThreshold *= gradientThreshold;
even's avatar
even committed
  }
  else // type == TYPE_SOBEL_3X3
  {
    buildGradientMap (data);
    for (int i = 0; i < width * height; i++)
      imap[i] = (int) sqrt (map[i].norm2 ());
even's avatar
even committed
    gmagThreshold *= gradientThreshold;
even's avatar
even committed
  mask = new bool[width * height];
  for (int i = 0; i < width * height; i++) mask[i] = false;
  masking = false;
  angleThreshold = NEAR_SQ_ANGLE;
  orientedGradient = false;
}


VMap::~VMap ()
{
  delete map;
  delete imap;
  delete mask;
}


void VMap::buildGradientMap (int *data)
{
  map = new Vr2i[width * height];
  Vr2i *gm = map;

  for (int j = 0; j < width; j++)
  {
    gm->set (0, 0);
    gm++;
  }
  for (int i = 1; i < height - 1; i++)
  {
    gm->set (0, 0);
    gm++;
    for (int j = 1; j < width - 1; j++)
    {
      gm->set (data[(i - 1) * height + j + 1]
               + 2 * data[i * height + j + 1]
               + data[(i + 1) * height + j + 1]
               - data[(i - 1) * height + j - 1]
               - 2 * data[i * height + j - 1]
               - data[(i + 1) * height + j - 1],
               data[(i + 1) * height + j - 1]
               + 2 * data[(i + 1) * height + j]
               + data[(i + 1) * height + j + 1]
               - data[(i - 1) * height + j - 1]
               - 2 * data[(i - 1) * height + j]
               - data[(i - 1) * height + j + 1]);
      gm++;
    }
    gm->set (0, 0);
    gm++;
  }
  for (int j = 0; j < width; j++)
  {
    gm->set (0, 0);
    gm++;
  }
}


void VMap::buildGradientMap (int **data)
{
  map = new Vr2i[width * height];
  Vr2i *gm = map;

  for (int j = 0; j < width; j++)
  {
    gm->set (0, 0);
    gm++;
  }
  for (int i = 1; i < height - 1; i++)
  {
    gm->set (0, 0);
    gm++;
    for (int j = 1; j < width - 1; j++)
    {
      gm->set (data[i-1][j+1] + 2 * data[i][j+1] + data[i+1][j+1]
               - data[i-1][j-1] - 2 * data[i][j-1] - data[i+1][j-1],
               data[i+1][j-1] + 2 * data[i+1][j] + data[i+1][j+1]
               - data[i-1][j-1] - 2 * data[i-1][j] - data[i-1][j+1]);
      gm++;
    }
    gm->set (0, 0);
    gm++;
  }
  for (int j = 0; j < width; j++)
  {
    gm->set (0, 0);
    gm++;
  }
}


void VMap::buildSobel5x5Map (int *data)
{
  map = new Vr2i[width * height];
  Vr2i *gm = map;

  for (int j = 0; j < 2 * width; j++)
  {
    gm->set (0, 0);
    gm++;
  }
  for (int i = 2; i < height - 2; i++)
  {
    gm->set (0, 0);
    gm++;
    gm->set (0, 0);
    gm++;
    for (int j = 2; j < width - 2; j++)
    {
      gm->set (5 * data[(i - 2) * height + j + 2]
                 + 8 * data[(i - 1) * height + j + 2]
                 + 10 * data[i * height + j + 2]
                 + 8 * data[(i + 1) * height + j + 2]
                 + 5 * data[(i + 2) * height + j + 2]
               + 4 * data[(i - 2) * height + j + 1]
                 + 10 * data[(i - 1) * height + j + 1]
                 + 20 * data[i * height + j + 1]
                 + 10 * data[(i + 1) * height + j + 1]
                 + 4 * data[(i + 2) * height + j + 1]
               - 4 * data[(i - 2) * height + j - 1]
                 - 10 * data[(i - 1) * height + j - 1]
                 - 20 * data[i * height + j - 1]
                 - 10 * data[(i + 1) * height + j - 1]
                 - 4 * data[(i + 2) * height + j - 1] 
               - 5 * data[(i - 2) * height + j - 2]
                 - 8 * data[(i - 1) * height + j - 2]
                 - 10 * data[i * height + j - 2]
                 - 8 * data[(i + 1) * height + j - 2]
                 - 5 * data[(i + 2) * height + j - 2],
               5 * data[(i + 2) * height + j - 2]
                 + 8 * data[(i + 2) * height + j - 1]
                 + 10 * data[(i + 2) * height + j]
                 + 8 * data[(i + 2) * height + j + 1]
                 + 5 * data[(i + 2) * height + j + 2]
               + 4 * data[(i + 1) * height + j - 2]
                 + 10 * data[(i + 1) * height + j - 1]
                 + 20 * data[(i + 1) * height + j]
                 + 10 * data[(i + 1) * height + j + 1]
                 + 4 * data[(i + 1) * height + j + 2]
               - 4 * data[(i - 1) * height + j - 2]
                 - 10 * data[(i - 1) * height + j - 1]
                 - 20 * data[(i - 1) * height + j]
                 - 10 * data[(i - 1) * height + j + 1]
                 - 4 * data[(i - 1) * height + j + 2]
               - 5 * data[(i - 2) * height + j - 2]
                 - 8 * data[(i - 2) * height + j - 1]
                 - 10 * data[(i - 2) * height + j]
                 - 8 * data[(i - 2) * height + j + 1]
                 - 5 * data[(i - 2) * height + j + 2]);
      gm++;
    }
    gm->set (0, 0);
    gm++;
    gm->set (0, 0);
    gm++;
  }
  for (int j = 0; j < 2 * width; j++)
  {
    gm->set (0, 0);
    gm++;
  }
}


void VMap::buildSobel5x5Map (int **data)
{
  map = new Vr2i[width * height];
  Vr2i *gm = map;

  for (int j = 0; j < 2 * width; j++)
  {
    gm->set (0, 0);
    gm++;
  }
  for (int i = 2; i < height - 2; i++)
  {
    gm->set (0, 0);
    gm++;
    gm->set (0, 0);
    gm++;
    for (int j = 2; j < width - 2; j++)
    {
      gm->set (
        5 * data[i-2][j+2] + 8 * data[i-1][j+2] + 10 * data[i][j+2]
                           + 8 * data[i+1][j+2] + 5 * data[i+2][j+2]
        + 4 * data[i-2][j+1] + 10 * data[i-1][j+1] + 20 * data[i][j+1]
                           + 10 * data[i+1][j+1] + 4 * data[i+2][j+1]
        - 4 * data[i-2][j-1] - 10 * data[i-1][j-1] - 20 * data[i][j-1]
                           - 10 * data[i+1][j-1] - 4 * data[i+2][j-1]
        - 5 * data[i-2][j-2] - 8 * data[i-1][j-2] - 10 * data[i][j-2]
                           - 8 * data[i+1][j-2] - 5 * data[i+2][j-2],
        5 * data[i+2][j-2] + 8 * data[i+2][j-1] + 10 * data[i+2][j]
                           + 8 * data[i+2][j+1] + 5 * data[i+2][j+2]
        + 4 * data[i+1][j-2] + 10 * data[i+1][j-1] + 20 * data[i+1][j]
                           + 10 * data[i+1][j+1] + 4 * data[i+1][j+2]
        - 4 * data[i-1][j-2] - 10 * data[i-1][j-1] - 20 * data[i-1][j]
                           - 10 * data[i-1][j+1] - 4 * data[i-1][j+2]
        - 5 * data[i-2][j-2] - 8 * data[i-2][j-1] - 10 * data[i-2][j]
                           - 8 * data[i-2][j+1] - 5 * data[i-2][j+2]);
      gm++;
    }
    gm->set (0, 0);
    gm++;
    gm->set (0, 0);
    gm++;
  }
  for (int j = 0; j < 2 * width; j++)
  {
    gm->set (0, 0);
    gm++;
  }
}


int VMap::sqNorm (int i, int j) const
{
  return (map[j * width + i].norm2 ());
}


int VMap::sqNorm (Pt2i p) const
{
  return (map[p.y () * width + p.x ()].norm2 ());
}


int VMap::largestIn (const vector<Pt2i> &pix) const
{
  if (pix.empty ()) return (-1);

  int imax = -1;
  vector<Pt2i>::const_iterator pt = pix.begin ();
  int gmax = imap[pt->y() * width + pt->x()];
even's avatar
even committed
  if (gmax < gmagThreshold) gmax = gmagThreshold;
even's avatar
even committed

  int i = 0;
  while (pt != pix.end ())
  {
    int g = imap[pt->y() * width + pt->x()];
    if (g > gmax)
    {
      gmax = g;
      imax = i;
    }
    pt ++;
    i ++;
  }
  return (imax == i - 1 ? -1 : imax);
}


int VMap::keepFreeElementsIn (const vector<Pt2i> &pix, int n, int *ind) const
{
  int i = 0;
  while (i < n)
  {
    if (mask[pix[ind[i]].y () * width + pix[ind[i]].x ()]) ind[i] = ind[--n];
    else i++;
  }
  return (n);
}


int VMap::keepOrientedElementsIn (const vector<Pt2i> &pix,
                                       const Vr2i &ref, int n, int *ind) const
{
  int vx = ref.x ();
  int vy = ref.y ();
  int i = 0;
  while (i < n)
  {
    Vr2i gr = map[pix[ind[i]].y () * width + pix[ind[i]].x ()];
    if (vx * gr.x () + vy * gr.y () <= 0) ind[i] = ind[--n];
    else i++;
  }
  return (n);
}


int VMap::keepDirectedElementsIn (const vector<Pt2i> &pix,
                                  const Vr2i &ref, int n, int *ind) const
{
  int vx = ref.x ();
  int vy = ref.y ();
  long vn2 = vx * vx + vy * vy;

  int i = 0;
  while (i < n)
  {
    Pt2i p = pix.at (ind[i]);
    Vr2i gr = map[p.y () * width + p.x ()];
    long gx = gr.x ();
    long gy = gr.y ();
    if ((vx * vx * gx * gx + vy * vy * gy * gy + 2 * vx * vy * gx * gy) * 100
        < vn2 * (gx * gx + gy * gy) * angleThreshold)
      ind[i] = ind[--n];
    else i++;
  }
  return (n);
}


even's avatar
even committed
int VMap::localMax (int *lmax, const vector<Pt2i> &pix) const
even's avatar
even committed
{
  // Builds the gradient norm signal
  int n = (int) pix.size ();
  int *gn = new int[n];
  int i = 0;
  vector<Pt2i>::const_iterator it = pix.begin ();
even's avatar
even committed
  while (it != pix.end ()) gn[i++] = magn (*it++);
even's avatar
even committed

  // Gets the local maxima
  int count = searchLocalMax (lmax, n, gn);

  // Prunes the already selected candidates
even's avatar
even committed
  count = keepFreeElementsIn (pix, count, lmax);

  // Sorts candidates by gradient magnitude
  sortMax (lmax, count, gn);

  delete gn;
  return count;
}


int VMap::localMax (int *lmax, const vector<Pt2i> &pix, const Vr2i &gref) const
{
  // Builds the gradient norm signal
  int n = (int) pix.size ();
  int *gn = new int[n];
  int i = 0;
  vector<Pt2i>::const_iterator it = pix.begin ();
  while (it != pix.end ()) gn[i++] = magn (*it++);

  // Gets the local maxima
  int count = searchLocalMax (lmax, n, gn);
even's avatar
even committed

  // Prunes the candidates with opposite gradient
  if (orientedGradient)
    count = keepOrientedElementsIn (pix, gref, count, lmax);

  // Prunes the candidates wrongly oriented
  count = keepDirectedElementsIn (pix, gref, count, lmax);

  // Sorts candidates by gradient magnitude
  sortMax (lmax, count, gn);

  delete gn;
  return count;
}


int VMap::searchLocalMax (int *lmax, int n, int *in) const
{
  int offset = 0;
  int count = 0;
  bool up = true;

  // Gets the first distinct value from start
  while (offset < n - 1 && in[offset] == in[0])
  {
    if (in[offset] - in[offset + 1] < 0)
    {
      up = true;
      break;
    }
    if (in[offset] - in[offset + 1] > 0)
    {
      up = false;
      break;
    }
    offset++;
  }

  for(int i = offset; i < n - 1; i++)
  {
    if (up)
    {
      if ((in[i + 1] - in[i]) < 0)
      {
        up = false;
        int k = i;
        while (in[k - 1] == in[i]) k--;
        lmax[count++] = k + (i - k) / 2;
      }
    }
    else
      if (in[i + 1] - in[i] > 0) up = true;
  }
  return count;
}


void VMap::sortMax (int *lmax, int n, int *val) const
{
  for (int i = 1; i < n; i ++)
  {
    int j = i, tmp = lmax[i];
    bool on = true;
    while (on && j > 0)
    {
      if (val[tmp] > val[lmax[j-1]])
      {
        lmax[j] = lmax[j-1];
        j --;
      }
      else on = false;
    }
    lmax[j] = tmp;
  }
}


void VMap::clearMask ()
{
  for (int i = 0; i < width * height; i++) mask[i] = false;
}


void VMap::setMask (const vector<Pt2i> &pts)
{
  vector<Pt2i>::const_iterator it = pts.begin ();
  while (it != pts.end ())
  {
    Pt2i pt = *it++;
    mask[pt.y () * width + pt.x ()] = true;
  }
}