如何获取网络摄像头中特定区域的平均颜色 (Processing/JavaScript)?

How to get the average color of a specific area in a webcam feed (Processing/JavaScript)?

我正在使用 Processing 从我的笔记本电脑获取网络摄像头源。在左上角,我在显示的提要上绘制了一个矩形。我正在尝试获取网络摄像头的平均颜色,但仅限于该矩形包含的区域。

结果我一直得到颜色 (0, 0, 0),黑色。

谢谢大家!

PS 对不起,如果我的代码看起来很乱。我是 Processing 的新手,所以我不知道这是否难以阅读或包含不良做法。谢谢。

import processing.video.*;

Capture webcam;
Capture cap;
PImage bg_img;

color bgColor = color(0, 0, 0);

int rMargin = 50;
int rWidth = 100;

color input = color(0, 0, 0);
color background = color(255, 255, 255);
color current;
int bgTolerance = 5;

void setup() {
  size(1280,720);

  // start the webcam
  String[] inputs = Capture.list();
  if (inputs.length == 0) {
    println("Couldn't detect any webcams connected!");
    exit();
  }
  webcam = new Capture(this, inputs[0]);

  webcam.start();

}


void draw() {
  if (webcam.available()) {

    // read from the webcam
    webcam.read();

    image(webcam, 0,0);
    webcam.loadPixels();

    noFill();
    strokeWeight(2);
    stroke(255,255, 255);
    rect(rMargin, rMargin, rWidth, rWidth);

    int yCenter = (rWidth/2) + rMargin;
    int xCenter = (rWidth/2) + rMargin;
    // rectMode(CENTER);

    int rectCenterIndex = (width* yCenter) + xCenter;

    int r = 0, g = 0, b = 0;

    //for whole image:
    //for (int i=0; i<bg_img.pixels.length; i++) {
    //    color c = bg_img.pixels[i];
    //    r += c>>16&0xFF;
    //    g += c>>8&0xFF;
    //    b += c&0xFF;
    //}
    //r /= bg_img.pixels.length;
    //g /= bg_img.pixels.length;
    //b /= bg_img.pixels.length;

    //CALCULATE AVG COLOR:
    int i;
for(int x = 50; x <= 150; x++){
   for(int y = 50; y <= 150; y++){
           i = (width*y) + x;
           color c = webcam.pixels[i];
           r += c>>16&0xFF;
           g += c>>8&0xFF;
           b += c&0xFF;
       }
    }
    r /= webcam.pixels.length;
    g /= webcam.pixels.length;
    b /= webcam.pixels.length;

    println(r + " " + g + " " + b);
  }
}

您非常接近,但遗漏了一个重要方面:您采样的像素数。

请注意,在示例代码中,您要除以完整像素数 (pixels.length) 的完整图像被注释掉了。

但是,在您的改编版本中,您只想计算整个图像的一部分的平均颜色,这意味着像素数较少。

您只对 100x100 像素的区域进行采样,这意味着您需要除以 10000 而不是 webcam.pixels.length (1920x1000)。这就是为什么你得到 0 因为它是整数除法。 这就是我在代码中的意思:

 int totalSampledPixels = rWidth * rWidth;
 r /= totalSampledPixels;
 g /= totalSampledPixels;
 b /= totalSampledPixels;

完整的调整草图:

import processing.video.*;

Capture webcam;
Capture cap;
PImage bg_img;

color bgColor = color(0, 0, 0);

int rMargin = 50;
int rWidth = 100;
int rHeight = 100;

color input = color(0, 0, 0);
color background = color(255, 255, 255);
color current;
int bgTolerance = 5;

void setup() {
  size(1280,720);

  // start the webcam
  String[] inputs = Capture.list();
  if (inputs.length == 0) {
    println("Couldn't detect any webcams connected!");
    exit();
  }
  webcam = new Capture(this, inputs[0]);

  webcam.start();

}


void draw() {
  if (webcam.available()) {

    // read from the webcam
    webcam.read();

    image(webcam, 0,0);
    webcam.loadPixels();

    noFill();
    strokeWeight(2);
    stroke(255,255, 255);
    rect(rMargin, rMargin, rWidth, rHeight);

    int yCenter = (rWidth/2) + rMargin;
    int xCenter = (rWidth/2) + rMargin;
    // rectMode(CENTER);

    int rectCenterIndex = (width* yCenter) + xCenter;

    int r = 0, g = 0, b = 0;

    //for whole image:
    //for (int i=0; i<bg_img.pixels.length; i++) {
    //    color c = bg_img.pixels[i];
    //    r += c>>16&0xFF;
    //    g += c>>8&0xFF;
    //    b += c&0xFF;
    //}
    //r /= bg_img.pixels.length;
    //g /= bg_img.pixels.length;
    //b /= bg_img.pixels.length;

    //CALCULATE AVG COLOR:
    int i;
    for(int x = 0; x <= width; x++){
       for(int y = 0; y <= height; y++){
         if (x >= rMargin && x <= rMargin + rWidth && y >= rMargin && y <= rMargin + rHeight){

           i = (width*y) + x;
           color c = webcam.pixels[i];
           r += c>>16&0xFF;
           g += c>>8&0xFF;
           b += c&0xFF;

         }
       }
    }
    //divide by just the area sampled (x >= 50 && x <= 150 && y >= 50 && y <= 150 is a 100x100 px area) 
    int totalSampledPixels = rWidth * rHeight;

    r /= totalSampledPixels;
    g /= totalSampledPixels;
    b /= totalSampledPixels;

    fill(r,g,b);
    rect(rMargin + rWidth, rMargin, rWidth, rHeight);

    println(r + " " + g + " " + b);
  }
}

请记住,这是 RGB 颜色 space 的平均值,这与感知颜色 space 不同。例如,如果您将红色和黄色平均化,您会期望橙色,但在 RGB 中,一点红色和绿色会变成黄色。

希望 RGB 平均值足以满足您的需要,否则您可能需要从 RGB 转换为 CIE XYZ colour space then to Lab colour space to compute the perceptual average (then convert back to XYZ and RGB to display on screen). If that is something you're interested in trying, you can find an older answer 在 openFrameworks 中演示这一点(您会注意到它可能类似于简单场景中的处理) .