Imagemagick进程永远挂在Loopbackjs上

时间:2021-12-02 09:00:50

I got this code to check if an image file contains blue pixels with Imagemagick and counting them - then saving the result.

我得到这个代码来检查图像文件是否包含Imagemagick的蓝色像素并计算它们 - 然后保存结果。

It works well, but it seems like many processes of Imagemagick hang forever on the server and are making it very slow.

它运行良好,但似乎Imagemagick的许多进程永远挂在服务器上,并使它非常慢。

Is there a way to improve this code and avoid this trouble?

有没有办法改善这些代码并避免这种麻烦?

module.exports = function (File) {
    File.observe('after save', function countPixels(ctx, next) {
        if (ctx.instance && !ctx.instance.blue_pixels) {
            var exec = require('child_process').exec;

            // Convert file to retrieve only blue pixels:
            exec('convert ' + ctx.instance.path + ' -fx "u.b>(u.g+0.2)&&u.b>(u.r+0.2)&&saturation>0.6" -format "%[fx:mean*w*h]" info:',
                    function (error, stdout, stderr) {
                        if (error !== null) {
                            return next(error);
                        } else {
                            ctx.instance.blue_pixels = stdout;
                            File.upsert(ctx.instance);
                        }
                    });
        }
        next();
    });
};

2 个解决方案

#1


1  

The -fx operator that you are using is notoriously slow - especially for large images. I had a try at casting the same formula using faster methods which may help you. So, I made a sample image:

您正在使用的-fx运算符非常慢 - 特别是对于大型图像。我尝试使用更快的方法来铸造相同的公式,这可能会对你有帮助。所以,我做了一个示例图像:

convert xc:red xc:lime -append \( xc:blue xc:cyan -append \) +append -resize 256x256! input.png

Imagemagick进程永远挂在Loopbackjs上

And then rewrote your expression like this:

然后重写你的表达式:

convert input.png \
  \( -clone 0 -separate -delete 0 -evaluate-sequence subtract -threshold 20% -write BG.png \) \
  \( -clone 0 -separate -delete 1 -evaluate-sequence subtract -threshold 20% -write BR.png \) \
  \( -clone 0 -colorspace hsl -separate -delete 0,2 -threshold 60% -write S.png \)            \
  -delete 0 \
  -evaluate-sequence min result.png

Note that the -write XYZ.png are just debug statements that can be removed.

请注意,-write XYZ.png只是可以删除的调试语句。

Basically, I am building a mask of all pixels that meet your criteria and making them white, and making all the ones that don't match your criteria black and at the end, I run -evaluate-sequence min to find the minimum of each pixel so that all three of your conditions must effectively be met:

基本上,我正在构建一个符合您标准的所有像素的蒙版,并将它们设置为白色,并使所有与您的标准不匹配的像素变黑,最后,我运行-evaluate-sequence min来查找每个像素的最小值像素,以便有效地满足您的所有三个条件:

  • that blue exceeds green by 20%
  • 蓝色超过绿色20%
  • that blue exceeds red by 20%
  • 蓝色超过红色20%
  • that the saturation exceeds 60%
  • 饱和度超过60%

The -separate -delete N splits your image into RGB channels and then deletes one of the resulting channels, so if I -delete 1 (that is the Green channel) I am left with Red and Blue. Here are the intermediate, debug images. The first one is the condition Blue exceeds Red by 20%:

-separate -delete N将您的图像拆分为RGB通道,然后删除其中一个结果通道,因此如果I -delete 1(即绿色通道),我将留下红色和蓝色。这是中间调试图像。第一个是条件蓝色超过红色20%:

Imagemagick进程永远挂在Loopbackjs上

Then that Blue exceeds Green by 20%:

那么蓝色超过绿色20%:

Imagemagick进程永远挂在Loopbackjs上

And finally that the Saturation exceeds 60%:

最后,饱和度超过60%:

Imagemagick进程永远挂在Loopbackjs上

And then the result:

然后结果:

Imagemagick进程永远挂在Loopbackjs上

You'll need to put your -format "%[fx:mean*w*h]" info: back on the end in place of the output image name to get the count of saturated blue pixels.

你需要将你的-format“%[fx:mean * w * h]”信息放回到最后代替输出图像名称以获得饱和蓝色像素的数量。

If I run your command:

如果我运行你的命令:

convert input.png -fx "u.b>(u.g+0.2)&&u.b>(u.r+0.2)&&saturation>0.6" result.png

Imagemagick进程永远挂在Loopbackjs上

My brain is not quite right today, so please run some checks - I may have something back-to-front somewhere!

我的大脑今天不太正确,所以请进行一些检查 - 我可能会在某个地方有一些东西!

As a benchmark, on a 10,000x10,000 pixel PNG, my code runs in 30 seconds, whereas the -fx equivalent takes nearly 7 minutes.

作为基准,在10,000x10,000像素的PNG上,我的代码在30秒内运行,而-fx相当于将近7分钟。

#2


1  

I don't know imagelagick part. But for node part I see that you call next non regarding to imagemgick opertion.

我不知道imagelagick的一部分。但是对于节点部分我看到你关于imagemgick opertion调用next non。

