在使用OpenCV中的imread()加载图像时,如何捕获损坏的JPEG文件?

25
OpenCV说类似于:
Corrupt JPEG data: premature end of data segment
或者
Corrupt JPEG data: bad Huffman code
或者
Corrupt JPEG data: 22 extraneous bytes before marker 0xd9

当使用imread()加载一个损坏的JPEG图像时,我是否能够捕捉到这个错误?如果不能,那么我该如何得到这个信息?我是否需要自己检查二进制文件?


1
你好,你有解决这个问题的方案吗?我也在使用OpenCV时遇到了这个问题。谢谢! - Bahramdun Adil
用户可能也有兴趣阅读此处的帖子 - jdhao
10个回答

11

OpenCV(2.4版本)未覆盖libjpeg的基本错误处理,使其“无法捕获”。请在modules/highgui/src/grfmt_jpeg.cpperror_exit()定义下方添加以下方法:

METHODDEF(void)
output_message( j_common_ptr cinfo )
{
    char buffer[JMSG_LENGTH_MAX];

    /* Create the message */
    (*cinfo->err->format_message) (cinfo, buffer);

    /* Default OpenCV error handling instead of print */
    CV_Error(CV_StsError, buffer);
}

现在将该方法应用于解码器错误处理程序:
state->cinfo.err = jpeg_std_error(&state->jerr.pub);
state->jerr.pub.error_exit = error_exit;
state->jerr.pub.output_message = output_message; /* Add this line */

将该方法同样应用于编码器错误处理程序:

cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = error_exit;
jerr.pub.output_message = output_message; /* Add this line */

重新编译并像往常一样安装OpenCV。从现在开始,您应该能够像其他任何OpenCV错误一样捕获libjpeg错误。例如:
>>> cv2.imread("/var/opencv/bad_image.jpg")
OpenCV Error: Unspecified error (Corrupt JPEG data: 1137 extraneous bytes before marker 0xc4) in output_message, file /var/opencv/opencv-2.4.9/modules/highgui/src/grfmt_jpeg.cpp, line 180
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
cv2.error: /var/opencv/opencv-2.4.9/modules/highgui/src/grfmt_jpeg.cpp:180: error: (-2) Corrupt JPEG data: 1137 extraneous bytes before marker 0xc4 in function output_message

我已经提交了一个拉取请求,但是被拒绝了,因为它会导致人们在没有异常捕获的情况下阅读图像时出现问题。

希望这能帮助仍在苦苦挣扎的任何人解决这个问题。祝好运。


5

修复文件中的错误可能比试图修复OpenCV的加载函数更容易。如果您正在使用Linux,可以使用ImageMagick对一组图像进行修复(通常已默认安装):

$ mogrify -set comment 'Image rewritten with ImageMagick' *.jpg

此命令更改文件的一个属性,而保留图像数据不变。然而,该图像被加载并重新保存,消除了导致损坏错误的额外信息。

如果需要更多关于ImageMagick的信息,可以访问他们的网站:http://www.imagemagick.org/script/index.php


虽然很难捕捉到错误,但至少我们可以通过这种方式消除错误信息。这是一个好的解决方案~ - jdhao

4

如果你使用imread(),就无法捕获它。然而,imread()调用了imdecode()函数。也许它会给你更多的反馈。为此,你需要自己将图像加载到内存中,然后调用解码器。

归根结底,你必须深入研究OpenCV源代码来解决你的问题。


2
是的..我就怕有人会告诉我这个 ;) - Ben
1
你有找到解决方法吗?我也遇到了同样的问题,非常感兴趣。 - joon
1
imdecode()没有提供有关libjpeg警告的任何反馈 - Aubin

2
我最近也遇到了这个问题,发现了以下解决方案。只需要在 $cv\modules\highgui\src\grfmt_jpeg.cpp 中编辑两处即可。
参考链接:http://artax.karlin.mff.cuni.cz/~isa_j1am/other/opencv/
--- opencv-1.0.0.orig/otherlibs/highgui/grfmt_jpeg.cpp  2006-10-16 13:02:49.000000000 +0200
+++ opencv-1.0.0/otherlibs/highgui/grfmt_jpeg.cpp   2007-08-11 09:10:28.000000000 +0200
@@ -181,7 +181,7 @@
             m_height = cinfo->image_height;
             m_iscolor = cinfo->num_components > 1;

