C# Imagemagick:优化识别截断图像的速度

C# Imagemagick:优化识别截断图像的速度,c#,imagemagick,C#,Imagemagick,我正在使用imagemagick识别文件夹中被截断图像的过早结束。我编写的脚本成功地识别了图像,但是速度非常慢。这可能是因为它必须将整个图像加载到内存中,但考虑到我将文件复制到磁盘所花费的时间,这应该不会给操作增加超过几个小时的时间。我正在分析超过700000张图像,以目前的速度,操作将需要一个多月才能完成,更不用说极高的CPU使用率了 foreach (string f in files) { Tuple<int, string> result = ImageCorrupt

我正在使用imagemagick识别文件夹中被截断图像的过早结束。我编写的脚本成功地识别了图像,但是速度非常慢。这可能是因为它必须将整个图像加载到内存中,但考虑到我将文件复制到磁盘所花费的时间,这应该不会给操作增加超过几个小时的时间。我正在分析超过700000张图像,以目前的速度,操作将需要一个多月才能完成,更不用说极高的CPU使用率了

foreach (string f in files)
{
    Tuple<int, string> result = ImageCorrupt(f);
    int exitCode = result.Item1;
    if (exitCode != 0)...
}

public static Tuple<int, string> ImageCorrupt(string pathToImage)
{
    var cmd = "magick identify -regard-warnings -verbose  \"" + pathToImage + "\"";

    var startInfo = new ProcessStartInfo
    {
        WindowStyle = ProcessWindowStyle.Hidden,
        FileName = "cmd.exe",
        Arguments = "/C " + cmd,
        UseShellExecute = false,
        RedirectStandardOutput = true,
        RedirectStandardError = true
    };

    var process = new Process
    {
        StartInfo = startInfo
    };

    process.Start();
    string output = process.StandardOutput.ReadToEnd();

    if (!process.WaitForExit(30000))
    {
        process.Kill();
    }

    return Tuple.Create(process.ExitCode, process.StandardError.ReadToEnd());
}
foreach(文件中的字符串f)
{
元组结果=ImageCorrupt(f);
int exitCode=result.Item1;
如果(exitCode!=0)。。。
}
公共静态元组图像损坏(字符串路径图像)
{
var cmd=“magick identification-重视警告-详细\”“+pathToImage+”\”;
var startInfo=新流程startInfo
{
WindowsStyle=ProcessWindowsStyle.Hidden,
FileName=“cmd.exe”,
Arguments=“/C”+cmd,
UseShellExecute=false,
重定向标准输出=真,
重定向标准错误=true
};
var流程=新流程
{
StartInfo=StartInfo
};
process.Start();
字符串输出=process.StandardOutput.ReadToEnd();
如果(!process.WaitForExit(30000))
{
process.Kill();
}
返回Tuple.Create(process.ExitCode,process.StandardError.ReadToEnd());
}
下面是我试图在图片中识别的问题的一个例子

有没有办法优化我的脚本以提高性能?或者有没有更快的方法来识别图像的问题?

您可以试试。它不会发现像imagemagick那样多的图像格式,但它会做基本的TIF/JPG/PNG/GIF等,而且速度要快得多

我会通过计算平均像素值来测试图像。这样你就可以保证读取每一个像素,而且操作也很便宜

我实际上没有在这里安装C#程序,但在(与net VIP绑定到同一个库的Python)中,它将是:

import sys
import pyvips

for filename in sys.argv[1:]:
    try:
        # the fail option makes pyvips throw an exception on a file
        # format error
        # sequential access means libvips will stream the image rather than
        # loading it into memory
        image = pyvips.Image.new_from_file(filename,
                                           fail=True, access="sequential")
        avg = image.avg()
    except pyvips.Error as e:
        print("{}: {}".format(filename, e))
$ time for i in {1..100}; do if ! identify -regard-warnings -verbose $i.jpg > /dev/null; then echo $i: error; fi; done
real        0m21.454s
我可以这样运行它:

$ for i in {1..1000}; do cp ~/pics/k2.jpg $i.jpg; done
$ cp ~/pics/k2_broken.jpg .
$ vipsheader 1.jpg
1.jpg: 1450x2048 uchar, 3 bands, srgb, jpegload
这是一个损坏的图像,1000个正常图像,全部为1450x2048。然后:

$ time ../sanity.py *.jpg
k2_broken.jpg: unable to call avg
  VipsJpeg: Premature end of JPEG file
VipsJpeg: out of order read at line 48
real    0m23.424s
所以在这台普通的笔记本电脑上,它在23秒内发现了损坏的图像

您的标识循环(尽管只测试100个图像)将是:

import sys
import pyvips

for filename in sys.argv[1:]:
    try:
        # the fail option makes pyvips throw an exception on a file
        # format error
        # sequential access means libvips will stream the image rather than
        # loading it into memory
        image = pyvips.Image.new_from_file(filename,
                                           fail=True, access="sequential")
        avg = image.avg()
    except pyvips.Error as e:
        print("{}: {}".format(filename, e))
$ time for i in {1..100}; do if ! identify -regard-warnings -verbose $i.jpg > /dev/null; then echo $i: error; fi; done
real        0m21.454s
时间长度大致相同,因此净VIP在该测试中大约快10倍

由于NetVIP相对节省内存,您也可以同时运行多个,具体取决于您有多少内核。这将提供几乎线性的加速

在这台双核四线程笔记本电脑上,我看到:

$ time parallel --jobs 10 -m ../sanity.py ::: *.jpg
k2_broken.jpg: unable to call avg
  VipsJpeg: Premature end of JPEG file
VipsJpeg: out of order read at line 48
real    0m10.828s

现在1001张图像的速度降到11秒。

试试“magick identification-ping”,这样可以停止加载整个图像。在这种情况下,它可能对您有用。Ping不会发现被截断的图像,不幸的是,它只加载标题,