前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Processing速写Day007-摄像头与物理世界

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

作者头像
ChildhoodAndy
发布2021-07-15 09:42:29
5330
发布2021-07-15 09:42:29
举报
文章被收录于专栏:小菜与老鸟小菜与老鸟

本篇是 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

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-07-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 小菜与老鸟 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 摄像头的颜色识别
  • 物理世界
    • 物理世界中随指尖颜色运动的平台
    • 查看代码
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档