C++基于像素连通域识别图片按钮并绘制标注框的代码实现问题
按钮识别程序补全方案
实现逻辑说明
- 新增像素判断函数:根据像素RGB值判定是否属于按钮区域,可根据实际图像的按钮、背景色差调整阈值
- 新增四连通递归搜索函数:遍历单个按钮的所有连通像素,自动计算该按钮的最小/最大横纵坐标,得到标注框的边界
- 遍历全图触发搜索:每识别到一个未处理的按钮像素就启动连通域搜索,搜索完成后在边界绘制红色标注框
- 按照PPM P3格式规范写入处理后的图像数据
完整补全代码
#include <iostream> #include <fstream> #include <cstdlib> using namespace std; class pixel_class { private: int red, green, blue; bool exclude; // if true, do not check this pixel public: void loaddata(int v1, int v2, int v3); void datatofile(fstream & ppmfile); int getR() { return red; } int getG() { return green; } int getB() { return blue; } void setexclude(bool ex) { exclude = ex; } bool getexclude() { return exclude; } }; void loadButtons(); // 新增辅助函数声明 bool isButtonPixel(int x, int y); void dfsSearch(int x, int y); int total, xmin, xmax, ymin, ymax; // MUST be global if used int screenx, screeny, maxcolours; // you must use these pixel_class picture[600][600]; // you must use this int main() { // Step 1 : read in the image from Buttons.ppm loadButtons(); // Step 2 : identify buttons and draw boxes for (int y = 0; y < screeny; y++) { for (int x = 0; x < screenx; x++) { if (isButtonPixel(x, y)) { // 初始化当前按钮的边界值 xmin = x; xmax = x; ymin = y; ymax = y; // 四连通搜索当前按钮的所有像素 dfsSearch(x, y); // 绘制红色矩形标注框,线宽2像素避免显示过细 for (int px = xmin - 1; px <= xmax + 1; px++) { if (px >= 0 && px < screenx) { if (ymin - 1 >= 0) picture[px][ymin - 1].loaddata(255, 0, 0); if (ymax + 1 < screeny) picture[px][ymax + 1].loaddata(255, 0, 0); } } for (int py = ymin - 1; py <= ymax + 1; py++) { if (py >= 0 && py < screeny) { if (xmin - 1 >= 0) picture[xmin - 1][py].loaddata(255, 0, 0); if (xmax + 1 < screenx) picture[xmax + 1][py].loaddata(255, 0, 0); } } } } } // Step 3 : output the final .ppm file fstream outfile; string outfilename = "Labeled_Buttons.ppm"; outfile.open(outfilename.c_str(), fstream::out); if (outfile.is_open() == false) { cout << "ERROR: 无法打开输出文件 " << outfilename << endl; exit(3); } // 写入PPM标准头信息 outfile << "P3" << endl; outfile << "# 按钮标注结果图" << endl; outfile << screenx << " " << screeny << endl; outfile << maxcolours << endl; // 写入所有像素数据 for (int y = 0; y < screeny; y++) { for (int x = 0; x < screenx; x++) { picture[x][y].datatofile(outfile); } outfile << endl; } outfile.close(); cout << "处理完成,标注结果已保存为 " << outfilename << endl; return 0; } void loadButtons() { // load the picture from Buttons.ppm int x, y, R, G, B; fstream infile; string infilename, line; infilename = "Buttons.ppm"; infile.open(infilename.c_str(), fstream::in); if (infile.is_open() == false) { cout << "ERROR: 无法打开输入文件 " << infilename << endl; exit(2); } getline(infile, line); // this line is "P3" getline(infile, line); // this line is "# filename" infile >> screenx >> screeny; // this line is the size infile >> maxcolours; // this line is 256 for (y = 0; y < screeny; y++) { for (x = 0; x < screenx; x++) { infile >> R >> G >> B; picture[x][y].loaddata(R, G, B); picture[x][y].setexclude(false); } } infile.close(); } // 判断是否为未处理的按钮像素,可根据实际图像调整阈值 bool isButtonPixel(int x, int y) { if (x < 0 || x >= screenx || y < 0 || y >= screeny) return false; if (picture[x][y].getexclude()) return false; // 示例判断逻辑:深色按钮、浅色背景,RGB之和小于600判定为按钮像素 int sumRGB = picture[x][y].getR() + picture[x][y].getG() + picture[x][y].getB(); return sumRGB < 600; } // 四连通域递归搜索,更新当前按钮的边界值 void dfsSearch(int x, int y) { if (!isButtonPixel(x, y)) return; // 标记为已处理避免重复搜索 picture[x][y].setexclude(true); // 更新边界坐标 xmin = min(xmin, x); xmax = max(xmax, x); ymin = min(ymin, y); ymax = max(ymax, y); // 按要求搜索四方向连通像素 dfsSearch(x - 1, y); dfsSearch(x + 1, y); dfsSearch(x, y - 1); dfsSearch(x, y + 1); } //--------------- methods for the pixel_class ------------ void pixel_class::loaddata(int v1, int v2, int v3) { red = v1; green = v2; blue = v3; } void pixel_class::datatofile(fstream & ppmfile) { // write the data for one pixel to the ppm file ppmfile << red << " " << green; ppmfile << " " << blue << " "; }
注意事项
如果你的按钮和背景色差和默认判断逻辑不符,修改isButtonPixel函数里的RGB判定规则即可。
内容的提问来源于stack exchange,提问作者DiFFt HD
相关产品推荐
相关产品推荐

