OpenCV 读取图片时警告 Premature end of JPEG file

在用 OpenCV 批量处理图片时,出现了题目所示的警告,直接翻译就是“JPEG 文件过早地结束”。这说明该批图片中存在不完整的文件。一般是由于拷贝、下载不完整造成的。遇到这种情况,首先要定位到底是哪个文件出了问题,然后再修改它。

定位文件

1
2
3
4
5
def check(path):
with open(path, 'rb') as f:
f.seek(-2,2)
if f.read() != '\xff\xd9':
print path

其中 fileObject.seek() 函数,用于定位指针在文件中的位置。

调用方法为:fileObject.seek(offset[, whence])

它包含两个参数:

  • offset 需要偏移的字节数,必要参数
  • whence 从哪个位置开始偏移,默认为 0,代表从文件开头开始算起,1 代表从当前位置开始算起,2 代表从文件末尾算起。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# test.txt contents:
# ABCDE
>>> f = open(r'test.txt')
>>> f.seek(3) # 从开头偏移三个字节
>>> f.read() # 偏移 3 个字节后开始读取文件
'DE'
>>> f = open(r'test.txt')
>>> f.seek(2) # 从文件开头偏移 2 个字节
>>> f.seek(2, 1) # 第二个参数是1,因此是基于上面的偏移继续偏移 2 个字节,因此当前指针位置在第四个字节
>>> f.read() # 从第四个字节开始读(不包括第四个字节),所以读到第五个字节
'E'
>>> f = open(r'test.txt')
>>> f.seek(-3, 2) # 第二个参数是 2,表示从文件末尾开始偏移,向前偏移 3 个字节
>>> f.read() # 从倒数第三个字节开始读(包括倒数第三个字节)
'CDE'

掌握了这个函数,再回过头理解之前检验 JPEG 文件的代码。其原理就是,检验二进制图片文件末尾两个字节的编码,看它是否为 “\xff\xd9”,如果不是,说明这个图片文件是不完整的。

修改文件

找到这个不完整的文件,用 opencv 读取,然后显示它,发现它确实有部分残缺,修改方法很简单,用 opencv 重新写入文件即可。该操作并不能真正修复缺失的图片信息,但是可以强制给不完整的图片加上结尾编码,使程序不再出现警告。