<p>Long story short: downscale using a standard downscaling algorithm. Then multiply the value in each element by <code>originalArea/scaledArea</code>. This is what Rahul meant in the comments.</p>

<p>Why that works:<br>
You can think of every output pixel as a (weighted or not) average of a neighbourhood of the source pixel. And as we know:</p>

<pre><code>average = sum / count
</code></pre>

<p>Now, for the caveats.</p>

<p>Broadly, there are 3 types of downscaling algorithms:</p>

<ol>
<li>Ones that simply do resampling with some kernel<br>
1.1. Ones that lowpass first<br>
1.2. Ones that don't</li>
<li>Pyramid downscaling</li>
<li>Algorithms like the one in "Genuine Fractals" which are intended for detail-preserving <strong>up</strong>scaling, but could conceivably be abused for downscaling</li>
</ol>

<p>Since "3." is not intended for downscaling, it's not useful for your case.</p>

<p>The problem with "1.2." is that, normally a small (e.g. 5x5) resampling kernel is used, which means that only a few of the source pixels are taken into account. In image resizing applications, this can manifest as aliasing. In your application, it can manifest as inaccuracy.</p>

<p>This problem with "1.2." can be fixed by using a big resampling kernel. I believe that's what the ImageMagick library used to do. E.g. taking a good-quality kernel like Lanczos and stretching it by x and y. Or you could go ahead and use a big box kernel like you describe in the question. Which one is appropriate depends on your exact application, but if you're dead set on using a box kernel, use that. The algorithm you described in the question would work fine, and I believe that on a CPU there is no better one (except splitting this one into threads), for the reason that any algorithm would need at least N (number of pixels) operations to take into account all the pixels, and your algorithm does a tiny amount of work for each of these N pixels.</p>

<p>But on the GPU there is a better algorithm that takes full advantage of the GPU's strong parallelism. It's called "parallel reduction", you can find info on it based on that. Since it's widely documented, I'll just sketch the algorithm:</p>

<p>Iteratively downscale the image by a factor of 2 by x and y until you get to your desired size.</p>

<p>"1.1." would probably also suit your needs, but I won't comment on it for now, as it's not much better than the other options.</p>

CC BY-SA 3.0
2017-11-19T17:08:37.160Z
2017-11-19T17:08:37.160Z
Stefan Monov
<p>I have a grayscale image and want to "resize" it in terms of "pixel concentration".<br>
That means I divide the source image <code>x_old * y_old</code> into <code>x_new * y_new</code> sections, and all (sub)pixel grayscale values in each section shall be accumulated to make the new grayscale value.</p>

<p>Writing two loops also considering the sub pixel parts in each section is easy, but doesn't seem very sophisticated.<br>
Are there some smart and yet efficient algorithms doing the task?</p>

