展示一张图片并在出现某些情况时替换为另一张图片

3
我在处理中使用一个颜色跟踪代码。
我希望的效果(示例):
  • 如果检测到红色,则显示图像1
  • 如果检测到绿色,则显示图像2
  • 如果检测到蓝色,则显示图像3
问题是,如果最后一个颜色被检测到并显示了最后一张图片,并且现在跟踪第一个颜色时,第一张图片不在前面(我看不到它)。
整个代码:
 import processing.video.*;
//import hypermedia.net.*;


PImage img;
PImage img2;
PImage img3;

Capture video; 
final int TOLERANCE = 20;

float XRc = 0;// XY coordinate of the center of the first target
float YRc = 0;
float XRh = 0;// XY coordinate of the center of the second target
float YRh = 0;
float XRc2 = 0; // XY coordinate of the center of the third target
float YRc2 = 0;
float XRh2 = 0;// XY coordinate of the center of the fourth target
float YRh2 = 0;

int ii=0; //Mouse click counter

color trackColor; //The first color is the center of the robot 
color trackColor2; //The second color is the head of the robot
color trackColor3; //The first color is the center of the robot 2
color trackColor4; //The first color is the center of the robot 2

void setup() {
img = loadImage("IMG_4700.JPG");
img2 = loadImage("2.JPG");
img3 = loadImage("3.JPG");
size(800,800);
video = new Capture(this,640,480);
video.start();

trackColor = color(94,164,126);
trackColor2 = color(60,110,194);
trackColor3 = color(197, 76,64);
trackColor4 = color(255,0,0);
smooth();
}

void draw() {
background(0);
if (video.available()) {
    video.read();
}

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

  float r2 = red(trackColor);
  float g2 = green(trackColor);
  float b2 = blue(trackColor);

  float r3 = red(trackColor2);
  float g3 = green(trackColor2);
  float b3 = blue(trackColor2);

  float r4 = red(trackColor3);
  float g4 = green(trackColor3);
  float b4 = blue(trackColor3);

  float r5 = red(trackColor4);
  float g5 = green(trackColor4);
  float b5 = blue(trackColor4);


  int somme_x = 0, somme_y = 0; // pour le calcul des baricentres
  int compteur = 0;

  int somme_x2 = 0, somme_y2 = 0; // pour le calcul des baricentres
  int compteur2 = 0;

  int somme_x3 = 0, somme_y3 = 0; // pour le calcul des baricentres
  int compteur3 = 0;

  int somme_x4 = 0, somme_y4 = 0; // pour le calcul des baricentres
  int compteur4 = 0;


  for(int x = 0; x < video.width; x++) {
    for(int y = 0; y < video.height; y++) {

      int currentLoc = x + y*video.width;
      color currentColor = video.pixels[currentLoc];

      float r1 = red(currentColor);
      float g1 = green(currentColor);
      float b1 = blue(currentColor);


      if(dist(r1,g1,b1,r2,g2,b2) < TOLERANCE) {
         somme_x += x;
         somme_y += y;
        compteur++;
      }

      else if(compteur > 0) { 
        XRc = somme_x / compteur;
        YRc = somme_y / compteur;
      }


      if(dist(r1,g1,b1,r3,g3,b3) < TOLERANCE) {
         somme_x2 += x;
         somme_y2 += y;
        compteur2++;
      }

      else if(compteur2 > 0) { 
        XRh = somme_x2 / compteur2;
        YRh = somme_y2 / compteur2;
      }

      if(dist(r1,g1,b1,r4,g4,b4) < TOLERANCE) {
         somme_x3 += x;
         somme_y3 += y;
        compteur3++;
      }

      else if(compteur3 > 0) { 
        XRc2 = somme_x3 / compteur3;
        YRc2 = somme_y3 / compteur3;
      }

      if(dist(r1,g1,b1,r5,g5,b5) < TOLERANCE) {
         somme_x4 += x;
         somme_y4 += y;
        compteur4++;
      }

      else if(compteur4 > 0) { 
        XRh2 = somme_x4 / compteur4;
        YRh2 = somme_y4 / compteur4;
      }

  }
  }


// track the color and show images
boolean c1 = false;
boolean c2 = false;
boolean c3 = false;


  if(XRc != 0 || YRc != 0) { // color Green detected
    c1 = true;
    c2 = false;
    c3 = false;
   } 


   if(XRh != 0 || YRh != 0) { // color blue detected
    c2 = true;
    c1 = false;
    c3 = false;
   }

    if(XRc2 != 0 || YRc2 != 0) { // color red detected
      c3 = true;
      c1 = false;
      c2 = false;
    }


     if(c1 == true) {
       image(img,0,0); // show image 1
      } else if (c2 == true) {
       image(img2,0,0); // show image 2
     } else if (c3 == true) {
       image(img3,0,0); // show image 3
     }

}

重要片段如下:
// detect color and show images
boolean c1 = false;
boolean c2 = false;
boolean c3 = false;


  if(XRc != 0 || YRc != 0) { // color Green detected
    c1 = true;
    c2 = false;
    c3 = false;
   } 


   if(XRh != 0 || YRh != 0) { // color blue detected
    c2 = true;
    c1 = false;
    c3 = false;
   }

    if(XRc2 != 0 || YRc2 != 0) { // color red detected
      c3 = true;
      c1 = false;
      c2 = false;
    }


     if(c1 == true) {
       image(img,0,0); // show image 1
      } else if (c2 == true) {
       image(img2,0,0); // show image 2
     } else if (c3 == true) {
       image(img3,0,0); // show image 3
     }

截图:

第一个物体被追踪并显示图像 第一个物体被追踪并显示图像

第二个物体被追踪并显示图像 第二个物体被追踪并显示图像

第三个物体被追踪并显示图像 第三个物体被追踪并显示图像

我的问题: (应该追踪第一个物体并显示第一张图片) 应该追踪第一个物体并显示第一张图片


请问您能否发布一些截图以准确展示您所看到的内容? - Kevin Workman
嘿@KevinWorkman,我已经更新了我的帖子,并附上了问题的图片。 - fab
如果我是你,我会添加一堆println()语句来确定到底哪些if语句被执行了,以及所有变量的值。这样可以告诉你代码在做什么,然后我们可以逆向思考为什么会这样。 - Kevin Workman
2个回答

3

有几个方面需要改进。在效率方面,有一些小建议:

  1. setup()中预先计算要跟踪的颜色的RGB组件,而不是在draw()中每秒钟多次计算(例如:float r2 = red(trackColor);等)。
  2. 您可以使用平坦的1D循环而不是使用视频的嵌套循环pixels[]。一个小缺点是您需要从像素索引计算x,y位置。由于您需要显示图像,并且似乎无所谓位置,因此您甚至可能不需要计算x,y。(例如: for(int currentLoc = 0; currentLoc < video.pixels.length; currentLoc++)

关于算法本身:

  1. 您正在使用单一的阈值值(TOLERANCE)。这将剪切掉左侧的任何内容,这是可以的,但不会剪切可能干扰计数器的整个其他颜色范围。我建议使用一个范围(例如MIN_TOLERANCEMAX_TOLERANCE)。
  2. 您正在使用R、G、B颜色空间。R、G、B颜色不像我们期望的那样混合在一起。更感知的颜色空间将表现出您所期望的行为(例如,橙色将更接近红色和黄色)。为此,您需要将RGB转换为CIE XYZ,然后转换为Lab*,计算两种颜色之间的欧几里得距离,然后如果需要显示它,则将结果转换回RGB。您可以在此处找到一个示例。它是在OpenFrameworks(c++)中编写的,但您应该能够看到与Processing的相似之处并进行移植。 还有另一个选择:HSB颜色空间。下面会详细介绍
  3. 您可以绘制一些可视化图形来显示代码如何分段图像。这将更快地了解哪些值效果更好,哪些不好
我建议尝试使用OpenCV for Processing库,它在底层使用更现代的OpenCV库,并提供更多功能和出色的示例。其中一个对您特别有用:HueRangeSelection

HueRangeSelection

试一试。注意你可以移动鼠标来改变范围,如果按住某个键不放,你可以增加范围。例如,这是一个快速演示如何使用你的图片。(HSB范围阈值结果在右下角显示得更小):

red range

green range

blue range

从我的经验来看,我建议不要使用反光材料(例如可乐罐)。您可以在上面的图像中看到,与颜色较浅的绿色和蓝色物体相比,分割效果不太好。因为可乐罐是有反射性的,它将会随着全局光线变化、位置/旋转以及靠近它的物体而呈现出不同的颜色。要满足所有这些条件是很麻烦的。
此外,要进一步了解HueRange示例,您可以:
  1. 应用形态学滤波器(例如腐蚀(), 然后膨胀())来去除一些噪点(较小的白色像素块)。此时,您可以计算每个颜色范围内的白色像素数量,并决定显示哪个图像。
  2. 在过滤后的图像上找到轮廓,可以用它来确定落在要跟踪的颜色范围内的区域的x、y、宽度和高度。

祝你好运,最重要的是要玩得开心!


2

嗯……没有运行代码,我敢打赌问题在于您依赖坐标(XRc及其兄弟节点)为零来选择要使用的图像。它们都被初始化为0,所以第一次运行很好,但是……您从未将它们重置为零,对吧?因此,在检测到3种颜色后,它们都已被更改一次,您的测试变得无用。也许您可以在检测到颜色时将它们全部重置为零。

也许您根本不需要布尔值……

您认为呢?

伪代码

//global
PImage imgs = new PImage[3];

int imageToDispaly = 0;




//all the stuff...





 if(XRc != 0 || YRc != 0) { // color Green detected
  // not sure this will work, but the idea is some thing like this.
  XRh = YRh = XRc2 = YRc2 = 0;
  imageToDispaly = 0;
 } 

 if(XRh != 0 || YRh != 0) { // color blue detected
  XRc = YRc = XRc2 = YRc2 = 0;
  imageToDispaly = 1;
 }

 if(XRc2 != 0 || YRc2 != 0) { // color red detected
  XRh = YRh = XRc = YRc = 0;
  imageToDispaly = 2;
 }

// at appropriated time...
image(imgs[imageToDispaly], x, y);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接