在做图像识别的课题时,我遇到了一个问题,需要按照使用slic算法计算后输出的数组对于某一张图片进行切分,因此需要使用一个字典来记录每个色块对应的范围。

字典对应的形式如下,其中key对应的是slic算法输出的每一个颜色块的index,value代表了[most_top, most_bottom, most_left, most_right]

1
{1:[1, 5, 3, 4]}

分别记录了每个颜色块的上下左右边界,需要按照下述方式进行初始化。

1
2
3
4
most_top = image_height  # 最上边界:设置为最下面
most_bottom = 0 # 最下边界:设置为最上面
most_left = image_width # 最左边界:设置为最右边
most_right = 0 # 最右边界:设置为最左边

因此对于字典也需要初始化,每个字典的keys值分别对应slic输出的数组中每一个index值,value为按照上述方式进行初始化的结果。

为了实现这个,我google到了这篇文章:python 字典初始化方法 全!!!

在这篇文章中我发现了一个最适合当前场景的方法,便是使用dict.fromkeys方法,于是照猫画虎,我对于自己这个需求写出了如下代码

1
2
len_color = len(Counter(segments.reshape(-1)))  # 统计数组中的类别个数
color_dic = dict.fromkeys([x for x in range(1, len_color + 1)], [most_top, most_bottom, most_left, most_right])

这里的segments为使用slic算法输出的结果。

看似上面的代码完美无缺对不对(这只抹茶好不要脸哦!)

然后在运行的时候我遇到了一个问题,那便是图像并没有按照预想的按照每一个颜色块的大小进行分割,而是输出了每张图的原图。

在认真检查过代码的逻辑之后,我觉得我可以99%地保证自己的代码逻辑没有任何问题。因为我实在是无法检查出来任何问题了。

于是这个时候只有祭出那个大法了,也就是IDE的Debug功能,虽然是第一次使用pycharm的debug功能,不过有着vs的debug经验,具体方法是大同小异的,所以也很快就进入状态了。

在debug的时候,经过我反复的操作,我突然发现1号色块的对应字典的value中即使是已经超出边界行,其value中的边界值仍然处于增加状态,这个时候我就非常的好奇,最初认为自己是哪里没有看到,于是就调出了segments来看,结果发现我自己并没有判断错误,在我反复的使用print大法来断定之后我仍然没有找到任何一点问题。

索性放弃,吃过晚饭后,我突然想起来看一下编译器下面debug时候一个没有在意的地方,也就是那个字典。将字典展开之后,我突然发现一件事情,字典中的所有value每一个里面的list的值都是相同的,最初因为色块相邻,所以没有在意这个问题。

当我再仔细看的时候,发现每一个value上面都标着了一个list4,最初我认为这个4代表的是每一个list中有四个元素,后来看了其他地方的标志我才意识到这个list的标志并非代表的4个元素,而是系统自动为每一个变量标记的名称,也就是说,这一个字典中的所有value中的list在底层都是同一个list的引用,大概用c语言的话来说,就是我用字典存储了若干份这个list的指针,然后无论哪一个色块进行改变的时候都会改变这唯一一个list,所以在后期循环字典切割图片的时候,每一个对应色块其实访问的都是一整张图片所对应的范围,所以每张图片才会输出成为原图的样子。

于是在反复经过试验之后,我尝试了下述代码

1、list转换法

1
color_dic = dict.fromkeys([x for x in range(1, len_color + 1)], list([most_top, most_bottom, most_left, most_right]))

2、元组法

1
color_dic = dict.fromkeys([x for x in range(1, len_color + 1)], (most_top, most_bottom, most_left, most_right))

3、元组+list转换法

1
color_dic = dict.fromkeys([x for x in range(1, len_color + 1)], list((most_top, most_bottom, most_left, most_right)))

结果在实验的时候发现,无论哪一个都以失败告终,这下我终于明白了究竟是哪里的问题。

这样写的话,字典中每一个value对应的都是第二个参数中的这个值,每个都是一个引用。应该摒弃掉这个方法,使用普通的循环就可以解决的!

也就是下面这段代码

1
2
for x in range(1, len_color + 1):
color_dic[x] = [most_top, most_bottom, most_left, most_right]

这样的话,每个key对应的value都是一个新的list,就不会再出现这种问题了。

case closed!(没事学什么福尔摩斯啊,掟上今日子看多了啊喂!)