确定图像是不是是序列的一部分的最佳方法是啥

Posted

技术标签:

【中文标题】确定图像是不是是序列的一部分的最佳方法是啥【英文标题】:Whats the best way of determining if an image is part of a sequence确定图像是否是序列的一部分的最佳方法是什么 【发布时间】:2012-08-07 23:56:58 【问题描述】:

我有一个图像文件,我想使用 python 检查它是否是图像序列的一部分。

例如我从这个文件开始:

/projects/image_0001.jpg

我想检查文件是否是序列的一部分,即

/projects/image_0001.jpg
/projects/image_0002.jpg
/projects/image_0003.jpg
...

如果我可以确定文件名是否可以是序列的艺术,即是否存在文件名的数字序列,则检查是否存在图像序列似乎很简单

我的第一个想法是要求用户将#### 添加到数字应该在的文件路径中,并输入一个开始和结束帧号来替换散列,但这显然不是很用户友好。有没有办法用正则表达式或类似的东西检查字符串中的数字序列?

【问题讨论】:

什么是图像序列?能举个例子吗? 所有文件名都是某种形式的picture_xxxx,还是混入了旧文件名? 可能是 pic.xxxx.jpg 或 pic-xxx.jpg 等。我想让脚本尽可能灵活,以适应不同的人的喜好 【参考方案1】:

我假设问题更多在于能够区分磁盘上的排序文件,而不是了解有关文件名本身的任何特定信息。

如果是这样,并且您正在寻找的是足够聪明的东西,可以列出如下列表:

/path/to/file_1.png /path/to/file_2.png /path/to/file_3.png ... /path/to/file_10.png /path/to/image_1.png /path/to/image_2.png ... /path/to/image_10.png

然后得到一个结果说 - 我有 2 个文件序列:/path/to/file_#.png 和 /path/to/image_#.png 你将需要 2 次通过 - 第一次通过来确定有效的表达式对于文件,第二次通过找出所有其他文件满足该要求。

您还需要知道是否要支持间隙(是否需要连续)

/path/to/file_1.png /path/to/file_2.png /path/to/file_3.png /path/to/file_5.png /path/to/file_6.png /path/to/file_7.png

这是 1 个序列 (/path/to/file_#.png) 还是 2 个序列 (/path/to/file_1-3.png, /path/to/file_5-7.png)

另外 - 你想如何处理序列中的数字文件?

/path/to/file2_1.png /path/to/file2_2.png /path/to/file2_3.png

等等

考虑到这一点,我将这样做:

    import os.path
    import projex.sorting
    import re

    def find_sequences( filenames ):
        """
        Parse a list of filenames into a dictionary of sequences.  Filenames not
        part of a sequence are returned in the None key

        :param      filenames | [<str>, ..]

        :return     <str> sequence: [<str> filename, ..], ..
        """
        local_filenames   = filenames[:]
        sequence_patterns = 
        sequences         = None: []

        # sort the files (by natural order) so we always generate a pattern
        # based on the first potential file in a sequence
        local_filenames.sort(projex.sorting.natural)

        # create the expression to determine if a sequence is possible
        # we are going to assume that its always going to be the 
        # last set of digits that makes a sequence, i.e.
        #
        #    test2_1.png
        #    test2_2.png
        #
        # test2 will be treated as part of the name
        # 
        #    test1.png
        #    test2.png
        #
        # whereas here the 1 and 2 are part of the sequence
        #
        # more advanced expressions would be needed to support
        # 
        #    test_01_2.png
        #    test_02_2.png
        #    test_03_2.png

        pattern_expr = re.compile('^(.*)(\d+)([^\d]*)$')

        # process the inputed files for sequences
        for filename in filenames:
            # first, check to see if this filename matches a sequence
            found = False
            for key, pattern in sequence_patterns.items():
                match = pattern.match(filename)
                if ( not match ):
                    continue

                sequences[key].append(filename)
                found = True
                break

            # if we've already been matched, then continue on
            if ( found ):
                continue

            # next, see if this filename should start a new sequence
            basename      = os.path.basename(filename)
            pattern_match = pattern_expr.match(basename)
            if ( pattern_match ):
                opts = (pattern_match.group(1), pattern_match.group(3))
                key  = '%s#%s' % opts

                # create a new pattern based on the filename
                sequence_pattern = re.compile('^%s\d+%s$' % opts)

                sequence_patterns[key] = sequence_pattern
                sequences[key] = [filename]
                continue

            # otherwise, add it to the list of non-sequences
            sequences[None].append(filename)

        # now that we have grouped everything, we'll merge back filenames
        # that were potential sequences, but only contain a single file to the
        # non-sequential list
        for key, filenames in sequences.items():
            if ( key is None or len(filenames) > 1 ):
                continue

            sequences.pop(key)
            sequences[None] += filenames

        return sequences

还有一个用法示例:

>>> test =   ['test1.png','test2.png','test3.png','test4.png','test2_1.png','test2_2.png','test2_3.png','test2_4.png']
>>> results = find_sequences(test)
>>> results.keys()
[None, 'test#.png', 'test2_#.png']

里面有一个方法是指自然排序,这是一个单独的话题。我刚刚使用了我的 projex 库中的自然排序方法。它是开源的,所以如果你想使用或查看它,它在这里:http://dev.projexsoftware.com/projects/projex

但是这个话题已经在论坛的其他地方讨论过了,所以就使用库中的方法。

【讨论】:

【参考方案2】:

使用 python 的re 模块来查看字符串是否包含数字序列相对容易。你可以这样做:

mo = re.findall('\d+', filename)

这将返回filename 中所有数字序列的列表。如果:

只有一个结果(即文件名只包含一个数字序列),AND 后续文件名具有相同长度的单个数字序列,AND 第二个数字序列比前一个大 1

...那么也许它们是序列的一部分。

【讨论】:

如果你需要知道数字在字符串中出现的位置,你可以使用:mo=list(re.finditer('\d+',filename)),它会返回一个匹配对象的列表,每个匹配对象都定义了mo[i].start()mo[i].end()的方法.要获取匹配对象之一的文本,请使用mo[i].group()。有关匹配对象的更多信息,请参阅docs.python.org/library/re.html#match-objects。

以上是关于确定图像是不是是序列的一部分的最佳方法是啥的主要内容,如果未能解决你的问题,请参考以下文章

使用 JSON 协议处理版本控制的最佳方法是啥?

将 UITapGestureRecognizer 添加到 UILabel 的特定部分的最佳方法是啥?

从 URLRequestConvertible 扩展时设置多部分请求的最佳方法是啥

Flutter:我是不是必须为我的应用程序的每个部分创建一个块?它的最佳做法是啥?

在运行时确定浏览器是不是太慢而无法优雅地处理复杂的 JavaScript/CSS 的最佳方法是啥?

使用部分索引元组列表对多索引数据帧进行切片的最佳方法是啥?