Search code examples
c#image-processingemgucvoperationtrigonometry

What is the fastest way to apply ArcCos for each pixel in an image using Emgu in c#


Good morning,

I am using a lot of operations on images with Emgu like Pow, Add, Sub, Mul. These operations work element by element between the two operated images. However, I see that the cos, acos, sin and asin are not included in Emgu library, and I need the fastest way to have an acos operation.

Eventhough, I already have this following way to do that, and I don't know if it is the fastest one or no.

// The original image
Image<Bgr, float> image = new Image<Bgr, float>(@"C:\image.jpg");

// Get the image width and height
int imageWidth = image.Width;

int imageHeight = image.Height;

// The ArcCos operated image
Image<Bgr, float> imageAcos = new Image<Bgr, float>(imageWidth, imageHeight);

// Start operating the image
for (int y = 0; y < imageHeight; y++)
{
    for(int x = 0; x < imageWidth; x++)
    {
    // The Blue frame
    imageAcos.Data[y, x, 0] = (float) Math.Acos((double) image.Data[y, x, 0]);

    // The Green frame
    imageAcos.Data[y, x, 1] = (float) Math.Acos((double) image.Data[y, x, 1]);

    // The Red frame
    imageAcos.Data[y, x, 2] = (float) Math.Acos((double) image.Data[y, x, 2]);
    }
}

Solution

  • With Image<,> I think this is about as fast as it can get without working with unsafe code and pointers. A quick speed-up would be to run the outer loop in parallel like so:

    Parallel.For(0, imageHeight, y =>
            {
                for (int x = 0; x < imageWidth; x++)
                {
                    // The Blue frame
                    imageAcos.Data[y, x, 0] = Method(image.Data[y, x, 0]);
    
                    // The Green frame
                    imageAcos.Data[y, x, 1] = Method(image.Data[y, x, 1]);
    
                    // The Red frame
                    imageAcos.Data[y, x, 2] = Method(image.Data[y, x, 2]);
                }
            });
    

    Whether this will result in a speed-up depends on the image size, so make sure to test this with your images. And it will utilize all your CPU cores, which you might not want.

    A simpler/more compact way to do this is by using the inbuilt Convert method.

    Image<Bgr, float> imageAcos = image.Convert(p => (float)Math.Acos((double)p));
    

    This can not by parallelized like the for-loops, but should be about as fast as your current implementation.

    By the way, I am pretty sure you have your x and y in the wrong order in the Data[].