CC BY-SA 3.0
2017-07-02T08:01:11.137Z
Could you clarify what is meant by "subpixel" in a greyscale context? Is this just where a new section overlaps with a non-integer number of old pixels, and a proportional value is returned?
trichoplax is on Codidact now
CC BY-SA 3.0
2017-07-02T08:05:26.210Z
It seems worth checking whether you are only interested in this approach specifically, or whether you are just looking for the best approach to resizing. There are other approaches, and which is best will depend on the purpose of resizing and your priorities.
trichoplax is on Codidact now
CC BY-SA 3.0
2017-07-03T08:16:22.590Z
Your description sounds like box filtering which while easy is not very good in terms of quality
joojaa
CC BY-SA 3.0
2017-07-03T11:57:31.477Z
@trichoplax: Your "subpixel" assumption is correct. *_new is not necessarily an integer quotient of *_old. And it's not just about resizing - I know there are better algorithms for that. Let's say that in my case each pixel value represents an amount of energy, and I want to know how much energy each pixel of a downsized image must emit when the sum of energy shall be constant.
mic
CC BY-SA 3.0
2017-07-03T12:29:14.297Z
Unless you are only interested in this specific approach, it might help to edit the question to describe your underlying objectives, like the energy conservation you mentioned.
trichoplax is on Codidact now
CC BY-SA 3.0
2017-07-03T12:33:20.120Z
+1 to joojaa's comment.  Also, if your grey scale data has come from a captured image, there's a good chance it may be non-linear, e.g. sRGB (Search also for Charles Poynton's gamma FAQ).  If it is, you should first linearise it, filter, and then de-linearise again.
Simon F
CC BY-SA 3.0
2017-07-04T07:33:24.757Z
@joojaa: I played a little with box filtering in Gimp, but have no idea what filter matrix could do the job. Actually it would have to sum all (sub)pixel grayscale values in every section, followed by maybe a simple nearest neighbor resize to maintain that values in the final image. The problem is that summing up needs different filter matrix values for each pixel, e.g. with resize factor 1/2,33: Horizontally: p_new[0] = p_old[0] + p_old[1] + 0.33*p_old[2],  p_new[1] = 0.67*p_old[2] + p_old[3] + 0.67*p_old[4],  p_new[3] = 0.33*p_old[4] + p_old[5] + p_old[6]
mic
CC BY-SA 3.0
2017-07-05T07:41:53.563Z
@Rahul: What resize algorithm would you suggest? A "usual" resizing will calculate average values from neighboring pixels, but not sum-up.
mic
<transformations><algorithm>
Image resize with pixel accumulation?
mic
# Image resize with pixel accumulation?

(Asked by: username_0 on 2017-06-30)

I have a grayscale image and want to "resize" it in terms of "pixel concentration".  
That means I divide the source image `x_old * y_old` into `x_new * y_new` sections, and all (sub)pixel grayscale values in each section shall be accumulated to make the new grayscale value.

Writing two loops also considering the sub pixel parts in each section is easy, but doesn't seem very sophisticated.  
Are there some smart and yet efficient algorithms doing the task?

**Tags:** transformations, algorithm

> **Comments:**
> **username_1**: Could you clarify what is meant by "subpixel" in a greyscale context? Is this just where a new section overlaps with a non-integer number of old pixels, and a proportional value is returned?  
> **username_1**: It seems worth checking whether you are only interested in this approach specifically, or whether you are just looking for the best approach to resizing. There are other approaches, and which is best will depend on the purpose of resizing and your priorities.  
> **username_2**: Your description sounds like box filtering which while easy is not very good in terms of quality  
> **username_0**: @username_1: Your "subpixel" assumption is correct. *_new is not necessarily an integer quotient of *_old. And it's not just about resizing - I know there are better algorithms for that. Let's say that in my case each pixel value represents an amount of energy, and I want to know how much energy each pixel of a downsized image must emit when the sum of energy shall be constant.  
> **username_1**: Unless you are only interested in this specific approach, it might help to edit the question to describe your underlying objectives, like the energy conservation you mentioned.  
> **username_3**: +1 to username_2's comment.  Also, if your grey scale data has come from a captured image, there's a good chance it may be non-linear, e.g. sRGB (Search also for Charles Poynton's gamma FAQ).  If it is, you should first linearise it, filter, and then de-linearise again.  
> **username_0**: @username_2: I played a little with box filtering in Gimp, but have no idea what filter matrix could do the job. Actually it would have to sum all (sub)pixel grayscale values in every section, followed by maybe a simple nearest neighbor resize to maintain that values in the final image. The problem is that summing up needs different filter matrix values for each pixel, e.g. with resize factor 1/2,33: Horizontally: p_new[0] = p_old[0] + p_old[1] + 0.33*p_old[2],  p_new[1] = 0.67*p_old[2] + p_old[3] + 0.67*p_old[4],  p_new[3] = 0.33*p_old[4] + p_old[5] + p_old[6]  
> **username_0**: @Rahul: What resize algorithm would you suggest? A "usual" resizing will calculate average values from neighboring pixels, but not sum-up.  

---

## 1 answers

### Answer by username_4 on 2017-11-19. Score: 2

Long story short: downscale using a standard downscaling algorithm. Then multiply the value in each element by `originalArea/scaledArea`. This is what Rahul meant in the comments.

Why that works:  
You can think of every output pixel as a (weighted or not) average of a neighbourhood of the source pixel. And as we know:

```
average = sum / count

```

Now, for the caveats.

Broadly, there are 3 types of downscaling algorithms:

1. Ones that simply do resampling with some kernel  
   1.1. Ones that lowpass first  
   1.2. Ones that don't
2. Pyramid downscaling
3. Algorithms like the one in "Genuine Fractals" which are intended for detail-preserving **up**scaling, but could conceivably be abused for downscaling

Since "3." is not intended for downscaling, it's not useful for your case.

The problem with "1.2." is that, normally a small (e.g. 5x5) resampling kernel is used, which means that only a few of the source pixels are taken into account. In image resizing applications, this can manifest as aliasing. In your application, it can manifest as inaccuracy.

This problem with "1.2." can be fixed by using a big resampling kernel. I believe that's what the ImageMagick library used to do. E.g. taking a good-quality kernel like Lanczos and stretching it by x and y. Or you could go ahead and use a big box kernel like you describe in the question. Which one is appropriate depends on your exact application, but if you're dead set on using a box kernel, use that. The algorithm you described in the question would work fine, and I believe that on a CPU there is no better one (except splitting this one into threads), for the reason that any algorithm would need at least N (number of pixels) operations to take into account all the pixels, and your algorithm does a tiny amount of work for each of these N pixels.

But on the GPU there is a better algorithm that takes full advantage of the GPU's strong parallelism. It's called "parallel reduction", you can find info on it based on that. Since it's widely documented, I'll just sketch the algorithm:

Iteratively downscale the image by a factor of 2 by x and y until you get to your desired size.

"1.1." would probably also suit your needs, but I won't comment on it for now, as it's not much better than the other options.


---