-            result = true;
+            result = (cinfo->err->num_warnings == 0);
         }
     }

@@ -405,8 +405,9 @@
                         icvCvt_CMYK2Gray_8u_C4C1R( buffer[0], 0, data, 0, cvSize(m_width,1) );
                 }
             }
-            result = true;
+
             jpeg_finish_decompress( cinfo );
+            result = (cinfo->err->num_warnings == 0);
         }
     }

1
任何人看到这篇文章并阅读了这个答案。
我必须找到一个已损坏的图像文件。
这些网站可以帮助您损坏文件: 第一个和第三个网站没有太大用处。
第二个网站很有趣,因为我可以设置需要损坏的文件大小。
我在这里使用的OpenCV版本是3.4.0
我使用了普通的cv2.imread(fileLocation)fileLocation是已损坏图像文件的位置。
OpenCV对这里使用的所有损坏文件都没有显示任何错误消息。
当我尝试打印它们时,第一个和第三个网站只提供了一个文件,并且两者中都存储了None
第二个网站让我决定需要损坏的文件数量。
打印图像时,OpenCV消息为“Corruption%”。
4%:无
10%:无
25%:无
50%:无,“损坏的JPEG数据:标记0x4f之前的3个无关字节”
75%:无,“损坏的JPEG数据:标记0xb2之前的153个无关字节”
100%:“损坏的JPEG数据:标记0xc6之前的330个无关字节”,无。
我猜这里我们唯一需要进行的检查就是:
如果图像不为None: 执行你的代码,否则弹出一个错误。

1
我正在使用opencv python包读取一些图像,但遇到了这个错误消息。这个错误无法被Python捕获。但是,如果您想找出哪些图像已损坏而不必重新编译opencv,可以尝试以下方法。
首先,您可以很容易地确定损坏的图像所在的目录。然后,转到该目录,并使用ImageMagick提供的mogrify命令行工具更改图像元信息,正如@goe所建议的那样。
mogrify -set comment "errors fixed in meta info" -format png *.jpg

上述命令将把原始的jpg图像转换为png格式,并清除原始图像中的元信息错误。当您运行 mogrify 命令时,它还会输出有关目录中哪个图像损坏的一些消息,以便您可以准确地找到损坏的图像。
之后,您可以随意处理原始损坏的jpg图像。

0

您可以将stderr重定向到文件中,然后在imread之后,在该文件中搜索字符串“Huffman”。搜索完毕后,请清空该文件。这对我很有效,现在我能够丢弃损坏的图像并处理好的图像。


0

我发现问题出在libjpeg上。如果OpenCV使用它,就会出错。

损坏的JPEG数据:标记0xd9之前有22个多余字节

你可以尝试我的解决方案来解决它。它在编译期间禁用了JPEG。之后OpenCV无法读写JPEG,但它仍然可以工作。

cmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=/usr/local -D BUILD_SHARED_LIBS=OFF -D BUILD_EXAMPLES=OFF -D BUILD_TESTS=OFF -D BUILD_PERF_TESTS=OFF -D WITH_JPEG=OFF -D WITH_IPP=OFF  ..

你应该在这里发布你的解决方案,而不是指向其他地方的用户。链接用于提供更多信息。 - jdhao

0

我找到了一个简单的解决方案,无需重新编译openCV。您可以使用imagemagick来检测相同的错误,但是它会像预期的那样返回一个错误。请参见此处的说明:https://dev59.com/hYrda4cB1Zd3GeqPRtnx#66283167


0
如果您使用imdecode加载图像,可以检查errno:
  std::vector<char> datas();
  //Load yout image in datas here
  errno = 0;
  cv::Mat mat = cv::imdecode(datas, -1);
  if (errno != 0)
  {
    //Error
  }

(在 OpenCV 3.4.1 上测试过)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接