【B-Human】之Color Table

本文详细介绍了ColorTable的概念及应用,包括如何通过SimRobot命令进行创建与配置,以及如何选择合适的色表。此外,文章还提供了创建Colortable的基本步骤与技巧,并指导如何在Simulator中调整光线条件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

详解Color Table

一、什么是color table
    A color table is a mapping from imagecolors to color classes.   一幅图像可以由 256*256*256 种颜色构成,即每 8 位色阶数据构成一个色彩频道     color channel ),有 3 个频道,这三个频道的色阶叠合在一起,图像就会以 24bit     真彩色显示,由于 256*256*256=16MB ,这个存储空间相当大,于是就只使用高 6 位来表示每个色彩频道,这样, color table 这个三维数组的大小就会成为 64*64*64=262144B. 但是仍能够准确的反应颜色信息。

二、simrobot console command解析
比较常用的几个:
1、ctundo 这个是很常用的,可以撤销上一次的错误,最多10次。
2、cton|off这个选择可以开始或关闭创建色表,注意在进行标定时候一定要记得先ctoff一下,以免在图像上点点时,改变了color table。
3、ctsave file保存当前你所创建的色表,不然白费了半天功夫。
4、ctsendAndWrite 通过它可以把当前的色表发给机器人,或者直接copyfile也行。
5、ctimageRadius 这个就是在你点一个点,在color table里出现的cube的大小,最大应该是32,这时候就会把整个colortable填满了。一般不要改这个。
6、cttraining on开始使用最近邻法构建k-d tree(这里是3-d tree),这时候点击就是产生training data。
7、ctkd neighbours|range 这个是设定k-d tree的邻居和范围.If the range issmall,colors nearby the training data are classied,if it is big,it may resultin huge blobs.Big neighbouring will result small cluseters.具体效果参见page53,上面的那副图。
8、ctclear清除当前的color table。
9、ctgrow|shrink 如果发现某种颜色与另一种在图像上一些blur,就让多的那种shrink下,如果发现color table中某种颜色过于稀薄,可以让它grow一下。

三、simrobot快捷操作
1、鼠标左键,通过这种方式点点或者按住鼠标不放选一块小区域,一般是结合trainingdata建立color table的方法。
2、按住shift键的同时按左键,这种一般就是纯手工建立color table,点一个点加一个class,选一块区域,就加一整快区域的。
3、按住ctrl键同时按左键,撤销上一步操作。
4、Shift加ctrl加左键,删除某一个或某一快颜色。
5、滚动滑轮,放大缩小image。

四、选择采用的色表
cameraCalibration.cfg文件中,最后一行的colorTemperature决定所使用的色表,其中default为 coltable.c64,sim为 coltableSim.c64,new为coltableNew.c64,old为coltableOld.c64.

五、配置模拟器中的光线
In the directoryConfig/Scenes/,first open one *.ros2 file,you can find  the linestart with <light...,now you can change the content to reallize the lightcondition you want according to the B-Human 11 Report,at page 184.Forexample,constantAttenuation means the constant value for Attenuation which willmake the light decreased with the distance.

