使用R语言中的jpeg软件包检测无效或损坏的jpg文件

3
我想使用jpeg包(或类似的包)来检测损坏的.jpg文件。我将与安装exiftool有问题的用户共享此代码,因此我希望使用不需要该程序的包。
我希望我的代码能够捕捉到完全损坏或部分损坏的图像(即,您可以看到图像的一部分,但其中一部分被切断)。
当图像损坏时,readJPEG函数会返回:
Error in readJPEG(photos[35]) : 
  JPEG decompression error: Not a JPEG file: starts with 0x7b 0x28

当图像部分损坏时,该函数返回:
JPEG decompression: Corrupt JPEG data: premature end of data segment

我想编写一个函数,如果图像“好”则返回FALSE,如果它是损坏或部分损坏的,则返回TRUE。到目前为止,如果图像是部分损坏的,我的函数无法正常工作(它会返回FALSE)。我做错了什么?

这是一个“部分损坏”的图像示例 - 当它被传输到新设备时,底部被切掉了一半。

library(jpeg)

    # Function to "catch" bad photos
is_corrupted <- function(x){
  tryCatch({
    check <- readJPEG(x)
    return(FALSE)
    },
    error = function(e)
      return(TRUE),
    warning = function(w)
      return(TRUE),
    message = function(m)
      return(TRUE)
    )
}

编辑: 尝试第二次...

我基于Ben的建议创建了一个修改后的函数,但是如果图像完全损坏,它仍然不会返回TRUE。 我也不喜欢它如何对照片进行两次测试。 任何建议都将不胜感激!

要测试该功能,您可以使用三个jpg文件... (1) 从计算机中选择任何有效的jpg文件,(2) 部分损坏的文件链接在这个问题中,以及(3) 引用一个不存在的文件以引发一个错误,该错误将被tryCatch 捕获(例如is_corrupted(""))。

is_corrupted <- function(x){
message <- capture.output(check2 <- readJPEG(x), type = "message")
if(length(message) > 0) {
  corrupt <- TRUE
} else {
corrupt <- tryCatch({
    check <- readJPEG(x)
    return(FALSE)
  },
  error = function(e) # catch "corrupt" images
    return(TRUE)
  ) 
}
return(corrupt)
}

部分损坏文件的返回行看起来像是一个“消息”,而不是一个“警告”。您可以尝试在is_corrupted内替换“警告”为“消息”。 - Ben Nutzer
谢谢@BenNutzer!我确实尝试过了 - 没有成功,但还是感谢你的建议:( 我会编辑函数,让大家知道这也不行。 - Nova
我使用 purrr::quietly(readJPEG) 测试了你的方法,封装后的函数没有返回任何消息或警告。我的猜测是这可能与底层的 .Call 调用另一个函数有关。一种解决方法是使用 capture.out(readJPEG(x), type = "message") 并对输出进行评估。我的结论是:你的代码没问题,只是不能正常工作。也许其他人可以确认/驳斥这一点。 - Ben Nutzer
我又试了一次,但是无法使它工作,而且我觉得我可能漏掉了某些非常简单的东西。你能看一下吗? - Nova
1个回答

1

我同意,这个比较棘手。我认为你需要在捕获部分之前进行错误检查。我会发布一个临时的(丑陋的)解决方案,希望其他人能够发布更优雅和直接的方法。

readJPEG2 <- purrr::safely(readJPEG)

purrr 进行错误检查,如果没有错误,则继续检查输出内容。
fun <- function(x){
          if(is.null(readJPEG2(x)$error)){
                    message2 <- capture.output(readJPEG(x), type = "message")
                    if(length(message2) > 0){
                              return("partially corrupted")
                    } else {
                              return("complete")
                    }
          } else {
                    return("corrupted")
          }

}

我不知道这个解决方案有多可靠,但或许它仍能对你有所帮助。


丑陋或不美观,但它绝对有效(谢谢!!!):P 你知道如何停止它写入消息“JPEG解压缩:损坏的JPEG数据:数据段过早结束”(例如“quietly = TRUE”选项)吗? - Nova
很高兴你觉得它有帮助!我也试图抑制消息,但失败了(suppressMessages)。我认为这是导致你的代码无法正常工作的相同问题。 - Ben Nutzer
我在Simon的gitHub页面上添加了一个问题(jpeg的作者)。如果有任何更改,我会在这里更新。 - Nova

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