Nahajate se tukaj

Vzporedno procesiranje slik

Namen naloge slikovnega procesiranja je vaja osnovnih komunikacij med paralelnimi bloki. Pokazali bomo, da je mogoče iz robov rekonstruirati originalno sliko. Inverzna operacija je zelo podobna velikem številu znanstvenih problemov, ki se računajo na HPC in rešujejo parcialne diferencialne enačbe z iterativnimi algoritmi, kot so Jacobi ali Gauss-Seidel.

S spleta si prenesite Leno v obliki PGM ter najprej izračunajte robove, ki bodo nekoliko temnejši od stranske slike. Uporabite naslednji filter za določitev slike robu

Nato iz taiste slike rekontruirajte originalno sliko z uporabo operatorja

s tem, da pri prvi iteraciji za old uporabite belo ozadje (255). Ponovite iteracije rekonkstrukcije (1, 10, 100, 1000, ...) in ugotovite ali je možno popolnoma rekonstruirati originalno sliko.

Branje ali pisanje binarnih PGM datotek je enostavno, saj je glava ASCII v par vrsticah, nato pa sledi blok znakovnih podatkov, ki popisujejo sivine (0..255).

Pri paralelizaciji problema razstavite problem na koščke, tako da vsak procesor dobi del slike za obdelavo, ki se potem sestavi v celoto. Poskusite določiti kriterij zaustavitve tako, da opazujete največje spremembe svetlosti med staro in novo rekonstruirano sliko.

Serijska koda

#include
#include
#include

unsigned char *img, *out;
int width, height, *edge, *new, *old;

int read_pgm(const char *filename)
{
  char buf[80];
  FILE *f = fopen(filename, "r");
  fgets(buf, 80, f); assert(buf[0] == 'P' && buf[1] == '5');
  fgets(buf, 80, f); if (buf[0] == '#') fgets(buf, 80, f);
  sscanf(buf, "%d %d", &width, &height);
  fgets(buf, 80, f);// levels=255
  img = malloc(width*height*sizeof(char));
  fread(img, width, height, f);
  fclose(f);
  return 0;
}

void write_pgm(int *img, const char *filename)
{
  int k;
  out = malloc(width*height*sizeof(char));
  FILE *f = fopen(filename, "w");
  for (k = 0; k < width*height; ++k)
    out[k] = img[k];
  fprintf(f, "P5\n# image by HPCFS\n%d %d\n255\n", width, height);
  fwrite(out, width, height, f);
  free(out);
  fclose(f);
}

void detect_edge()
{
  int i, j;
  edge = malloc(width*height*sizeof(int));
  for (i = 0; i < height; i++)
    for (j = 0; j < width; ++j)
      {
        if (i == 0 || i == height-1 || j == 0 || j == width-1)
          edge[i*width+j] = 255;
        else
          {
            edge[i*width+j] =((int)img[(i-1)*width+j]
                              +(int)img[(i+1)*width+j]
                              + (int)img[i*width+j-1]
                              + (int)img[i*width+j+1]
                              - 4*(int)img[i*width+j]);
          }
      }
}

void reconstruction(int iters)
{
  int i, j, k;
  new = malloc(width*height*sizeof(int));
  old = malloc(width*height*sizeof(int));
  for (k = 0; k < width*height; ++k)
    old[k] = 255;

  for (k = 0; k < iters; ++k)
    {
      int *tmp;
      #pragma omp parallel for
      for (i = 0; i < height; i++)
        for (j = 0; j < width; ++j)
          {
            if (i == 0 || i == height-1 || j == 0 || j == width-1)
              new[i*width+j] = 255;
            else
              {
                int level =  (old[(i-1)*width+j]+old[(i+1)*width+j]
                              + old[i*width+j-1] + old[i*width+j+1]
                              - edge[i*width+j])/4.0;
                //if (level < 0) level = 0;  if (level > 255) level = 255;
                new[i*width+j] = level;
              }
          }
      tmp = old; old = new;  new = tmp;
    }
}


int main(int argc, char *argv)
{
  read_pgm("lena512.pgm");
  detect_edge();
  write_pgm(edge, "edge.pgm");
  reconstruction(1000);
  write_pgm(old, "out.pgm");
  return 0;
}