Processing速写Day007-摄像头与物理世界

2021-07-15 09:42:29 浏览数 (1)

本篇是 Processing 速写100天计划 的第7天Day_007。Processing速写100天计划是小菜的一个命题作业,所谓速写,简单的在5-10分钟,复杂点的在1-2个小时,主要就是敦促小菜能够对 Processing 的基本功进行扎实练习。

平时工作一忙,可能会断更,不过后续有时间一定会接着拾起来。?

好了,话不多说。Day_007 的命题是摄像头识别颜色 物理世界,最后速写练习如上视频号的呈现。

小菜简单说下实现的思路。

摄像头的颜色识别

主要是两点

1)如何计算两个色值是否接近

2)如何寻找最接近目标识别色的那个色值或者位置

首先我添加了一个鼠标点击函数,获取了鼠标点击位置的目标颜色值,也就是我们要识别的颜色(后续要在这个颜色位置添加一个物理平台),并分别计算出了目标的RGB三个颜色通道值,之所以保存成全局的,是为了避免在 draw 函数中反复计算。

代码语言:javascript复制
void mousePressed() {
  int loc = mouseX   mouseY * video.width;
  targetColor = video.pixels[loc];
  targetColorR = red(targetColor);
  targetColorG = green(targetColor);
  targetColorB = blue(targetColor);
}

尽量减少不必要的计算,是提升性能的一个常见手段。

有了目标颜色,下面就是遍历摄像头的数据,进行寻找最接近目标色值的位置。

代码语言:javascript复制
void draw() {
  if (video.available()) {
    video.read();
  }

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

  float targetX = 0;
  float targetY = 0;
  float colorDistance  = 300;
  for (int x = 0; x < video.width; x  ) {
    for (int y = 0; y < video.height; y  ) {
      int loc = x   y * video.width;
      color videoColor = video.pixels[loc];
      float r1 = red(videoColor);
      float g1 = green(videoColor);
      float b1 = blue(videoColor);

      float d = dist(r1, g1, b1, targetColorR, targetColorG, targetColorB);
      if (d < colorDistance) {
        colorDistance = d;
        targetX = x;
        targetY = y;
      }
    }
  }

  if (colorDistance < 15) {
    drawTargetColorShape(targetX, targetY);
  }
}

颜色的距离计算:我们使用dist函数来计算俩颜色的距离,dist函数本来是计算二维、三维坐标点距离用的,刚好我们可以将颜色的RGB三个通道看成三维空间坐标,来计算两个颜色的距离。

寻找最接近的颜色位置:我们设定一个颜色距离的最小值,colorDistance初始值设置的比较随意,给的 300,随着一次又一次 for 循环的迭代遍历,如果计算出的颜色距离小于我们的colorDistance那么我们便更新这个colorDistance,同时更新目标像素的位置即 targetX 和 targetY,遍历结束后,最终的targetX、targetY就是最接近我们目标色的像素位置。

物理世界

谈到使用物理世界,不得不提到大名鼎鼎的Box2D。小菜之前从事游戏开发的时候,经常用到Box2D。Cocos2D引擎内置的物理引擎便是Box2D和Chipmunk。

Box2D 是用 C 语言编写的,但有多种语言的版本,比如 javascript,我们可以在浏览器中使用,也有 java 版的 jbox2d,Daniel Shiffman 基于 jbox2d,做了一层简单的封装,我们可以在三方库找到并添加 Box2D for Processing。

Box2D的话,今天这里就不详细的阐述了。我们主要看下这个速写中的实现用法。

物理世界中从上往下坠落的粒子球

每个粒子都是一个ParticleParticle中都有一个Body,该 Body负责物理世界的模拟,包括重力、碰撞等。

我们将粒子从画面上方随机生成,由于粒子是动态刚体,且受到重力作用,便会做自由落体运动。

Particle的绘制display函数,要注意的是绘制部分的坐标需要从物理模拟世界中查询,如Vec2 pos = box2d.getBodyPixelCoord(body);。这点是使用 Box2D 时值得注意的一个点。

代码语言:javascript复制
class Particle {

  Body body;
  float r;

  color col;

  Particle(float x, float y, float r_) {
    r = r_;

    makeBody(x, y, r);
    body.setUserData(this);

    col = color(random(255), random(255), random(255));
  }

  void killBody() {
    box2d.destroyBody(body);
  }

  boolean done() {
    Vec2 pos = box2d.getBodyPixelCoord(body);
    if (pos.y > height r*2) {
      killBody();
      return true;
    }
    return false;
  }

  void display() {
    Vec2 pos = box2d.getBodyPixelCoord(body);
    float a = body.getAngle();
    pushMatrix();
    translate(pos.x, pos.y);

    rotate(-a);
    fill(col);
    stroke(0);
    strokeWeight(1);
    ellipse(0, 0, r*2, r*2);

    line(0, 0, r, 0);
    popMatrix();
  }

  void makeBody(float x, float y, float r) {
    BodyDef bd = new BodyDef();
    bd.position = box2d.coordPixelsToWorld(x, y);
    bd.type = BodyType.DYNAMIC;

    body = box2d.world.createBody(bd);

    CircleShape cs = new CircleShape();
    cs.m_radius = box2d.scalarPixelsToWorld(r);

    FixtureDef fd = new FixtureDef();
    fd.shape = cs;

    fd.density = 2.0;
    fd.friction = 0.01;
    fd.restitution = 0.3;

    body.createFixture(fd);

    body.setAngularVelocity(random(-10, 10));
  }
}

物理世界中随指尖颜色运动的平台

物理平台是一个静态刚体,BodyTypeSTATIC,我们想让他跟着识别出的颜色位置移动,可以直接用刚体的setTransform改变它的位置,注意将目标位置用coordPixelsToWorld转换到Box2D的物理世界坐标中。

代码语言:javascript复制
  void display(float targetX, float targetY, color c) {
    body.setTransform(box2d.coordPixelsToWorld(targetX, targetY), 0);
    Vec2 pos = box2d.getBodyPixelCoord(body);

    rectMode(PConstants.CENTER);
    pushMatrix();
    translate(pos.x, pos.y);
    fill(c);
    stroke(0);
    rect(0, 0, w, h);
    popMatrix();
  }

查看代码

githubhttps://github.com/xiaocai-laoniao/Processing100DaysSketch

我来笔记地址https://www.wolai.com/childhoodandy/nFdnVWMHkYxtb6QgBxHDJx?theme=dark

0 人点赞