【问题标题】:pattern recognition in a matrix矩阵中的模式识别
【发布时间】:2011-07-06 14:48:48
【问题描述】:

我不确定我给这个命名是否正确,但无论如何我有一个基本上包含 1 或 0 的矩阵。矩阵是方阵,其大小可以是 3x3、4x4 或 5x5。

通过模式匹配,我的意思是在我的矩阵中找到一些“形状”,例如线条、T 或 U,例如:
0 1 0
0 1 0
1 1 1

该矩阵包含一个 T,但它也包含 2 行!现在,如果矩阵是 4x4,形状不会增加,但它们可以明显定位在更多位置,例如: 0 0 0 0
1 1 1 0
0 0 1 0
1 1 1 0

该矩阵将包含一个 U(虽然没有线,但这是一个例外,线具有矩阵的大小)。

天真地因为矩阵很小,我会尝试所有我愿意支持的形状的所有可能性,但这并不是很有趣。不过,我无法找出任何算法,并且无法正确标记此操作无济于事 ;)

有没有人知道如何“有效”地做到这一点? (考虑到矩阵的大小,实际上可能有点夸大其词,但你知道我的意思)。

【问题讨论】:

    标签: objective-c matrix


    【解决方案1】:

    您的问题有些模棱两可。例如,是否:

    1 1 1
    1 1 1
    1 1 1
    

    包含 6 行、一个 T、一个 U 和一堆其他字母?还是所有字母都分开?您最初的问题暗示可以以重叠的方式发现字母,因为 T 模板包含两行。因此,所有元素都“打开”的矩阵将在每个可能的位置包含每个可能的字母/行。

    另外,我假设您只关心 90 度旋转,并且当矩阵大小足够大以支持它时,您不希望尝试找到 45 度偏移字母。

    就易于实施而言,我想说的是,您所说的蛮力方法(测试所有四个字母旋转的每个位置)确实胜出。

    或者,您可以通过(警告:前面的算法描述模糊!):

    1) 沿着矩阵元素走,直到找到 1。然后基本上从堆栈中的 1 填充并跟踪方向变化。然后进行某种旋转不变查找,将一组“on”像素映射到找到的字母。

    2) 使用某种积分图像或框过滤器描述来获取矩阵子部分的总和。然后,您可以对小节进行查找并将小节总和映射到字母/行值。

    3) 由于 cmets 已确定您实际上只是在寻找 4 个形状,因此可能值得采用一种新方法。如果我没记错的话,你只检查 4 种形状(线、十字、T 和 U)。它们中的每一个都可以有 4 个方向。一个快速提示是,您可以只运行算法 4 次,但将底层矩阵旋转 90 度。然后你不必在你的算法中调整旋转。还要注意,十字只需要在一个方向上找到,因为它在所有 4 个方向上看起来都相同,而线在两个方向上是相同的。无论如何,您可以通过首先搜索“最难”的东西来节省一些工作。假设我在这里寻找一个直立的“U”:

    1 0 1
    1 0 1 
    1 1 1
    

    我从左上角开始。我没有检查以确保任何像素都“关闭”(或 0),而是转到下一个我希望找到“打开”值(或 1)的地方。假设这是左上角下方的像素。我检查了左中像素,确实它打开了。然后我在下面检查。如果您为每个字母开发了一个简单的规则集,如果您没有“打开”所需的值,您可以快速放弃对它的搜索。如果您随后运行相同的算法 4 次并且只搜索正值,我不确定您是否能做得比这更好!

    我提到的方法只是想法。不过,就效率提升而言,它们可能带来的麻烦多于其价值。谁知道呢,它们可能根本不起作用!

    祝你好运!

    【讨论】:

    • 是的,您提供的矩阵将包含所有内容。我确实只对 90 度旋转感兴趣。很抱歉造成混乱;)支持的东西真的很少,它们是交叉、线、T 和 U。我想我会采用蛮力方法;)感谢您的反馈!
    • 我只是在阅读您的答案时想到了一些东西,我不确定您的第二个算法想法是什么意思。我可以为矩阵(例如它们的索引)中“启用”的每个位置(即它将具有 1 的位置)分配一个数字,而不是使用 0 和 1,然后我可以存储获得一条线所需的总和,与所有形状相同,然后遍历矩阵,对所有元素求和并在我的数组中查找。不幸的是,我认为很难获得唯一值,就像我有一个从左上到右下的 3x3 矩阵中的数字 1 到 9 的矩阵 --> 几个 15 秒
    • 是的,这就是我使用第二种方法的目的。我将其视为计算机视觉问题,因为图像只是计算机的大矩阵。但是,是的,问题是你会有多余的总和,你必须做一些额外的处理来确定它是哪个字母。我将用另一种方法编辑我的原始答案。
    【解决方案2】:

    按照 aardvarkk 的想法,我想我可以为我最终做的事情做出贡献。 (objective-c 代码)我对数组大小检查不是很迂腐,因为我的矩阵必须是方阵。如果代码很丑也很抱歉:D

    我为要重新识别的形状创建了一个小类结构,它们有一个“方向”列表,这些“方向”本质上是枚举的值。

    -(BOOL)findShape:(NSInteger)size directions:(NSArray*)directions{
        NSMutableArray* current = [mgs tokens];
        for (int rot = 0; rot < 4; rot++) {
            for (int i = 0; i < size; i++) {
                for(int j = 0; j < size; j++){
                    NSInteger value = [[[current objectAtIndex:i] objectAtIndex:j] integerValue];
                    if(value){
                        BOOL carryOn = [self iterateThroughDirections:directions i:i j:j tokens:current size:size];
                        if(carryOn){
                            return YES;
                        }
                    }
                }
            }
            current = [self rotate:current];
        }
        return NO;
    }
    
    
    -(BOOL) iterateThroughDirections:(NSArray*)directions i:(NSInteger)i j:(NSInteger)j tokens:(NSMutableArray*)tokens size:(NSInteger)size{
        BOOL carryOn = YES;
        for(int k = 0; k < [directions count] && carryOn; k++){
            NSNumber* dir = [directions objectAtIndex:k];
            NSInteger d = [dir integerValue];
            //move in the direction
            switch (d) {
                case UP:
                    if(i > 0){
                        i--;
                    }else{
                        carryOn = NO;
                    }
                    break;
                case DOWN:
                    if(i < size-1){
                        i++;
                    }else{
                        carryOn = NO;
                    }
                    break;
                case LEFT:
                    if(j > 0){
                        j--;
                    }else{
                        carryOn = NO;
                    }
                    break;
                case RIGHT:
                    if(j < size-1){
                        j++;
                    }else{
                        carryOn = NO;
                    }
                    break;
                default:
                    NSAssert(NO, @"invalid direction");
                    break;
            }
            NSInteger v = [[[tokens objectAtIndex:i] objectAtIndex:j] integerValue];
            //now that we moved, check if the token is active, if it's not we're done
            if(!v){
                carryOn = NO;
                break;
            }
        }
        return carryOn;
    }
    
    -(NSMutableArray*)rotate:(NSMutableArray*)matrix{
        NSInteger w = [matrix count];
        NSInteger h = [[matrix objectAtIndex:0] count];
        NSMutableArray* rotated = [[NSMutableArray arrayWithCapacity:h] retain];
        for (int i = 0; i < h; i++) {
            [rotated addObject:[NSMutableArray arrayWithCapacity:w]];
        }
        for(int i = 0; i < h; ++i){
            for(int j = 0; j < w; ++j){
                [[rotated objectAtIndex:i] addObject:[[matrix objectAtIndex:j] objectAtIndex:h-i-1]];
            }
        }
    
        return rotated;
    }
    

    这似乎对我很有效!再次感谢您的帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-01-16
      • 1970-01-01
      • 2021-03-02
      • 2023-04-09
      • 2013-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多