六、创建一个color table的基本步骤
1、纯手工创建
            ct on   ---> ct <color>   然后再按住shift 键同时点击图像上相应的点或区域(区域比较好用)  ---> 当点了足够多的点感觉segmentedimage 不错了的时候,ct save <file>  ---> 使用copyfiles 工具将其上传到机器人(此种方法较慢,但是效果较好)
       2 、通过近邻法建立 k-d tree 来自动创建 color table
            ct training on  --->  点击图像上的对应颜色的点,不需要太多  ---> ct kd neighbours <number> àct kd range <number>  设定下neighbour range(3 20 效果还不错---> ct reclassify  生成colortable  ---> ct save <file>  --->  使用copyfiles 工具将其上传到机器人(此种方法速度快,不需点太多的点,但经常需要调整)
       生成的color table 如果效果不理想可以根据实际再进行调整。

详情咨询happylyang同学:http://www.happylyang.com   
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #define B_SIZE 19 #define M_MOVE 400 #define S_COUNT 5000 #define H_SIZE 100000 //S_COUNTz //H_SIZE=HAXI_SIZE哈希链表对棋局进行缓存, char board[B_SIZE][B_SIZE];//棋盘暂时用字符串生成 int h[M_MOVE][2];//记录每一步 int count = 0;//记录步数 int cp = 1;//cp=current_player int lx = -1; int ly = -1; int lc[B_SIZE][B_SIZE] = {0}; int end_flag = 0;//弃权次数,用于计算是否结束比赛 // 并查集初始化 int parent[B_SIZE * B_SIZE]; void u_find() { for (int i = 0; i < B_SIZE * B_SIZE; i++) { parent[i] = i; } } // 查找根节点 //路径压缩优化,提高查找效率 int find(int x) { if (parent[x] != x) { parent[x] = find(parent[x]); } return parent[x]; } // 合并两个集合,处理围棋里面的连通块,即大龙** void union_sets(int x, int y) { int rootX = find(x); int rootY = find(y); if (rootX != rootY) { parent[rootX] = rootY; } } //深度优先策略,搜索气 void dfs(int x, int y, char color, int visited[B_SIZE][B_SIZE], int *qi) { if (x < 0 || x >= B_SIZE || y < 0 || y >= B_SIZE) { return; } if (visited[x][y]) { return; } if (board[x][y] == '.') { (*qi)++; //更新气的数量 return; } if (board[x][y] != color) { return; } visited[x][y] = 1; dfs(x + 1, y, color, visited, qi); dfs(x - 1, y, color, visited, qi); dfs(x, y - 1, color, visited, qi); dfs(x, y + 1, color, visited, qi); } //记录气的数目 int qi[B_SIZE][B_SIZE]; //更新气的数目 void update_qi() { memset(qi, -1, sizeof(qi)); for (int i = 0; i < B_SIZE; i++) { for (int j = 0; j < B_SIZE; j++) { if (board[i][j] != '.') { int visited[B_SIZE][B_SIZE] = {0}; int qis = 0; dfs(i, j, board[i][j], visited, &qis); qi[i][j] = qis; } } } } //初始化棋盘 void initialize() { for (int i = 0; i < B_SIZE; i++) { for (int j = 0; j < B_SIZE; j++) { board[i][j] = '.'; } } count = 0; lx = -1; ly = -1; memset(lc, 0, sizeof(lc)); u_find(); update_qi(); end_flag = 0; } //显示棋盘 void show() { printf(" "); for (int i = 0; i < B_SIZE; i++) { printf(" %c ", 'a' + i); } printf("\n"); for (int i = 0; i < B_SIZE; i++) { printf("%2d", i + 1); for (int j = 0; j < B_SIZE; j++) { if (i == lx && j == ly) { printf("-%c-", board[i][j] == '*' ? '*' : board[i][j] == 'o' ? 'o' : '.'); } else { printf(" %c ", board[i][j]); } } printf("\n"); } } //检测合法落子 int legal_move(int x, int y) { return x >= 0 && x < B_SIZE && y >= 0 && y < B_SIZE; } //提子 int capture_zi(int x, int y) { char opponent = (cp == 1)? 'o' : '*'; int captured = 0; int visited[B_SIZE][B_SIZE] = {0}; int directions[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; for (int i = 0; i < 4; i++) { int new_x = x + directions[i][0]; int new_y = y + directions[i][1]; if ( legal_move(new_x, new_y) && board[new_x][new_y] == opponent && !visited[new_x][new_y]) { int liberties = 0; dfs(new_x, new_y, opponent, visited, &liberties); if (liberties == 0) { for (int j = 0; j < B_SIZE; j++) { for (int k = 0; k < B_SIZE; k++) { if (visited[j][k]) { board[j][k] = '.'; captured++; } } } } memset(visited, 0, sizeof(visited)); } } update_qi(); return captured; } //判断打劫 int is_ko(int x, int y) { if (count < 2) { return 0; } int captured = capture_zi(x, y); if (captured!= 1) return 0; int prev_x = h[count - 2][0]; int prev_y = h[count - 2][1]; int current[B_SIZE][B_SIZE] = {0}; for (int i = 0; i < B_SIZE; i++) { for (int j = 0; j < B_SIZE; j++) { if (board[i][j]!= lc[i][j]) { current[i][j] = 1; } } } int single_capture = 0; for (int i = 0; i < B_SIZE; i++) { for (int j = 0; j < B_SIZE; j++) { if (current[i][j]) { if (single_capture) return 0; single_capture = 1; } } } if (single_capture && x == prev_x && y == prev_y) return 1; return 0; } //落子 void move(int x, int y) { board[x][y] = cp == 1? '*' : 'o'; h[count][0] = x; h[count][1] = y; count++; lx = x; ly = y; int captured = capture_zi(x, y); for (int i = 0; i < B_SIZE; i++) { for (int j = 0; j < B_SIZE; j++) { lc[i][j] = board[i][j]; } } //检测落子的气 int self = 0; int visited[B_SIZE][B_SIZE] = {0}; dfs(x, y, board[x][y], visited, &self); if (self == 0) { board[x][y] = '.'; count--; printf("wrong position,please change a correct position.\n"); return; } cp = 3 - cp; update_qi(); end_flag = 0; } //保存棋局 void save(const char *filename) { FILE *file = fopen(filename, "w"); if (file == NULL) { printf("can't open file\n"); return; } for (int i = 0; i < count; i++) { fprintf(file, "%d %d\n", h[i][0], h[i][1]); } fclose(file); } //读取棋局 void load(const char *filename) { initialize(); FILE *file = fopen(filename, "r"); if (file == NULL) { printf("can't open file\n"); return; } int x, y; while (fscanf(file, "%d %d", &x, &y) == 2) { move(x, y); } fclose(file); } //复盘 void replay() { initialize(); int a = 0;//记录当前步骤 char input; while (1) { show();//先展示棋盘 printf("N show the next situation, L show the next situation ,Q break.\n"); scanf(" %c", &input); if (input == 'N' && a < count - 1) { a++; move(h[a][0], h[a][1]); } else if (input == 'L' && a > 0) { a--; initialize(); for (int i = 0; i <= a; i++) { move(h[i][0], h[i][1]); } } else if (input == 'Q') { break; } } } //数子 void m_count() { int black = 0, white = 0; for (int i = 0; i < B_SIZE; i++) { for (int j = 0; j < B_SIZE; j++) { if (board[i][j] == '*') { black++; } else if (board[i][j] == 'o') { white++; } } } printf("Black: %d, White: %d\n", black, white); if (black > white) { printf("Black stones win!\n"); } else if (white > black) { printf("White stones win!\n"); } else { printf("It's a draw!\n"); } } // 检查是否结束比赛 int game_over() { if (end_flag >= 2) { printf("Both players have passed consecutively. Game over!\n"); m_count(); return 1; } return 0; } //节点定义,存储坐标 typedef struct wjt { int x, y; int wins; int visits; struct wjt *next; } wjt; wjt *hash_table[H_SIZE]; // 简单的哈希函数,提高搜索决策效率 unsigned int hash(char board[B_SIZE][B_SIZE]) { unsigned int hash_val = 0; for (int i = 0; i < B_SIZE; i++) { for (int j = 0; j < B_SIZE; j++) { hash_val = (hash_val * 31 + board[i][j]) % H_SIZE; } } return hash_val; } // 在哈希表中查找节点 wjt *find_node(char board[B_SIZE][B_SIZE], int x, int y) { unsigned int hash_val = hash(board); wjt *current = hash_table[hash_val]; while (current != NULL) { if (current->x == x && current->y == y) { return current; } current = current->next; } return NULL; } // 插入新节点到哈希表 void insert_node(char board[B_SIZE][B_SIZE], int x, int y) { unsigned int hash_val = hash(board); wjt *new_node = (wjt *)malloc(sizeof(wjt)); new_node->x = x; new_node->y = y; new_node->wins = 0; new_node->visits = 0; new_node->next = hash_table[hash_val]; hash_table[hash_val] = new_node; } // 改进后的评估函数,考虑棋子的气和布局 int evaluate(char board[B_SIZE][B_SIZE], int cp) { int b_score = 0, w_score = 0; int i, j; for (i = 0; i < B_SIZE; i++) { for (j = 0; j < B_SIZE; j++) { if (board[i][j] == '*') { b_score += qi[i][j]; } else if (board[i][j] == 'o') { w_score += qi[i][j]; } } } if (cp == 1) { return b_score - w_score; } else { return w_score - b_score; } } // 蒙特卡罗模拟 int mct(char board[B_SIZE][B_SIZE], int cp) { char temp[B_SIZE][B_SIZE]; memcpy(temp, board, sizeof(temp)); int player = cp; int end_flag = 0; int local_count = 0; int local_history[M_MOVE][2]; while (1) { int valid_flag = 0; for (int i = 0; i < B_SIZE; i++) { for (int j = 0; j < B_SIZE; j++) { if (legal_move(i, j)) { local_history[local_count][0] = i; local_history[local_count][1] = j; local_count++; temp[i][j] = player == 1? '*' : 'o'; int captured = 0; // 模拟提子 char opponent = (player == 1)? 'o' : '*'; int visited[B_SIZE][B_SIZE] = {0}; int directions[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; for (int k = 0; k < 4; k++) { int new_x = i + directions[k][0]; int new_y = j + directions[k][1]; if (new_x >= 0 && new_x < B_SIZE && new_y >= 0 && new_y < B_SIZE && temp[new_x][new_y] == opponent &&!visited[new_x][new_y]) { int liberties = 0; int temp_visited[B_SIZE][B_SIZE] = {0}; dfs(new_x, new_y, opponent, temp_visited, &liberties); if (liberties == 0) { for (int m = 0; m < B_SIZE; m++) { for (int n = 0; n < B_SIZE; n++) { if (temp_visited[m][n]) { temp[m][n] = '.'; captured++; } } } } } } // 检测落子的气 int self = 0; int self_visited[B_SIZE][B_SIZE] = {0}; dfs(i, j, temp[i][j], self_visited, &self); if (self == 0) { temp[i][j] = '.'; local_count--; } else { valid_flag = 1; end_flag = 0; break; } } } if (valid_flag) break; } if (!valid_flag) { end_flag++; player = 3 - player; if (end_flag >= 2) { break; } continue; } player = 3 - player; } int black = 0, white = 0; for (int i = 0; i < B_SIZE; i++) { for (int j = 0; j < B_SIZE; j++) { if (temp[i][j] == '*') { black++; } else if (temp[i][j] == 'o') { white++; } } } if (cp == 1 && black > white) { return 1; } else if (cp == 2 && white > black) { return 1; } return 0; } // 电脑落子函数 void computer_move(char board[B_SIZE][B_SIZE], int cp) { memset(hash_table, 0, sizeof(hash_table)); for (int i = 0; i < B_SIZE; i++) { for (int j = 0; j < B_SIZE; j++) { if (legal_move(i, j)) { insert_node(board, i, j); } } } for (int k = 0; k < S_COUNT; k++) { for (int i = 0; i < B_SIZE; i++) { for (int j = 0; j < B_SIZE; j++) { wjt *node = find_node(board, i, j); if (node != NULL) { char temp[B_SIZE][B_SIZE]; memcpy(temp, board, sizeof(temp)); temp[i][j] = cp == 1? '*' : 'o'; int result = mct(temp, cp); node->visits++; if (result == 1) { node->wins++; } } } } } int best_x = -1, best_y = -1; double best_score = -1; for (int i = 0; i < B_SIZE; i++) { for (int j = 0; j < B_SIZE; j++) { wjt *node = find_node(board, i, j); if (node != NULL) { // 结合模拟结果和当前棋局评估来计算得分 double simulation_score = (double)node->wins / node->visits; int evaluation_score = evaluate(board, cp); double combined_score = simulation_score * 0.6 + evaluation_score * 0.4; // 可调整权重 if (combined_score > best_score) { best_score = combined_score; best_x = i; best_y = j; } } } } if (best_x != -1 && best_y != -1) { move(best_x, best_y); } } // 释放哈希表中所有节点的内存 void free_hash_table() { for (int i = 0; i < H_SIZE; i++) { wjt *current = hash_table[i]; wjt *next; while (current != NULL) { next = current->next; free(current); current = next; } hash_table[i] = NULL; } } int main(int argc, char *argv[]) { int mode; printf("-----------------------------------------------------------\n"); printf("-----------------------------------------------------------\n"); printf("-----------------------------------------------------------\n"); printf("------Game mode: 1. Two players 2. Human vs Computer------\n"); printf("-----------------------------------------------------------\n"); printf("-----------------------------------------------------------\n"); printf("-----------------------------------------------------------\n"); printf("Please select:"); scanf("%d", &mode); initialize(); int x, y; char col_str[2]; int row; while (1) { show(); printf("Current player: %s\n", cp == 1 ? "Black" : "White"); if (mode == 2 && cp == 2) { // computer_move(board, cp); } else { char input[10]; printf("Please enter the move position (e.g., c12) or 'P' to pass: "); scanf("%s", input); if (strcmp(input, "P") == 0) { end_flag++; cp = 3 - count; if (game_over()) { break; } continue; } sscanf(input, "%1s%d", col_str, &row); x = row - 1; y = col_str[0] - 'a'; if (legal_move(x, y)) { if (is_ko(x, y)) { printf("This move is a ko. It is prohibited. Please make a new move!\n"); continue; } move(x, y); } else { printf("The move position is invalid. Please enter a new position!\n"); } } if (game_over()) { break; } char c[10]; //存储指令 printf("Enter S to save the game, L to load the game, R to replay the game, other to continue: "); scanf("%s", c); if (strcmp(c, "S") == 0) { char file[100]; //文件名 printf("Please enter the file name to save: "); scanf("%s", file); save(file); } else if (strcmp(c, "L") == 0) { char file[100]; printf("Please enter the file name to load: "); scanf("%s", file); load(file); } else if (strcmp(c, "R") == 0) { replay(); } } free_hash_table(); return 0; } 修改代码
最新发布
05-13
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值