Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GetPixelsFast too slow for our use-case #2

Open
derwaldgeist opened this issue Apr 3, 2023 · 1 comment
Open

GetPixelsFast too slow for our use-case #2

derwaldgeist opened this issue Apr 3, 2023 · 1 comment

Comments

@derwaldgeist
Copy link

derwaldgeist commented Apr 3, 2023

Hi, we have an AR app that downloads a couple of textures for objects around the user. For these textures, we have to know the predominant color. The texture images (PNGs) are approx. 1.5mb.

We noticed significant frame drops, and when we analysed the root cause, we learned that ColorThief's "GetPixelFast" method is the actual culprit. More specifically, the following line:

var pixels = imageData.ToArray();

This array conversion takes around 1.5s. And it doesn't matter which quality setting we choose, as this array conversion is done before quality is taken into account.

Is there a way to speed this up, i.e. by copying only the required pixels into an array?

@derwaldgeist
Copy link
Author

derwaldgeist commented Apr 3, 2023

I was able to speed things up drastically:

private int[][] GetPixelsFast(Texture2D sourceImage, int quality, bool ignoreWhite, int mipLevel) {
		var mipData = sourceImage.GetPixels32(mipLevel);
		var pixelCount = mipData.Length;

		// Store the RGB values in an array format suitable for quantize
		// function

		// numRegardedPixels must be rounded up to avoid an
		// ArrayIndexOutOfBoundsException if all pixels are good.

		var numRegardedPixels = (quality <= 0) ? 0 : (pixelCount + quality - 1) / quality;

		var numUsedPixels = 0;
		var pixelArray = new int[numRegardedPixels][];

		for (var i = 0; i < pixelCount; i += quality) {
			var b = Convert.ToInt32(mipData[i].b);
			var g = Convert.ToInt32(mipData[i].g);
			var r = Convert.ToInt32(mipData[i].r);
			var a = Convert.ToInt32(mipData[i].a);

			// If pixel is mostly opaque and not white
			if (a >= 125 && !(ignoreWhite && r > 250 && g > 250 && b > 250)) {
				pixelArray[numUsedPixels] = new[] { r, g, b };
				numUsedPixels++;
			}
		}

		// Remove unused pixels from the array
		var copy = new int[numUsedPixels][];
		Array.Copy(pixelArray, copy, numUsedPixels);
		return copy;
	}

It could be further sped up if a higher mip level would be used and if the rest of the logic directly operated on the returned COLOR32 values, I guess.

Not sure if this is a generic solution for all cases, but for me, it worked wonders.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant