📄 laservisualbarcode.cc
字号:
mrr = 0.0; mbb = 0.0; // Look for a candidate patch in scan. for (i = 0; i < data->ranges_count; i++) { r = (double) (data->ranges[i]); b = (double) (data->min_angle + i * data->resolution); h = (int) (data->intensity[i]); // If there is a reflection... if (h > 0) { mn += 1; mr += r; mb += b; mrr += r * r; mbb += b * b; } // If there is no reflection and we have a patch... else if (mn > 0) { // Compute the moments of the patch. mr /= mn; mb /= mn; mrr = mrr / mn - mr * mr; mbb = mbb / mn - mb * mb; // Test moments to see if they are valid. valid = 1; valid &= (mn >= 1.0); dr = this->barwidth / 2; db = atan2(this->barwidth / 2, mr); valid &= (mrr < (dr * dr)); valid &= (mbb < (db * db)); if (valid) { // Do a best fit to determine the pose of the reflector. this->FitLaserFiducial(data, i - (int) mn, i - 1, pose); // Match this fiducial against the ones we are already tracking. this->MatchLaserFiducial(time, pose); } mn = 0.0; mr = 0.0; mb = 0.0; mrr = 0.0; mbb = 0.0; } } return;}////////////////////////////////////////////////////////////////////////////////// Find the line of best fit for the given segment of the laser scan.// Fills in the pose and pose of the reflector relative to the laser.void LaserVisualBarcode::FitLaserFiducial(player_laser_data_t *data, int first, int last, double pose[3]){ int i; double r, b; double mn, mr, mb; mn = 0.0; mr = 1e6; mb = 0.0; for (i = first; i <= last; i++) { r = (double) (data->ranges[i]) / 1000; b = (double) (data->min_angle + i * data->resolution) / 100.0 * M_PI / 180; if (r < mr) mr = r; mn += 1.0; mb += b; } mr += this->barwidth / 2; mb /= mn; pose[0] = mr * cos(mb); pose[1] = mr * sin(mb); pose[2] = mb; return;}////////////////////////////////////////////////////////////////////////////////// Match a new laser fiducial against the ones we are already// tracking. The pose is relative to the laser.void LaserVisualBarcode::MatchLaserFiducial(double time, double pose[3]){ int i; double dx, dy, dr; double mindr; fiducial_t *fiducial; fiducial_t *minfiducial; // Observations must be at least this close to the existing // fiducial. mindr = this->max_dist; minfiducial = NULL; // Find the existing fiducial which is closest to the new // observation. for (i = 0; i < this->fiducial_count; i++) { fiducial = this->fiducials + i; dx = pose[0] - fiducial->pose[0]; dy = pose[1] - fiducial->pose[1]; dr = sqrt(dx * dx + dy * dy); if (dr < mindr) { mindr = dr; minfiducial = fiducial; } } // If we didnt find a matching fiducial, add a new one. if (minfiducial == NULL) { if (this->fiducial_count < ARRAYSIZE(this->fiducials)) { minfiducial = this->fiducials + this->fiducial_count++; minfiducial->id = -1; minfiducial->pose[0] = pose[0]; minfiducial->pose[1] = pose[1]; minfiducial->pose[2] = pose[2]; minfiducial->laser_time = time; minfiducial->ptz_select_time = -1; minfiducial->ptz_lockon_time = -1; minfiducial->id_time = -1; } } // Otherwise, update the existing fiducial. else { minfiducial->pose[0] = pose[0]; minfiducial->pose[1] = pose[1]; minfiducial->pose[2] = pose[2]; minfiducial->laser_time = time; } return;}////////////////////////////////////////////////////////////////////////////////// Retire fiducials we havent seen for a while.void LaserVisualBarcode::RetireLaserFiducials(double time, player_laser_data_t *data){ int i; fiducial_t *fiducial; // Remove any old fiducials. for (i = 0; i < this->fiducial_count; i++) { fiducial = this->fiducials + i; if (time - fiducial->laser_time > this->retire_time) { if (this->ptz_fiducial == fiducial) this->ptz_fiducial = NULL; memmove(fiducial, fiducial + 1, (this->fiducial_count - i - 1) * sizeof(fiducial_t)); this->fiducial_count--; i--; } } return;}////////////////////////////////////////////////////////////////////////////////// Update the PTZ to point at one of the laser reflectors.int LaserVisualBarcode::UpdatePtz(player_ptz_data_t * data, double timestamp){ this->ptz_time = timestamp; // Pick a fiducial to look at. this->SelectPtzTarget(timestamp, data); // Point the fiducial this->ServoPtz(timestamp, data); return 1;}////////////////////////////////////////////////////////////////////////////////// Select a target fiducial for the PTZ to inspect.// This algorithm picks the one that we havent looked at for a long time.void LaserVisualBarcode::SelectPtzTarget(double time, player_ptz_data_t *data){ int i; double t, maxt; fiducial_t *fiducial; // Consider the currently selected target for a while to // give the blobfinder time to identify it. if (this->ptz_fiducial != NULL) { if (time - this->ptz_fiducial->ptz_select_time < this->max_ptz_attention) return; } // Find one we havent looked at for while. this->ptz_fiducial = NULL; maxt = -1; for (i = 0; i < this->fiducial_count; i++) { fiducial = this->fiducials + i; t = time - fiducial->ptz_select_time; if (t > maxt) { maxt = t; this->ptz_fiducial = fiducial; } } if (this->ptz_fiducial) { this->ptz_fiducial->ptz_select_time = time; this->ptz_fiducial->ptz_lockon_time = -1; } return;}////////////////////////////////////////////////////////////////////////////////// Servo the PTZ to a target fiducial.void LaserVisualBarcode::ServoPtz(double time, player_ptz_data_t *data){ double dx, dy, r, pan, tilt, zoom; fiducial_t *fiducial; player_ptz_cmd_t cmd; double maxtilt; double deadpan, deadzoom; // Max tilt value. maxtilt = 5 * M_PI / 180; // Deadband values. deadpan = 2; deadzoom = 2; fiducial = this->ptz_fiducial; if (fiducial == NULL) { r = 0; pan = 0; tilt = 0; zoom = M_PI; } else { // Compute range and bearing of fiducial relative to camera. // TODO: account for camera geometry. dx = fiducial->pose[0]; dy = fiducial->pose[1]; r = sqrt(dx * dx + dy * dy); pan = atan2(dy, dx); zoom = 8 * atan2(this->barwidth / 2, r); // See if we have locked on yet. if (fiducial->ptz_lockon_time < 0) if (fabs(pan * 180 / M_PI - data->pan) < deadpan && fabs(zoom * 180 / M_PI - data->zoom) < deadzoom) fiducial->ptz_lockon_time = time; // If we havent locked on yet... if (fiducial->ptz_lockon_time < 0) tilt = 0; else tilt = maxtilt * sin((time - fiducial->ptz_lockon_time) / this->max_ptz_attention * 2 * M_PI); } // Compose the command packet to send to the PTZ device. cmd.pan = pan; cmd.tilt = tilt; cmd.zoom = zoom; this->ptz->PutMsg(InQueue, PLAYER_MSGTYPE_CMD, PLAYER_PTZ_CMD_STATE, &cmd, sizeof(cmd), NULL); // Compute the dimensions of the image at the range of the target fiducial. this->zoomwidth = 2 * r * tan(data->zoom/2); this->zoomheight = 3.0 / 4.0 * this->zoomwidth; return;}////////////////////////////////////////////////////////////////////////////////// Process any new blobfinder data.int LaserVisualBarcode::UpdateBlobfinder(player_blobfinder_data_t * data, double timestamp){ int id; // Extract valid blobs. this->FindBlobs(timestamp, data); // Search for fiducials. id = this->FindVisualFiducials(timestamp, data, 0, NULL); // Assign id to fiducial we are currently looking at. if (id >= 0 && this->ptz_fiducial) { if (this->ptz_fiducial->ptz_lockon_time >= 0) { this->ptz_fiducial->id = id; this->ptz_fiducial->id_time = timestamp; } } return 1;}////////////////////////////////////////////////////////////////////////////////// Find blobs with valid properties.void LaserVisualBarcode::FindBlobs(double time, player_blobfinder_data_t *data){ unsigned int i; blob_t *nblob; player_blobfinder_blob_t *blob; unsigned int width, height; unsigned int minx, maxx, miny, maxy; unsigned int minwidth, maxwidth, minheight, maxheight; int minarea, maxarea; double tol; // Allowable tolerance (fractional error). tol = 0.5; // Compute expect width and height at the current range and zoom. width = (int) (this->barwidth / this->zoomwidth * data->width); height = (int) (this->barheight / this->zoomheight * data->height); // Set limits minx = (int) ((1 - tol) * data->width / 2); maxx = (int) ((1 + tol) * data->width / 2); miny = 0; maxy = data->height; minwidth = (int) ((1 - tol) * width); maxwidth = (int) ((1 + tol) * width); minheight = (int) ((1 - tol) * height); maxheight = (int) ((1 + tol) * height); minarea = 50; maxarea = maxwidth * maxheight; /* printf("zoom %.3f %.3f\n", this->zoomwidth, this->zoomheight); printf("image %d %d\n", data->width, data->height); printf("w, h %d %d\n", width, height); */ this->blob_count = 0; for (i = 0; i < data->blobs_count; i++) { blob = data->blobs + i; // Test the blob properties. if (blob->x < minx || blob->x > maxx) continue; if (blob->y < miny || blob->y > maxy) continue; if ((blob->right - blob->left) < minwidth || (blob->right - blob->left) > maxwidth) continue; if ((blob->bottom - blob->top) < minheight || (blob->bottom - blob->top) > maxheight) continue; if ((int) blob->area < minarea || (int) blob->area > maxarea) continue; /* printf("%d %d : %d %d : %d\n", blob->x, blob->y, blob->right - blob->left, blob->bottom - blob->top, blob->area); */ // Add to valid blob list. if (this->blob_count < ARRAYSIZE(this->blobs)) { nblob = this->blobs + this->blob_count++; nblob->ch = blob->id; nblob->x = blob->x; nblob->y = blob->y; } } return;}////////////////////////////////////////////////////////////////////////////////// Do a recursive depth-first search of the blob list for fiducals.int LaserVisualBarcode::FindVisualFiducials(double time, player_blobfinder_data_t *data, int depth, blob_t *prevblob){ int i, id; blob_t *blob; double dx, dy; double tol; double width, height; // Allowable tolerance (fractional error). tol = 0.5; // Compute expected width and height at the current range and zoom. width = (int) (this->barwidth / this->zoomwidth * data->width); height = (int) (this->barheight / this->zoomheight * data->height); for (i = 0; i < this->blob_count; i++) { blob = this->blobs + i; if (depth > 0) { dx = blob->x - prevblob->x; dy = blob->y - prevblob->y; if (fabs(dx) > (1 - tol) * width) continue; if (dy < (1 - tol) * height) continue; if (dy > (1 + tol) * height) continue; } if (depth == this->barcount - 1) { id = blob->ch; return id; } id = this->FindVisualFiducials(time, data, depth + 1, blob); if (id >= 0) { id = 10 * id + blob->ch; return id; } } return -1;}////////////////////////////////////////////////////////////////////////////////// Update the device data (the data going back to the client).void LaserVisualBarcode::UpdateData(){ int i; double r, b, o; double timestamp; fiducial_t *fiducial; player_fiducial_data_t data; data.fiducials_count = 0; for (i = 0; i < this->fiducial_count; i++) { fiducial = this->fiducials + i; // Only report fiducials that where seen in the most recent laser // scan. if (fiducial->laser_time != this->laser_time) continue; r = sqrt(fiducial->pose[0] * fiducial->pose[0] + fiducial->pose[1] * fiducial->pose[1]); b = atan2(fiducial->pose[1], fiducial->pose[0]); o = fiducial->pose[2]; data.fiducials[data.fiducials_count].id = fiducial->id; data.fiducials[data.fiducials_count].pose.px = r * cos(b); data.fiducials[data.fiducials_count].pose.py = r * sin(b); data.fiducials[data.fiducials_count].pose.pyaw = o; data.fiducials_count++; } // Compute the data timestamp (from laser). timestamp = this->laser_time; // Copy data to server. Publish(device_addr, NULL, PLAYER_MSGTYPE_DATA, PLAYER_FIDUCIAL_DATA_SCAN, (void*) &data, sizeof(data), ×tamp);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -