前一段时间帮别人做项目,这个题目是数码管识别,这个最简单的办法就是准备图片,放到SVM中训练,就会得到不错的效果,但是,我想起以前做过这个项目,当时还没接触机器学习,用的是传统方法识别的。主要思想就是三次扫描一个数目管,判断他的7个发光二极管的亮灭,就可以识别出结果,但当时由于获取到的数码管图像太小,误识别很高,就放弃了,不过现在这个题目得到的图片大,清楚,不容易误识别,就可以用这个方法识别,顺便复习一下当时的思路和算法。
采用三次扫描法,可以实现数码管数字的识别,识别方法的思想也简单: 第一次:扫描五号位置和一号位置 第二次:扫描四号位置和二号位置 第三次:扫描零号位置和六号位置三号位置
主要思路如图所示:
扫描结束后,会得到一个码表,比如数字二,它的编码为 0 1 0 1 1 0 1 1,转换为十六进制为0x5b,得到编码之后,就可以查表,识别数字。
下面给出一个可以运行的demo,大家可以运行一下,看下效果(前提配置好OpenCV的C++环境)。
链接:https://download.csdn.net/download/qq_36327203/11221814
效果截图:
这种方法的代码实现如下:
//2 3 4 5 6 7 8 9 0 static unsigned char model_num2[9] = { 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x47, 0x7f, 0x6f, 0x3f }; int match_num(Mat &img) { // 6 5 4 3 2 1 0 //2 0x5b 1 0 1 1 0 1 1 //3 0x4f 1 0 0 1 1 1 1 //4 0x66 1 1 0 0 1 1 0 //5 0x6d 1 1 0 1 1 0 1 //6 0x7d 1 1 1 1 1 0 1 //7 0x47 0 1 0 0 1 1 1 0x07 //8 0x7f 1 1 1 1 1 1 1 //9 0x6f 1 1 0 1 1 1 1 //0 0x3f 0 1 1 1 1 1 1 //2 3 4 5 6 7 8 9 0 //unsigned char model_num2[9] = { 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x47, 0x7f, 0x6f, 0x3f }; Mat img_temp = img.clone(); /* ---------------------00000------------------------- --------------------5-----1------------------------ --------------------5-----1------------------------ ---------------------66666------------------------- --------------------4-----2------------------------ --------------------4-----2------------------------ ---------------------33333------------------------- */ rectangle(img_temp, Rect(0, 0, img_temp.cols, img_temp.rows), Scalar(0), 1); //处理边界 int y1 = img_temp.rows >> 2; //y方向1/4处 int y2 = (img_temp.rows >> 2) * 3;; //y方向3/4处 int xx = img_temp.cols >> 1; //x方向1/2处 int yy = img_temp.rows >> 1; //x方向1/2处 unsigned char temp_value = 0; //识别到1 if ((double)img.rows / (double)img.cols > 2.5) return 1; //两条横线检测遍历 for (int y = y1; y < img_temp.rows; y += (y1 * 2)) { uchar *pp = img_temp.ptr<uchar>(y); for (int x = 0; x < img_temp.cols - 1; x++) { if (pp[x] == 0) { if (pp[x + 1] == 255) { if (x < xx && y < yy) temp_value |= (0x01 << 5); if (x > xx && y < yy) temp_value |= (0x01 << 1); if (x < xx && y > yy) temp_value |= (0x01 << 4); if (x > xx && y > yy) temp_value |= (0x01 << 2); } } } } //一条竖线检测遍历 for (int y = 0; y < img_temp.rows - 1; y++) { uchar *pp = img_temp.ptr<uchar>(y); if (pp[xx] == 0) { if (pp[xx + img_temp.step] == 255) { if (y < y1) temp_value |= (0x01 << 0); if (y > y2) temp_value |= (0x01 << 3); if (y > y1 && y < y2) temp_value |= (0x01 << 6); } } } //查表匹配 for (int model_i = 0; model_i < 9; model_i++) { if (temp_value == model_num2[model_i]) { if (model_i == 8) return 0; //0为特殊情况 else return model_i + 2; } } return -1; }图形必须预处理好,不能有其他明显的噪声。 这种方法是基于擦混同方法识别的,稳定性方面不好,复杂环境下效果不好。