Acceso de píxel rápido/eficiente en Magick ++
-
26-10-2019 - |
Pregunta
Como un ejercicio educativo para mí, estoy escribiendo una aplicación que puede promediar un montón de imágenes. Esto a menudo se usa en astrofotografía para reducir el ruido.
La biblioteca que estoy usando es Magick ++ y he logrado escribir la aplicación. Pero, desafortunadamente, es lento. Este es el código que estoy usando:
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);
}
}
El código promedia 10 imágenes revisando cada píxel y agregando la intensidad de píxeles de cada canal en un doble vector. La función aviso Luego toma el vector como parámetro y promedia el resultado. Este promedio se usa luego en el píxel correspondiente en Trayedimage - cuál es la imagen resultante. Funciona bien, pero como mencioné, no estoy contento con la velocidad. Toma 2 minutos y 30 segundos en una máquina Core i5. Las imágenes son tiffs de 8 megapíxeles y 16 bits. Entiendo que son muchos datos, pero lo he visto más rápido en otras aplicaciones.
¿Es mi bucle lento o es PixelColor (X, Y) ¿Una forma lenta de acceder a los píxeles en una imagen? ¿Hay una manera mas rápida?
Solución
¿Por qué usar vectores/matrices?
Por que no
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;
Esto evita 36 llamadas de función en objetos vectoriales por píxel.
Y puede obtener un rendimiento aún mejor utilizando un PixelCache
de toda la imagen en lugar del original Image
objetos. Consulte la sección "Acceso de píxel de imagen de bajo nivel" del Magick en línea ++ Documentación para la imagen
Entonces el bucle interno se convierte en
PixelPacket* pix = cache[i]+row*columns+column;
red+= pix->red;
blue+= pix->blue;
green+= pix->green;
Ahora también ha eliminado 10 llamadas a PixelColor, 10 constructores COLORGB y 30 funciones de accesorios por píxel.
Tenga en cuenta que esta es toda la teoría; No he probado nada de eso
Otros consejos
Comentarios:
- ¿Por qué usas vectores para
red
,blue
ygreen
? Porque usarpush_back
Puede realizar reasignaciones y procesamiento de cuellos de botella. En su lugar, podría asignar solo una vez tres matrices de 10 colores. - ¿No podrías declarar
rgb
¿Fuera de los bucles para aliviar la pila de construcciones y destrucciones innecesarias? - ¿No tiene magia ++ una forma de promedio de imágenes?
En caso de que alguien más quiera promedio de imágenes para reducir el ruido, y no se siente demasiado "Ejercicio educativo" ;-)
ImageMagick puede hacer un promedio de una secuencia de imágenes como esta:
convert image1.tif image2.tif ... image32.tif -evaluate-sequence mean result.tif
También puede hacer un filtrado mediano y otros cambiando la palabra mean
En el comando anterior a lo que quieras, por ejemplo:
convert image1.tif image2.tif ... image32.tif -evaluate-sequence median result.tif
Puede obtener una lista de las operaciones disponibles con:
identify -list evaluate
Producción
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