/* * 作成日: 2008/06/18 */ package jp.ac.fit.asura.nao.vision.perception; import static jp.ac.fit.asura.nao.vision.GCD.cCYAN; import static jp.ac.fit.asura.nao.vision.GCD.cYELLOW; import static jp.ac.fit.asura.nao.vision.VisualObjects.BlueGoal; import static jp.ac.fit.asura.nao.vision.VisualObjects.YellowGoal; import java.awt.Rectangle; import java.util.List; import jp.ac.fit.asura.nao.physical.Field; import jp.ac.fit.asura.nao.vision.VisualParam.Float; import jp.ac.fit.asura.nao.vision.VisualParam.Int; import jp.ac.fit.asura.nao.vision.perception.BlobVision.Blob; import org.apache.log4j.Logger; /** * @author sey * * @version $Id: GoalVision.java 704 2008-10-23 17:25:51Z sey $ * */ public class GoalVision extends AbstractVision { private Logger log = Logger.getLogger(GoalVision.class); public void findYellowGoal() { VisualObject goal = getContext().get(YellowGoal); findGoal((GoalVisualObject) goal, cYELLOW); } public void findBlueGoal() { VisualObject goal = getContext().get(BlueGoal); findGoal((GoalVisualObject) goal, cCYAN); } private void findGoal(GoalVisualObject vo, byte color) { int threshold = getContext().getParam(Int.GOAL_BLOB_THRESHOLD); List<Blob> blobs = getContext().blobVision.findBlobs(color, 10, threshold); List<Blob> set = vo.getBlobs(); for (Blob blob : blobs) { set.add(blob); } if (!blobs.isEmpty()) { getContext().generalVision.processObject(vo); getContext().generalVision.calcBoundary(vo, color); calculateDistance(vo); checkRobotAngle(vo); } } private void calculateDistance(GoalVisualObject vo) { vo.isLeftPost = false; vo.isRightPost = false; Rectangle area = vo.area; int dist = -1; if (!vo.isLeftTouched() && !vo.isRightTouched()) { // 左右で切れていない if (!vo.isTopTouched() && !vo.isBottomTouched()) { // どこも切れていない log.debug("no touched."); dist = calcDistWithHeight(vo); } else if ((vo.isTopTouched() && !vo.isBottomTouched()) || (!vo.isTopTouched() && vo.isBottomTouched())) { // 上もしくは下だけ切れてる log.debug("top or bottom touched."); if (vo.getBlobs().size() == 1) { int mass = 0; for (Blob b : vo.getBlobs()) { mass += b.mass; } if ((float) mass / (area.width * area.height) > 0.4) { dist = calcDistWithPole(vo); vo.isLeftPost = true; vo.isRightPost = true; } else { dist = calcDistWithWidth(vo); } } else if (vo.getBlobs().size() > 1 && (float) (area.width / area.height) > 1.5f) { // blob二つ以上で構成されていて横長なら両方のポールがみえてるはず dist = calcDistWithWidth(vo); } } else { // 上下が切れている log.debug("top and bottom touched."); if (vo.getBlobs().size() == 1 && (float) area.height / area.width > 1.5f) { // たぶん1つのポール dist = calcDistWithPole(vo); vo.isLeftPost = true; vo.isRightPost = true; } } } else { // 右か左で切れている log.debug("left or right touched."); if ((vo.isTopTouched() && !vo.isBottomTouched()) || (!vo.isTopTouched() && vo.isBottomTouched())) { // 上か下だけ切れている log.debug("top or bottom touched"); if ((float) area.width / area.height > 1.5f) { // 横長であれば高さから dist = calcDistWithHeight(vo); } else if ((float) area.height / area.width > 6.0f) { // かなり縦長 dist = calcDistWithPole(vo); if (vo.isRightTouched()) vo.isRightPost = true; if (vo.isLeftTouched()) vo.isLeftPost = true; } } else if (!vo.isTopTouched() && !vo.isBottomTouched()) { // 上下が切れていない dist = calcDistWithHeight(vo); } } if (dist * dist > Field.MaxY * Field.MaxX * 4) { log.debug(vo.getType() + " dist too far. dist:" + dist); vo.confidence = 0; return; } if (dist <= 0) { log.debug(vo.getType() + " invalid distance dist:" + dist); vo.confidence = 0; return; } vo.distance = dist; vo.distanceUsable = true; log.debug(vo.getType() + " dist:" + dist); return; } // blob中のポールの太さから距離を計算 private int calcDistWithPole(GoalVisualObject vo) { Rectangle area = vo.area; log.debug(vo.type + " calc distance with pole. size:" + area.width); float a = getContext().getParam(Float.GOAL_DIST_CALIB_POLEa); float b = getContext().getParam(Float.GOAL_DIST_CALIB_POLEb); float c = getContext().getParam(Float.GOAL_DIST_CALIB_POLEc); return (int) (a / (area.width + b) - c); } // blob中のゴールの高さ(ポールの高さ)から距離を計算 private int calcDistWithHeight(GoalVisualObject vo) { Rectangle area = vo.area; log.debug(vo.type + " calc distance with height. size:" + area.height); float a = getContext().getParam(Float.GOAL_DIST_CALIB_HEIGHTa); float b = getContext().getParam(Float.GOAL_DIST_CALIB_HEIGHTb); float c = getContext().getParam(Float.GOAL_DIST_CALIB_HEIGHTc); return (int) (a / (area.height + b) - c); } // blob中のゴールの幅(二本のポールの間の幅)から距離を計算 private int calcDistWithWidth(GoalVisualObject vo) { Rectangle area = vo.area; log.debug(vo.type + " calc distance with width. size:" + area.width); float a = getContext().getParam(Float.GOAL_DIST_CALIB_WIDTHa); float b = getContext().getParam(Float.GOAL_DIST_CALIB_WIDTHb); float c = getContext().getParam(Float.GOAL_DIST_CALIB_WIDTHc); return (int) (a / (area.width + b) - c); } private void checkRobotAngle(GoalVisualObject goal) { if (goal.robotAngle.y > 0.15f) { log.debug(goal.getType() + " sanity too high angle."); goal.confidence = 0; } else if (goal.robotAngle.y < -0.5f) { log.debug(goal.getType() + " sanity too low angle."); goal.confidence = 0; } } }