📄 laservisualbw.cc
字号:
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 LaserVisualBW::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 LaserVisualBW::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 LaserVisualBW::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 LaserVisualBW::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 LaserVisualBW::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 camera data.int LaserVisualBW::UpdateCamera(player_camera_data_t * data, double timestamp){ int id, best_id; int x; int symbol_count; int symbols[480]; this->camera_time = timestamp; best_id = -1; // Barcode may not be centered, so look across entire image for (x = 0; x < this->camera_data.width; x += 16) { // Extract raw symbols symbol_count = this->ExtractSymbols(x, sizeof(symbols) / sizeof(symbols[0]), symbols); // Identify barcode id = this->ExtractCode(symbol_count, symbols); // If we see multiple barcodes, we dont know which is the correct one if (id >= 0) { if (best_id < 0) { best_id = id; } else if (best_id != id) { best_id = -1; break; } } } // Assign id to fiducial we are currently looking at. // TODO: check for possible aliasing (not looking at the correct barcode). if (best_id >= 0 && this->ptz_fiducial) { if (this->ptz_fiducial->ptz_lockon_time >= 0) { this->ptz_fiducial->id = best_id; this->ptz_fiducial->id_time = timestamp; } } return 1;}////////////////////////////////////////////////////////////////////////////////// Extract a bit string from the image. Takes a vertical column in// the image and thresholds it.int LaserVisualBW::ExtractSymbols(int x, int symbol_max_count, int symbols[]){ int i, j, off, inc, pix; double fn, fv; int state, start, symbol_count; double kernel[] = {+1, +2, 0, -2, -1}; // GREY if (this->camera_data.bpp == 8) { off = x * this->camera_data.bpp / 8; inc = this->camera_data.width * this->camera_data.bpp / 8; } // RGB24, use G channel else if (this->camera_data.bpp == 24) { off = x * this->camera_data.bpp / 8 + 1; inc = this->camera_data.width * this->camera_data.bpp / 8; } // RGB32, use G channel else if (this->camera_data.bpp == 32) { off = x * this->camera_data.bpp / 8 + 1; inc = this->camera_data.width * this->camera_data.bpp / 8; } else { PLAYER_ERROR1("no support for image depth %d", this->camera_data.bpp); return 0; } //FILE *file = fopen("edge.out", "a+"); assert(symbol_max_count >= this->camera_data.height); state = -1; start = -1; symbol_count = 0; for (i = 2, pix = off + 2 * inc; i < this->camera_data.height - 2; i++, pix += inc) { // Run an edge detector fn = fv = 0.0; for (j = -2; j <= 2; j++) { fv += kernel[j + 2] * this->camera_data.image[pix + j * inc]; fn += fabs(kernel[j + 2]); } fv /= fn; // Pick the transitions if (state == -1) { if (fv > +this->edge_thresh) { state = 1; start = i; } else if (fv < -this->edge_thresh) { state = 0; start = i; } } else if (state == 0) { if (fv > +this->edge_thresh) { symbols[symbol_count++] = -(i - start); state = 1; start = i; } } else if (state == 1) { if (fv < -this->edge_thresh) { symbols[symbol_count++] = +(i - start); state = 0; start = i; } } //fprintf(file, "%d %f %f %d\n", i, fv, fn, state); } if (state == 0) symbols[symbol_count++] = -(i - start); else if (state == 1) symbols[symbol_count++] = +(i - start); //fprintf(file, "\n\n"); //fclose(file); return symbol_count;}////////////////////////////////////////////////////////////////////////////////// Extract a code from a symbol string.int LaserVisualBW::ExtractCode(int symbol_count, int symbols[]){ int i, j, k; double a, b, c; double mean, min, max, wm, wo; int best_digit; double best_err; double err[10]; // These are UPC the mark-space patterns for digits. From: // http://www.ee.washington.edu/conselec/Sp96/projects/ajohnson/proposal/project.htm double digits[][4] = { {-3,+2,-1,+1}, // 0 {-2,+2,-2,+1}, // 1 {-2,+1,-2,+2}, // 2 {-1,+4,-1,+1}, // 3 {-1,+1,-3,+2}, // 4 {-1,+2,-3,+1}, // 5 {-1,+1,-1,+4}, // 6 {-1,+3,-1,+2}, // 7 {-1,+2,-1,+3}, // 8 {-3,+1,-1,+2}, // 9 }; best_digit = -1; // Note that each code has seven symbols in it, not counting the // initial space. for (i = 0; i < symbol_count - 7; i++) { /* for (j = 0; j < 7; j++) printf("%+d", symbols[i + j]); printf("\n"); */ a = symbols[i]; b = symbols[i + 1]; c = symbols[i + 2]; // Look for a start guard: +N-N+N if (a > this->guard_min && b < -this->guard_min && c > this->guard_min) { mean = (a - b + c) / 3.0; min = MIN(a, MIN(-b, c)); max = MAX(a, MAX(-b, c)); assert(mean > 0); if ((mean - min) / mean > this->guard_tol) continue; if ((max - mean) / mean > this->guard_tol) continue; //printf("guard %d %.2f\n", i, mean); best_err = this->err_first; best_digit = -1; // Read the code digit (4 symbols) and compare against the known // digit patterns for (k = 0; k < (int) (sizeof(digits) / sizeof(digits[0])); k++) { err[k] = 0; for (j = 0; j < 4; j++) { wm = digits[k][j]; wo = symbols[i + 3 + j] / mean; err[k] += fabs(wo - wm); //printf("digit %d = %.3f %.3f\n", k, wm, wo); } //printf("digit %d = %.3f\n", k, err[k]); if (err[k] < best_err) { best_err = err[k]; best_digit = k; } } // Id is good if it fits on and *only* one pattern. So find the // second best digit and make sure it has a much higher error. for (k = 0; k < (int) (sizeof(digits) / sizeof(digits[0])); k++) { if (k == best_digit) continue; if (err[k] < this->err_second) { best_digit = -1; break; } } // Stop if we found a valid digit if (best_digit >= 0) break; } } //if (best_digit >= 0) // printf("best = %d\n", best_digit); return best_digit;}////////////////////////////////////////////////////////////////////////////////// Update the device data (the data going back to the client).void LaserVisualBW::WriteData(){ 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 + -