Fast / efficient pixel access in Magick ++

As a training exercise for myself, I am writing an application that can average a bunch of images. This is often used in astrophotography to reduce noise.

The library I use is Magick ++, and I managed to write an application. But unfortunately, it is slow. This is the code I'm using:

for(row=0;row<rows;row++) { for(column=0;column<columns;column++) { red.clear(); blue.clear(); green.clear(); for(i=1;i<10;i++) { ColorRGB rgb(image[i].pixelColor(column,row)); red.push_back(rgb.red()); green.push_back(rgb.green()); blue.push_back(rgb.blue()); } redVal = avg(red); greenVal = avg(green); blueVal = avg(blue); redVal = redVal*MaxRGB; greenVal = greenVal*MaxRGB; blueVal = blueVal*MaxRGB; Color newRGB(redVal,greenVal,blueVal); stackedImage.pixelColor(column,row,newRGB); } } 

The code averages 10 images by looking at each pixel and adding the intensity of each channel pixel to the double vector. The avg function then transfers the vector as a parameter and averages the result. This average value is then used in the corresponding pixel in stackedImage - this is the resulting image. It works fine, but, as I said, speed does not suit me. On a Core i5, it takes 2 minutes and 30 seconds. Images are 8-megapixel and 16-bit TIFF. I understand that he has a lot of data, but I saw how it was done faster in other applications.

Is my loop slow or pixelColor (x, y) a slow way to access image pixels? Is there a faster way?

+4
source share
3 answers

Why use vectors / arrays?

Why not

 double red=0.0, blue=0.0, green=0.0; for(i=1;i<10;i++) { ColorRGB rgb(image[i].pixelColor(column,row)); red+=rgb.red(); blue+=rgb.blue(); green+=rgb.green(); } red/=10; blue/=10; green/=10; 

This avoids 36 function calls for vector objects per pixel.

And you can get even better performance by using the PixelCache entire image instead of the original Image objects. See the โ€œAccessing Low-Level Imagesโ€ section of the Magick ++ online documentation for images.

Then the inner loop becomes

 PixelPacket* pix = cache[i]+row*columns+column; red+= pix->red; blue+= pix->blue; green+= pix->green; 

Now you have also removed 10 calls for PixelColor, 10 ColorRGB constructors, and 30 pixel access functions.

Note. This is all theory; I have not tested anything.

+4
source

Comments:

  • Why are you using vectors for red , blue and green ? Since using push_back can redistribute and handle bottlenecks. Instead, you can select only once three arrays of 10 colors.
  • Could you declare rgb out of loops to free a stack of unnecessary constructions and destructions?
  • Does Magick ++ have medium-sized images?
+1
source

Just in case, someone wants to average the images to reduce noise, and does not feel too "a training exercise"; -)

ImageMagick can average the image sequence as follows:

 convert image1.tif image2.tif ... image32.tif -evaluate-sequence mean result.tif 

You can also perform median filtering and others by changing the word mean in the command above to what you want, for example:

 convert image1.tif image2.tif ... image32.tif -evaluate-sequence median result.tif 

You can get a list of available operations with:

 identify -list evaluate 

Output

 Abs Add AddModulus And Cos Cosine Divide Exp Exponential GaussianNoise ImpulseNoise LaplacianNoise LeftShift Log Max Mean Median Min MultiplicativeNoise Multiply Or PoissonNoise Pow RightShift RMS RootMeanSquare Set Sin Sine Subtract Sum Threshold ThresholdBlack ThresholdWhite UniformNoise Xor 
0
source

Source: https://habr.com/ru/post/1343948/


All Articles