module.exports = function (File) {
    File.observe('after save', function countPixels(ctx, next) {
        if (ctx.instance && !ctx.instance.blue_pixels) {
            var exec = require('child_process').exec;

            // Convert file to retrieve only blue pixels:
            exec('convert ' + ctx.instance.path + ' -fx "u.b>(u.g+0.2)&&u.b>(u.r+0.2)&&saturation>0.6" -format "%[fx:mean*w*h]" info:',
                    function (error, stdout, stderr) {
                        if (error !== null) {
                            return next(error);
                        } else {
                            ctx.instance.blue_pixels = stdout;
                            File.upsert(ctx.instance);
                            next();
                        }
                    });
        }
        else{next();}
        //next(); //run next hook ASAP (before imagemagick returns back the result)
    });
};

#1


1  

The -fx operator that you are using is notoriously slow - especially for large images. I had a try at casting the same formula using faster methods which may help you. So, I made a sample image:

您正在使用的-fx运算符非常慢 - 特别是对于大型图像。我尝试使用更快的方法来铸造相同的公式,这可能会对你有帮助。所以,我做了一个示例图像:

convert xc:red xc:lime -append \( xc:blue xc:cyan -append \) +append -resize 256x256! input.png

Imagemagick进程永远挂在Loopbackjs上

And then rewrote your expression like this:

然后重写你的表达式:

convert input.png \
  \( -clone 0 -separate -delete 0 -evaluate-sequence subtract -threshold 20% -write BG.png \) \
  \( -clone 0 -separate -delete 1 -evaluate-sequence subtract -threshold 20% -write BR.png \) \
  \( -clone 0 -colorspace hsl -separate -delete 0,2 -threshold 60% -write S.png \)            \
  -delete 0 \
  -evaluate-sequence min result.png

Note that the -write XYZ.png are just debug statements that can be removed.

请注意,-write XYZ.png只是可以删除的调试语句。

Basically, I am building a mask of all pixels that meet your criteria and making them white, and making all the ones that don't match your criteria black and at the end, I run -evaluate-sequence min to find the minimum of each pixel so that all three of your conditions must effectively be met:

基本上,我正在构建一个符合您标准的所有像素的蒙版,并将它们设置为白色,并使所有与您的标准不匹配的像素变黑,最后,我运行-evaluate-sequence min来查找每个像素的最小值像素,以便有效地满足您的所有三个条件:

  • that blue exceeds green by 20%
  • 蓝色超过绿色20%
  • that blue exceeds red by 20%
  • 蓝色超过红色20%
  • that the saturation exceeds 60%
  • 饱和度超过60%

The -separate -delete N splits your image into RGB channels and then deletes one of the resulting channels, so if I -delete 1 (that is the Green channel) I am left with Red and Blue. Here are the intermediate, debug images. The first one is the condition Blue exceeds Red by 20%:

-separate -delete N将您的图像拆分为RGB通道,然后删除其中一个结果通道,因此如果I -delete 1(即绿色通道),我将留下红色和蓝色。这是中间调试图像。第一个是条件蓝色超过红色20%:

Imagemagick进程永远挂在Loopbackjs上

Then that Blue exceeds Green by 20%:

那么蓝色超过绿色20%:

Imagemagick进程永远挂在Loopbackjs上

And finally that the Saturation exceeds 60%:

最后,饱和度超过60%:

Imagemagick进程永远挂在Loopbackjs上

And then the result:

然后结果:

Imagemagick进程永远挂在Loopbackjs上

You'll need to put your -format "%[fx:mean*w*h]" info: back on the end in place of the output image name to get the count of saturated blue pixels.

你需要将你的-format“%[fx:mean * w * h]”信息放回到最后代替输出图像名称以获得饱和蓝色像素的数量。

If I run your command:

如果我运行你的命令:

convert input.png -fx "u.b>(u.g+0.2)&&u.b>(u.r+0.2)&&saturation>0.6" result.png

Imagemagick进程永远挂在Loopbackjs上

My brain is not quite right today, so please run some checks - I may have something back-to-front somewhere!

我的大脑今天不太正确,所以请进行一些检查 - 我可能会在某个地方有一些东西!

As a benchmark, on a 10,000x10,000 pixel PNG, my code runs in 30 seconds, whereas the -fx equivalent takes nearly 7 minutes.

作为基准,在10,000x10,000像素的PNG上,我的代码在30秒内运行,而-fx相当于将近7分钟。

#2


1  

I don't know imagelagick part. But for node part I see that you call next non regarding to imagemgick opertion.

我不知道imagelagick的一部分。但是对于节点部分我看到你关于imagemgick opertion调用next non。

module.exports = function (File) {
    File.observe('after save', function countPixels(ctx, next) {
        if (ctx.instance && !ctx.instance.blue_pixels) {
            var exec = require('child_process').exec;

            // Convert file to retrieve only blue pixels:
            exec('convert ' + ctx.instance.path + ' -fx "u.b>(u.g+0.2)&&u.b>(u.r+0.2)&&saturation>0.6" -format "%[fx:mean*w*h]" info:',
                    function (error, stdout, stderr) {
                        if (error !== null) {
                            return next(error);
                        } else {
                            ctx.instance.blue_pixels = stdout;
                            File.upsert(ctx.instance);
                            next();
                        }
                    });
        }
        else{next();}
        //next(); //run next hook ASAP (before imagemagick returns back the result)
    });
};