Multithreaded direct access sample

Magick.NET is an object-oriented C# interface to ImageMagick. Use this forum to discuss, make suggestions about, or report bugs concerning Magick.NET
Locked
SLS8
Posts: 6
Joined: 2020-03-03T11:26:22-07:00
Authentication code: 1152

Multithreaded direct access sample

Post by SLS8 »

The previous samples on the forum were using functions that are no longer used so I made this test. I don't know if it's the fastest option, I'm still learning the Magick.NET api, but this works very fast.

Single thread, multi function (per channel):

Code: Select all

public static MagickImage ChangePixels(MagickImage img)
{
	MagickImage retimg = new MagickImage("xc:black", input.Width, input.Height);
	using (var pcimg = img.GetPixelsUnsafe())
	{
		using (var pcret = retimg.GetPixelsUnsafe()) 
		{
			var pximg = pcimg.GetValues();
			var pxret = pcret.GetValues();
			
			for (int x = 0; x < pxret.Length; x += img.ChannelCount)
			{
				pxret[x] = (ushort)(pximg[x] / 2f);
				pxret[x + 1] = (ushort)(pximg[x + 1] / 3f);
				pxret[x + 2] = (ushort)(pximg[x + 2] / 4f);
			}
			pcret.SetPixels(pxret);
		}
	}
	return retimg;
}
Multithreaded, single function (per value):

Code: Select all

Parallel.For(0, pxret.Length, i =>
{
	pxret[i] = (ushort)(pximg[i] / 3f);
});
Multithreaded partitions, single function (for fast functions and/or smaller images)

Code: Select all

Parallel.ForEach(Partitioner.Create(0, pxret.Length), part =>
{
	for (int i = part.Item1; i < part.Item2; i++)
	{
		pxret[i] = ...
	}
});	
Multithreaded, multi function:

Code: Select all

//set this list once, after loading the image
var steps = new List<int>();
for (int i = 0; i < (img.Height * img.Width * img.ChannelCount); i += img.ChannelCount)	
	steps.Add(i);

Parallel.ForEach(steps, i =>
{
	pxret[i] = MyFunc(pximg[i]);
	pxret[i + 1] = MyFunc(pximg[i + 1]);
	pxret[i + 2] = MyFunc(pximg[i + 2]);
});
Or you can split the input image in tiles and process all of them in parallel, like in this topic

Locked