矩阵中的模式识别

时间:2011-07-06 14:48:48

标签: objective-c matrix

我不确定我是否给出了正确的名称,但无论如何我有一个基本上包含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(但没有行,这是例外,行具有矩阵的大小)。

因为矩阵非常小,我会尝试为每个我愿意支持的形状提供所有可能性,但这并不是很有趣。我无法弄清楚任何算法,但无法正确标记此操作没有帮助;)

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

2 个答案:

答案 0 :(得分:0)

你的问题有些含糊不清。例如,确实:

1 1 1
1 1 1
1 1 1

包含6行,T,U和一串其他字母?或者所有字母都分开了吗?您的初始问题暗示可以以重叠方式发现字母,因为T模板包含两行。因此,所有元素都在'on'的矩阵将包含每个可能位置中的每个可能的字母/行。

另外,我假设你只关心90度旋转,当矩阵大小足以支持它时,你不会想要找到45度偏移字母。

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

或者,您可能会非常喜欢(警告:前面的模糊算法描述!):

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

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

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

1 0 1
1 0 1 
1 1 1

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

我提到的方法只是想法。但是,就效率提升而言,它们可能比它们的价值更大。谁知道,他们可能根本不工作!

祝你好运!

答案 1 :(得分:0)

我认为我可以根据aardvarkk的想法为我最终做的事做出贡献。 (objective-c code)我对数组大小检查不是很迂腐,因为我的矩阵必然是一个方阵。如果代码很丑,也很抱歉: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;
}

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