Getting average color of an image

I’m trying to get the average pixel color of an image.
My source image is a 512x512 image with these colors:

There’s a single pixel on the very top left with the rgb colors 64,191,84.
The target image has the same format and the dimensions 1x1.
I’ve tried using vkCmdBlitImage to copy and rescale the image:


int32_t wSrc = 512;
int32_t hSrc = 512;

int32_t wDest = 1;
int32_t hDest = 1;
vk::ImageSubresourceLayers srcLayer {vk::ImageAspectFlagBits::eColor,0,0,1};
vk::ImageSubresourceLayers destLayer {vk::ImageAspectFlagBits::eColor,0,0,1};
vk::ImageBlit blit {
	srcLayer,
	{
		vk::Offset3D{0,0,0},
		vk::Offset3D{
			wSrc,
			hSrc,1
		}
	},destLayer,
	{
		vk::Offset3D{0,0,0},
		vk::Offset3D{
			wDest,
			hDest,1
		}
	}
};
m_buffer.blitImage(imgSrc,vk::ImageLayout::eTransferSrcOptimal,imgDest,vk::ImageLayout::eTransferDstOptimal,1,&blit,vk::Filter::eLinear);

However, this results in the target image having the color 64,191,84 for its pixel. It seems to just grab the pixel at the top left without doing any interpolation at all.

If I use larger dimensions for the target image, it works:
64x64 | 16x16:

At lower dimensions, some of the colors ‘vanish’, and they’re not incorporated into the final image at all:
4x4 | 2x2:

I’ve tried using nearest filtering instead, same result.

How can I get around this? I suppose one way would be to generate multiple images (With half the size of the previous image) until I’ve reached 1x1 (Essentially generate all of the mipmaps), however I need to do this each frame. Is there a faster way?

[QUOTE=Silverlan;40057]
How can I get around this? I suppose one way would be to generate multiple images (With half the size of the previous image) until I’ve reached 1x1 (Essentially generate all of the mipmaps), however I need to do this each frame. Is there a faster way?[/QUOTE]

Does the result need to be 100% accurate? I’d use some random sampling (or a fixed sampling grid) in a compute shader to get some information about all area of the screen. I think that taking one pixel from every 16x16 or even 32x32 block should already give you a fairly accurate estimate of the overall average.

You are probably trying to be too smart for your benefit. You know, you could just average it on the CPU (with comparable performance).

Anyway, your results sure are odd.
Do you use layers to debug?
Why is the z range set to [0;1]? I assume those are not 3D images.

It doesn’t need to be all that accurate, I just need the approximate brightness of the scene to select a dynamic exposure value for HDR tone mapping.
I’ve never used compute shaders, but I guess this is as good as time as any to get into that. Thanks for the tip.

That would require host visible memory, but the image I’m trying to get the average color of is the main scene, so this isn’t an option for me.

Which ones specifically?

I got that from the “copyblitimage” sample in the SDK, which also uses 2D images, so I’m assuming it’s correct.

[QUOTE=Silverlan;40064]
That would require host visible memory, but the image I’m trying to get the average color of is the main scene, so this isn’t an option for me.[/QUOTE]
On my HW/driver the default framebuffer is not even transferable(copyable/blitable). So, can I see your VkSwapchainCreateInfo and an output from vkGetPhysicalDeviceSurfaceCapabilities (supportedUsageFlags specificaly).
Also check vkGetPhysicalDeviceFormatProperties( BLIT_SRC and BLIT_DST bits)

The VK_LAYER_LUNARG_standard_validation meta-layer and the VK_EXT_debug_report extension dependency for the Instance and again the VK_LAYER_LUNARG_standard_validation for the Device. And provide valid debug callback CreateInfo to pNext of CreateInstance AND then create debug callback right after you create instance. You should now have proper debug environment.

I see. Well, it does make some twisted way of sense. The 2D image IS one texel deep.

[QUOTE=krOoze;40065]On my HW/driver the default framebuffer is not even transferable(copyable/blitable). So, can I see your VkSwapchainCreateInfo and an output from vkGetPhysicalDeviceSurfaceCapabilities (supportedUsageFlags specificaly).
Also check vkGetPhysicalDeviceFormatProperties( BLIT_SRC and BLIT_DST bits)[/QUOTE]
Oh, I didn’t actually mean the swapchain. The scene is rendered into a separate image first (Which I did the blitting on), which is later being used to draw to the swapchain.

Anyway, the compute shader solution did the trick. I’m now averaging the color from 64 samples every 0.2 seconds, which is good enough for me.
Thanks for the help to both of you! :slight_smile: