Rapide / Pixel Accès en Grâce à notre efficacité Magick ++
-
26-10-2019 - |
Question
En tant que excercise éducatif pour moi-même, je vous écris une application qui peut en moyenne un tas d'images. Ceci est souvent utilisé en astrophotographie pour réduire le bruit.
La bibliothèque que je utilise est Magick ++ et je l'ai réussi à écrire en fait la demande. Mais, malheureusement, sa lenteur. Voici le code que je utilise:
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);
}
}
Les moyennes de code 10 d'images en passant par chaque pixel et en ajoutant l'intensité de pixel de chaque canal en une double vecteur. La fonction avg prend alors le vecteur en tant que paramètre et la moyenne des résultats. Cette moyenne est ensuite utilisée au pixel correspondant stackedImage - qui est l'image résultante. Il fonctionne très bien, mais comme je le disais, je ne suis pas satisfait de la vitesse. Il prend 2 minutes et 30 secondes sur une machine Core i5. Les images sont de 8 mégapixels et 16 bits TIFFs. Je comprends que son beaucoup de données, mais je l'ai vu faire plus rapidement dans d'autres applications.
Est-ce ma boucle lente ou des thats est pixelColor (x, y) d'une façon lente à des pixels d'accès à une image? Y at-il un moyen plus rapide?
La solution
Why use vectors/arrays at all?
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 on vector objects per pixel.
And you may get even better performance by using a PixelCache
of the whole image instead of the original Image
objects. See the "Low-Level Image Pixel Access" section of the online Magick++ documentation for Image
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 to PixelColor, 10 ColorRGB constructors, and 30 accessor functions per pixel.
Note, This is all theory; I haven't tested any of it
Autres conseils
Comments:
- Why do you use vectors for
red
,blue
andgreen
? Because usingpush_back
can perform reallocations, and bottleneck processing. You could instead allocate just once three arrays of 10 colors. - Couldn't you declare
rgb
outside of the loops in order to relieve stack of unnecessary constructions and destructions? - Doesn't Magick++ have a way to average images?
Just in case anyone else wants to average images to reduce noise, and doesn't feel like too much "educational exercise" ;-)
ImageMagick can do averaging of a sequence of images like this:
convert image1.tif image2.tif ... image32.tif -evaluate-sequence mean result.tif
You can also do median filtering and others by changing the word mean
in the above command to whatever you want, e.g.:
convert image1.tif image2.tif ... image32.tif -evaluate-sequence median result.tif
You can get a list of the 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