在線筆試中遇到的簡單圖像內容識別問題

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通過率。可以再想想如何提高。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章