Skip to content
Snippets Groups Projects
edge_detection.jn 6.35 KiB
Newer Older
  • Learn to ignore specific revisions
  • Aaron Councilman's avatar
    Aaron Councilman committed
    fn gaussian_smoothing<n, m, gs : usize>(
      input: f32[n, m],
      filter: f32[gs, gs],
    ) -> f32[n, m] {
      let result : f32[n, m];
    
      // Define the gaussian radius as half the gaussian size
      const gr = gs / 2;
    
      for row = 0 to n {
        for col = 0 to m {
          let smoothed = 0.0;
    
          for i = 0 to gs {
            for j = 0 to gs {
              let val = input[if row + i < gr               then 0
                              else if row + i - gr > n - 1  then n - 1
                                                            else row + i - gr,
                              if col + j < gr               then 0
                              else if col + j - gr > m - 1  then m - 1
                                                            else col + j - gr];
              smoothed += val * filter[i, j];
            }
          }
    
          result[row, col] = smoothed;
        }
      }
    
      return result;
    }
    
    const MIN_BR : f32 = 0;
    const MAX_BR : f32 = 1;
    
    fn laplacian_estimate<n, m, sz: usize>(
      input: f32[n, m],
      structure: f32[sz, sz],
    ) -> f32[n, m] {
      const r = sz / 2;
    
      let result : f32[n, m];
    
      for row = 0 to n {
        for col = 0 to m {
          // Copy data for dilation filter
          let imageArea : f32[sz, sz];
          for i = 0 to sz {
            for j = 0 to sz {
              imageArea[i, j] = if row + i < r              then MIN_BR
                                else if row + i - r > n - 1 then MIN_BR
                                else if col + j < r         then MIN_BR
                                else if col + j - r > m - 1 then MIN_BR
                                     else input[row + i - r, col + j - r];
            }
          }
    
          // Compute pixel of dilated image
          let dilated = MIN_BR;
          for i = 0 to sz {
            for j = 0 to sz {
              dilated = max!(dilated, imageArea[i, j] * structure[i, j]);
            }
          }
    
          // Data copy for erotion filter
          let imageArea : f32[sz, sz];
          for i = 0 to sz {
            for j = 0 to sz {
              imageArea[i, j] = if row + i < r              then MAX_BR
                                else if row + i - r > n - 1 then MAX_BR
                                else if col + j < r         then MAX_BR
                                else if col + j - r > m - 1 then MAX_BR
                                     else input[row + i - r, col + j - r];
            }
          }
    
          // Compute pixel of eroded image
          let eroded = MAX_BR;
          for i = 0 to sz {
            for j = 0 to sz {
              eroded = min!(eroded, imageArea[i, j] * structure[i, j]);
            }
          }
    
          let laplacian = dilated + eroded - 2 * input[row, col];
          result[row, col] = laplacian;
        }
      }
    
      return result;
    }
    
    fn zero_crossings<n, m, sz: usize>(
      input: f32[n, m],
      structure: f32[sz, sz],
    ) -> f32[n, m] {
      const r = sz / 2;
    
      let result : f32[n, m];
    
      for row = 0 to n {
        for col = 0 to m {
          // Data copy for dilation filter
          let imageArea : f32[sz, sz];
          for i = 0 to sz {
            for j = 0 to sz {
              imageArea[i, j] = if row + i < r              then MIN_BR
                                else if row + i - r > n - 1 then MIN_BR
                                else if col + j < r         then MIN_BR
                                else if col + j - r > m - 1 then MIN_BR
                                else if input[row + i - r, col + j - r] > MIN_BR
                                then MAX_BR
                                else MIN_BR;
            }
          }
    
          // Compute the pixel of dilated image
          let dilated = MIN_BR;
          for i = 0 to sz {
            for j = 0 to sz {
              dilated = max!(dilated, imageArea[i, j] * structure[i, j]);
            }
          }
    
          // Data copy for erotion filter
          let imageArea : f32[sz, sz];
          for i = 0 to sz {
            for j = 0 to sz {
              imageArea[i, j] = if row + i < r              then MAX_BR
                                else if row + i - r > n - 1 then MAX_BR
                                else if col + j < r         then MAX_BR
                                else if col + j - r > m - 1 then MAX_BR
                                else if input[row + i - r, col + j - r] > MIN_BR
                                then MAX_BR
                                else MIN_BR;
            }
          }
    
          // Compute the pixel of eroded image
          let eroded = MAX_BR;
          for i = 0 to sz {
            for j = 0 to sz {
              eroded = min!(eroded, imageArea[i, j] * structure[i, j]);
            }
          }
    
          let sign = dilated - eroded;
          result[row, col] = sign;
        }
      }
    
      return result;
    }
    
    fn gradient<n, m, sb: usize>(
      input: f32[n, m],
      sx: f32[sb, sb],
      sy: f32[sb, sb],
    ) -> f32[n, m] {
      const sbr = sb / 2;
    
      let result : f32[n, m];
    
      for row = 0 to n {
        for col = 0 to m {
    
          let gx = 0;
          let gy = 0;
    
          for i = 0 to sb {
            for j = 0 to sb {
              let val = input[if row + i < sbr              then 0
                              else if row + i - sbr > n - 1 then n - 1
                                                            else row + i - sbr,
                              if col + j < sbr              then 0
                              else if col + j - sbr > m - 1 then m - 1
                                                            else col + j - sbr];
              gx += val * sx[i, j];
              gy += val * sy[i, j];
            }
          }
    
          result[row, col] = sqrt!(gx * gx + gy * gy);
        }
      }
    
      return result;
    }
    
    fn max_gradient<n, m: usize>(gradient: f32[n, m]) -> f32 {
      let max = gradient[0, 0];
    
      for i = 0 to n {
        for j = 0 to m {
          max = max!(max, gradient[i, j]);
        }
      }
    
      return max;
    }
    
    fn reject_zero_crossings<n, m: usize>(
      crossings: f32[n, m],
      gradient: f32[n, m],
      max_gradient: f32,
      theta: f32,
    ) -> f32[n, m] {
      let result : f32[n, m];
    
      for row = 0 to n {
        for col = 0 to m {
          result[row, col] =
            if crossings[row, col] > 0 && gradient[row, col] > theta * max_gradient
            then 1.0
            else 0.0;
        }
      }
    
      return result;
    }
    
    #[entry]
    fn edge_detection<n, m, gs, sz, sb: usize>(
      input: f32[n, m],
      gaussian_filter: f32[gs, gs],
      structure: f32[sz, sz],
      sx: f32[sb, sb],
      sy: f32[sb, sb],
      theta: f32,
    ) -> f32[n, m] {
      let smoothed  = gaussian_smoothing::<n, m, gs>(input, gaussian_filter);
      let laplacian = laplacian_estimate::<n, m, sz>(smoothed, structure);
      let zcs       = zero_crossings::<n, m, sz>(laplacian, structure);
      let gradient  = gradient::<n, m, sb>(smoothed, sx, sy);
      let maxgrad   = max_gradient::<n, m>(gradient);
      return reject_zero_crossings::<n, m>(zcs, gradient, maxgrad, theta);
    }