在线笔试中遇到的简单图像内容识别问题

1 问题

1.1 问题描述

  给定一幅点阵图像,其中仅含有大写字母“M”和“S”,要求图像中两种字母的个数。注意,图像中的字母可能尺寸不同及存在旋转。

1.2 输入说明

  输入的第一行所给定两个数分别是图像矩阵的高度(H)和宽度(W),之后的H行W列个字符则给出了图像。“.”表示空白,“#”表示字母像素。
  图像中字符的说明:
  1)字母所采用的字体实际上是微软雅黑
  2)每个字母至少包含20个像素
  3)字母间的像素距离不小于2

50 50
..................................................
..................................................
..........................................#.......
............................###..........##.......
.......##..................##.##........#.........
.......##..................#...........##.........
......###.......#..........#...........##.........
......####.....###.........###..........######....
......#.##.....###..........####..............#...
......#.##....####............##..............#...
.....##..#...##.#..........#...#.............##...
.....##..#..##.##..........#####...........##.....
.....#...#.##..##.................................
.....#...###...#..................................
.....#...###...#..................................
.........##...##......................##..........
..............##.....##..............###..........
....................###............###............
...................###.............##.............
..................###.............##..............
.................###..............##..............
................###......###.......########.......
...............###.....#####........########......
..............###...########...............##.....
.............###..#####..##................##.....
............########....###................##.....
...........#######......##.....##.........###.....
............###.........##....###.......####......
.......................###...###.......###........
.......#...............##...###...................
.....####.............###..###....................
...######.............##..###.....................
..####................######......................
..###................######.......................
.###.................#####.......##...............
.###................#####........######...........
.###.................###.........##########.......
..##########.......................##...####......
..############......................##............
....###########......................###..........
.............##.......................###.........
.............###.......................###........
.............###...................#######........
.............##................########...........
............###................####...............
..........####..................######............
.......######......................######.........
.......###.............................##.........
..................................................
..................................................

1.3 输出要求

  要求输出两个整数,分表表示给定图像中“M”和“S”字母的数量。例如对于上述输入图像,样例输出为:

3 4

2 分析

(1)遍历所有像素,并利用洪泛法进行像素填充从而分离出不同的字母(应该用8-邻域,这点可以从范例输入中推断出),不同的字母中填充不同数字,背景填充0,对范例图像的填充结果如下:

00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000010000000
00000000000000000000000000002220000000000110000000
00000003300000000000000000022022000000001000000000
00000003300000000000000000020000000000011000000000
00000033300000003000000000020000000000011000000000
00000033330000033300000000022200000000001111110000
00000030330000033300000000002222000000000000001000
00000030330000333300000000000022000000000000001000
00000330030003303000000000020002000000000000011000
00000330030033033000000000022222000000000001100000
00000300030330033000000000000000000000000000000000
00000300033300030000000000000000000000000000000000
00000300033300030000000000000000000000000000000000
00000000033000330000000000000000000000440000000000
00000000000000330000055000000000000004440000000000
00000000000000000000555000000000000444000000000000
00000000000000000005550000000000000440000000000000
00000000000000000055500000000000004400000000000000
00000000000000000555000000000000004400000000000000
00000000000000005550000005550000000444444440000000
00000000000000055500000555550000000044444444000000
00000000000000555000555555550000000000000004400000
00000000000005550055555005500000000000000004400000
00000000000055555555000055500000000000000004400000
00000000000555555500000055000005500000000044400000
00000000000055500000000055000055500000004444000000
00000000000000000000000555000555000000044400000000
00000006000000000000000550005550000000000000000000
00000666600000000000005550055500000000000000000000
00066666600000000000005500555000000000000000000000
00666600000000000000005555550000000000000000000000
00666000000000000000055555500000000000000000000000
06660000000000000000055555000000077000000000000000
06660000000000000000555550000000077777700000000000
06660000000000000000055500000000077777777770000000
00666666666600000000000000000000000770007777000000
00666666666666000000000000000000000077000000000000
00006666666666600000000000000000000007770000000000
00000000000006600000000000000000000000777000000000
00000000000006660000000000000000000000077700000000
00000000000006660000000000000000000777777700000000
00000000000006600000000000000007777777700000000000
00000000000066600000000000000007777000000000000000
00000000006666000000000000000000777777000000000000
00000006666660000000000000000000000777777000000000
00000006660000000000000000000000000000077000000000
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000

(2)依次计算每个分离出来的字母的中心位置。由于字母S图像的中心位置处于字母笔画上,因此,是有像素的;而字母M图像的中心位置处于空白位置处。据此判断
(3)根据(2)的判断结果进行计数即可得到结果。

3 代码

#include <iostream>
#include <queue>
#include <algorithm>
#include <math.h>

using namespace std;

int N, M;
int image[501][501];
int mark[501][501];

void floodfill(int n, int m, int mark_number) {
    if (n<0 || m<0 || mark[n][m]!=-1) return;
    mark[n][m] = mark_number;
    floodfill(n-1, m, mark_number);
    floodfill(n+1, m, mark_number);
    floodfill(n, m-1, mark_number);
    floodfill(n, m+1, mark_number);

    floodfill(n-1, m-1, mark_number);
    floodfill(n-1, m+1, mark_number);
    floodfill(n+1, m-1, mark_number);
    floodfill(n+1, m+1, mark_number);
}

int judge(int mark_number) {
    double total_n=0, total_m=0, count=0;
    for (int n=0; n<N; n++) {
        for (int m=0; m<M; m++) {
            if (mark[n][m] != mark_number) continue;
            total_n += n;
            total_m += m;
            count++;
        }
    }
    return mark[(int)round(total_n/count)][(int)round(total_m/count)];
}

int main(void) {
    cin >> N >> M;


    //input
    for (int n=0; n<N; n++) {
        char temp[501];
        cin >> temp;
        for (int m=0; m<M; m++) {
            image[n][m] = (temp[m] == '#');
            mark[n][m] = (temp[m] == '.' ? 0 : -1); //-1是未检查,0是背景,之后顺次1,2,3...
        }
    }

    //flood fill to find all
    int mark_number = 1;
    for (int n=0; n<N; n++) {
        for (int m=0; m<M; m++) {
            if (mark[n][m] == -1) {
                floodfill(n, m, mark_number);
                mark_number++;
            }
        }
    }
    /*for (int n=0; n<N; n++) {
        for (int m=0; m<M; m++) {
            cout << mark[n][m];
        }
        cout << endl;
    }*/

    int count_m=0, count_s=0;
    for (int i=1; i<mark_number; i++) {
        if (judge(i) == 0) {
            count_m++;
        } else {
            count_s++;
        }
    }

    cout << count_m << " " << count_s << endl;

    return 0;
}

4 后记

  所给出的方法思路比较简洁,代码量也小,比较适合实际笔试,实际运行结果得到了90%的case通过率。可以再想想如何提高。

猜你喜欢

转载自blog.csdn.net/solomonlangrui/article/details/52795323