SorryToPerson logo
返回
算法2026-04-28·10 分钟

算法知识库:计算机视觉基础算法实现

JavaScript/TypeScript 实现计算机视觉基础算法,如图像处理、边缘检测、特征提取等。

计算机视觉基础算法实现

1. 图像类定义

ts
class Image {
  width: number;
  height: number;
  data: number[][][]; // [y][x][channel]

  constructor(width: number, height: number, data?: number[][][]) {
    this.width = width;
    this.height = height;
    this.data = data || this.createEmptyData(width, height);
  }

  private createEmptyData(width: number, height: number): number[][][] {
    return Array.from({ length: height }, () => Array.from({ length: width }, () => [0, 0, 0]));
  }

  getPixel(x: number, y: number): number[] {
    if (x < 0 || x >= this.width || y < 0 || y >= this.height) {
      return [0, 0, 0];
    }
    return [...this.data[y][x]];
  }

  setPixel(x: number, y: number, color: number[]): void {
    if (x >= 0 && x < this.width && y >= 0 && y < this.height) {
      this.data[y][x] = [...color];
    }
  }

  clone(): Image {
    const newData = this.data.map((row) => row.map((pixel) => [...pixel]));
    return new Image(this.width, this.height, newData);
  }
}

2. 灰度转换

ts
function toGrayscale(image: Image): Image {
  const grayImage = new Image(image.width, image.height);

  for (let y = 0; y < image.height; y += 1) {
    for (let x = 0; x < image.width; x += 1) {
      const [r, g, b] = image.getPixel(x, y);
      const gray = Math.round(0.299 * r + 0.587 * g + 0.114 * b);
      grayImage.setPixel(x, y, [gray, gray, gray]);
    }
  }

  return grayImage;
}

3. 高斯模糊

ts
function gaussianBlur(image: Image, sigma: number = 1): Image {
  const kernel = createGaussianKernel(sigma);
  return convolve(image, kernel);
}

function createGaussianKernel(sigma: number): number[][] {
  const size = Math.ceil(6 * sigma);
  if (size % 2 === 0) size += 1;
  const center = Math.floor(size / 2);
  const kernel: number[][] = [];

  let sum = 0;
  for (let y = 0; y < size; y += 1) {
    kernel[y] = [];
    for (let x = 0; x < size; x += 1) {
      const dx = x - center;
      const dy = y - center;
      const value = Math.exp(-(dx * dx + dy * dy) / (2 * sigma * sigma));
      kernel[y][x] = value;
      sum += value;
    }
  }

  // 归一化
  for (let y = 0; y < size; y += 1) {
    for (let x = 0; x < size; x += 1) {
      kernel[y][x] /= sum;
    }
  }

  return kernel;
}

function convolve(image: Image, kernel: number[][]): Image {
  const result = new Image(image.width, image.height);
  const kSize = kernel.length;
  const kCenter = Math.floor(kSize / 2);

  for (let y = 0; y < image.height; y += 1) {
    for (let x = 0; x < image.width; x += 1) {
      let r = 0,
        g = 0,
        b = 0;

      for (let ky = 0; ky < kSize; ky += 1) {
        for (let kx = 0; kx < kSize; kx += 1) {
          const px = x + kx - kCenter;
          const py = y + ky - kCenter;
          const [pr, pg, pb] = image.getPixel(px, py);
          const weight = kernel[ky][kx];

          r += pr * weight;
          g += pg * weight;
          b += pb * weight;
        }
      }

      result.setPixel(x, y, [Math.round(r), Math.round(g), Math.round(b)]);
    }
  }

  return result;
}

4. Sobel 边缘检测

ts
function sobelEdgeDetection(image: Image): Image {
  const grayImage = toGrayscale(image);
  const result = new Image(image.width, image.height);

  const sobelX = [
    [-1, 0, 1],
    [-2, 0, 2],
    [-1, 0, 1],
  ];

  const sobelY = [
    [-1, -2, -1],
    [0, 0, 0],
    [1, 2, 1],
  ];

  for (let y = 1; y < image.height - 1; y += 1) {
    for (let x = 1; x < image.width - 1; x += 1) {
      let gx = 0;
      let gy = 0;

      for (let ky = -1; ky <= 1; ky += 1) {
        for (let kx = -1; kx <= 1; kx += 1) {
          const pixel = grayImage.getPixel(x + kx, y + ky)[0];
          gx += pixel * sobelX[ky + 1][kx + 1];
          gy += pixel * sobelY[ky + 1][kx + 1];
        }
      }

      const magnitude = Math.sqrt(gx * gx + gy * gy);
      const edge = Math.min(255, Math.round(magnitude));
      result.setPixel(x, y, [edge, edge, edge]);
    }
  }

  return result;
}

5. Canny 边缘检测 (简化版)

ts
function cannyEdgeDetection(image: Image, lowThreshold: number = 50, highThreshold: number = 150): Image {
  // 1. 高斯模糊
  const blurred = gaussianBlur(image, 1.4);

  // 2. 梯度计算
  const gradient = sobelEdgeDetection(blurred);

  // 3. 非极大值抑制 (简化版)
  const suppressed = nonMaxSuppression(gradient);

  // 4. 双阈值处理
  const thresholded = doubleThreshold(suppressed, lowThreshold, highThreshold);

  // 5. 边缘连接 (简化版)
  return hysteresis(thresholded);
}

function nonMaxSuppression(gradient: Image): Image {
  // 简化实现
  return gradient.clone();
}

function doubleThreshold(image: Image, low: number, high: number): Image {
  const result = new Image(image.width, image.height);

  for (let y = 0; y < image.height; y += 1) {
    for (let x = 0; x < image.width; x += 1) {
      const pixel = image.getPixel(x, y)[0];
      let value = 0;

      if (pixel >= high) {
        value = 255;
      } else if (pixel >= low) {
        value = 128; // 弱边缘
      }

      result.setPixel(x, y, [value, value, value]);
    }
  }

  return result;
}

function hysteresis(image: Image): Image {
  const result = image.clone();

  for (let y = 1; y < image.height - 1; y += 1) {
    for (let x = 1; x < image.width - 1; x += 1) {
      if (image.getPixel(x, y)[0] === 128) {
        // 检查 8 邻域是否有强边缘
        let hasStrongNeighbor = false;
        for (let dy = -1; dy <= 1; dy += 1) {
          for (let dx = -1; dx <= 1; dx += 1) {
            if (image.getPixel(x + dx, y + dy)[0] === 255) {
              hasStrongNeighbor = true;
              break;
            }
          }
          if (hasStrongNeighbor) break;
        }

        const value = hasStrongNeighbor ? 255 : 0;
        result.setPixel(x, y, [value, value, value]);
      }
    }
  }

  return result;
}

6. 直方图均衡化

ts
function histogramEqualization(image: Image): Image {
  const grayImage = toGrayscale(image);
  const histogram = new Array(256).fill(0);
  const cdf = new Array(256).fill(0);

  // 计算直方图
  for (let y = 0; y < grayImage.height; y += 1) {
    for (let x = 0; x < grayImage.width; x += 1) {
      const pixel = grayImage.getPixel(x, y)[0];
      histogram[pixel] += 1;
    }
  }

  // 计算累积分布函数
  cdf[0] = histogram[0];
  for (let i = 1; i < 256; i += 1) {
    cdf[i] = cdf[i - 1] + histogram[i];
  }

  // 归一化 CDF
  const totalPixels = grayImage.width * grayImage.height;
  const cdfMin = cdf.find((val) => val > 0) || 0;

  const result = new Image(grayImage.width, grayImage.height);
  for (let y = 0; y < grayImage.height; y += 1) {
    for (let x = 0; x < grayImage.width; x += 1) {
      const pixel = grayImage.getPixel(x, y)[0];
      const equalized = Math.round(((cdf[pixel] - cdfMin) / (totalPixels - cdfMin)) * 255);
      result.setPixel(x, y, [equalized, equalized, equalized]);
    }
  }

  return result;
}

7. 实现要点

  • 图像处理基于像素操作。
  • 卷积用于滤波和特征提取。
  • 边缘检测结合梯度和阈值。
  • 直方图均衡化改善对比度。
  • 实际应用中应使用专门的图像处理库。
算法计算机视觉JavaScript