It is currently Fri Jan 20, 2017 4:55 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 37 posts ]  Go to page Previous  1, 2, 3  Next
Author Message
PostPosted: Wed Jan 04, 2017 12:32 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 17591
Location: NE Indiana, USA (NTSC)
The loop causing you problems, the loop that proves that you're interpolating before enlarging, is this one:
Code:
      while(t_count > 0)
      {
         MK3X(*m); m++;
         t_count--;
      }


Top
 Profile  
 
PostPosted: Wed Jan 04, 2017 12:59 pm 
Offline
Formerly Fx3
User avatar

Joined: Fri Nov 12, 2004 4:59 pm
Posts: 2830
Location: Brazil
Well... let me point the obvious.
1) I expect a satisfactory result by preserving the native pixels.
2) No vertical interpolation, only an horizontal pixel interpolation.
3) If I can handle 1-1 pixels, I could handle 3-3 pixels, but...
4) You insist that I should use the 3x image size for interpolation. Right, how do I work with a matrix of 3x3 of same pixels?

The code is here! Isn't time to contribute instead of criticism-only?
Additionally, even if I learn a superb Bilinear filtering, the repeated pixel will be there! That's the point.


Top
 Profile  
 
PostPosted: Wed Jan 04, 2017 1:23 pm 
Offline
User avatar

Joined: Fri Nov 19, 2004 7:35 pm
Posts: 3716
There are so many different ways to choose a scaling algorithm.

The most common form of linear interpolation is blurry, and just considers your scanline as a smooth transition between pixel values at each location, and you'd be sampling at fractional coordinates on a smooth gradient.

Then there's another form of linear interpolation where only fractional pixel widths are interpolated, and whole pixel widths. You want a number of output pixels per input pixel, which doesn't have to be an integer. So if you wanted 2.6 output pixels per input pixel, the first three input pixels would look like this: Draw 2 whole pixels, .6 partial pixels. next color, .4 partial pixels, 2 whole pixels, .2 partial pixels. next color, .8 partial pixels, 1 whole pixel, .8 partial pixels. And so on...

As for what the best way to do it is, that's a question of preference.


Edit: just looked at "rocknes_interpolation.png", and it appears that you are just treating each partial pixel as if it has a value of .5 partial pixels.

Mockup of what the second interpolation method I described might look like:
Attachment:
megaman_mockup.png
megaman_mockup.png [ 27.01 KiB | Viewed 175 times ]


Made the mockup in Gimp by stretching horizontally to 65536x240 (nearest neighbor), downscaling to 876x240 (linear), resizing to 876x720 (nearest neighbor).

Edit again:

If you do the interpolation in the Linear RGB colorspace instead of SRGB colorspace, you get more evenly spaced pixels. Compare the two images side by side.
Attachment:
megaman_mockup_2.png
megaman_mockup_2.png [ 46.47 KiB | Viewed 170 times ]

_________________
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!


Last edited by Dwedit on Wed Jan 04, 2017 2:15 pm, edited 2 times in total.

Top
 Profile  
 
PostPosted: Wed Jan 04, 2017 1:31 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 9213
Location: Rio de Janeiro - Brazil
Zepper wrote:
1) I expect a satisfactory result by preserving the native pixels.

Enlarging then stretching preserves more of the original look than stretching then enlarging.

Quote:
2) No vertical interpolation, only an horizontal pixel interpolation.

That's fine, just do it AFTER enlarging to 3x, not before.

Quote:
4) You insist that I should use the 3x image size for interpolation. Right, how do I work with a matrix of 3x3 of same pixels?

If you insist on doing one pixel at a time instead of processing the whole image, you can probably pre calculate which pixels are enlarged to 3x3 and which are enlarged to 4x3, and use this look-up table for each pixel in the scanline. If you want interpolation, it would be better to buffer the scanline, stretch it by 3x, then stretch with interpolation to the final width.

Quote:
The code is here! Isn't time to contribute instead of criticism-only?

You showed us what you want, and to achieve that you need to scale then stretch, but your still stretching then scaling. You absolutely need to change the order these steps are done if you really want results like the examples you posted. This is not criticism, it's just fact.

Sorry for not contributing with code, but it's not like you have to do things in a completely different way, you just have to swap the other of the scaling and the stretching.

Quote:
Additionally, even if I learn a superb Bilinear filtering, the repeated pixel will be there! That's the point.

Yes, it will be there, but an error of 1 pixel relative to 3 pixels is much less noticeable than an error of 1 pixel relative to 1 pixel, which is what you get from stretching the small picture.


Top
 Profile  
 
PostPosted: Wed Jan 04, 2017 2:47 pm 
Offline
Formerly Fx3
User avatar

Joined: Fri Nov 12, 2004 4:59 pm
Posts: 2830
Location: Brazil
tokumaru wrote:
Zepper wrote:
1) I expect a satisfactory result by preserving the native pixels.

Enlarging then stretching preserves more of the original look than stretching then enlarging.

It depends of HOW TO DO the things.

Quote:
Quote:
2) No vertical interpolation, only an horizontal pixel interpolation.

That's fine, just do it AFTER enlarging to 3x, not before.

How so? A color fade-in effect starting at the left (or right?) most pixel!?

Quote:
Quote:
4) You insist that I should use the 3x image size for interpolation. Right, how do I work with a matrix of 3x3 of same pixels?

If you insist on doing one pixel at a time instead of processing the whole image (...)

No, you didn't see the code.

Quote:
Quote:
The code is here! Isn't time to contribute instead of criticism-only?

You showed us what you want, and to achieve that you need to scale then stretch, but your still stretching then scaling.
(...) but it's not like you have to do things in a completely different way, you just have to swap the other of the scaling and the stretching.

Annoying of "stretching". :evil:
For my best, it's called error difusion. As I said, a fade-in/out effect of the generated interpolated pixel with the nearest pixels.
I don't know if there's a true need of working in every pixel of the image, and not only the neighbor pixels of the repeated one. Currently, my interpolation makes the image a bit less deformed than just repeating the pixels.


Top
 Profile  
 
PostPosted: Wed Jan 04, 2017 3:29 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 9213
Location: Rio de Janeiro - Brazil
Zepper wrote:
How so? A color fade-in effect starting at the left (or right?) most pixel!?

The specific type of interpolation doesn't matter as much as the resolution at which it's being applied. *ANY* stretching will be obvious when applied at the low resolution, it will *NEVER* look good. At high resolutions though, after blowing up the pixels by an integer value, you can try different scaling algorithms (nearest neighbor, linear, whatever) and see what works best.

Quote:
No, you didn't see the code.

From the images, it's obvious that the stretching is working over 256 unique pixels of the scanline. Even if those pixels are actually 3x3 hardware pixels, you're probably still working with only 256 units, which is the same as working on the original 256-pixel scanline.

Quote:
Annoying of "stretching". :evil:

By "stretching", I mean scaling by a non-integer value, a scaling step that changes the aspect ratio.

Quote:
For my best, it's called error difusion.

The error diffuses better at higher resolutions, because the error spreads more evenly across the entire scanline, which is longer.

Here's an example... say you have these 3 pixels that have to be stretched into 5:

A naive nearest pixel approach at the native resolution will give you something like this: ████

Any pixel that needs to be doubled will create an error of 100%, it will double the native pixel! When you scale this up by 3x, THE ERROR IS SCALED UP AS WELL!!! So you end up with the following sequence (this is what you appear to be doing):

(original)
████ (stretched by 1.666)
███████████████ (scaled by 3x)

Now, if instead you scale by 3x first, the error will NOT be scaled up and will be way more subtle (the error is distributed more evenly):

(original)
█████████ (scaled by 3x)
███████████████ (stretched by 1.666)

In this particular case, the error was divided so evenly that all final pixels ended up the same size, with absolutely no distortion at all.

The bottomline is, you need to keep the error at the size of the target pixels, which are smaller, not at the size of the source pixels, which are big. At this point you're free to try different interpolations for the optimal result, but no matter what interpolation you use, it should be performed at the higher resolution, not the native resolution.


Top
 Profile  
 
PostPosted: Wed Jan 04, 2017 4:54 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 9213
Location: Rio de Janeiro - Brazil
Just for completeness sake, here's an approximation of both situations using linear interpolation:

(original)
(stretched by 1.666)
███████████████ (scaled by 3x)

(original)
█████████ (scaled by 3x)
█████████████ (stretched by 1.666)

There's less smudging when you scale up first then stretch, so the final picture will still look mostly blocky, despite the small transitions between different colors.


Top
 Profile  
 
PostPosted: Wed Jan 04, 2017 6:39 pm 
Offline
Formerly Fx3
User avatar

Joined: Fri Nov 12, 2004 4:59 pm
Posts: 2830
Location: Brazil
Check yourself. 8-)
Code:
#define MK3X(v) { \
   surface_00[0] = surface_00[1] = surface_00[2] = \
   surface_08[0] = surface_08[1] = surface_08[2] = \
   surface_16[0] = surface_16[1] = surface_16[2] = v; \
   surface_00 += 3; surface_08 += 3; surface_16 += 3; \
}
static void gfx_expand_3xsq(TPAL * const p)
{
   tbuffer[t_count] = p->value;
   t_count++;
   //full buffer   
   if(256 == t_count)
   {
      unsigned int pclock=0;
      unsigned int *t=tbuffer;
      unsigned int *tl=&tbuffer[256];
      while(t < tl)
      {
         MK3X(*t);         
         if(pclock)
         {
            *surface_00 = *surface_08 = *surface_16 = gfx_pixel_interpolate(t[0],t[1]);
            surface_00++; surface_08++; surface_16++;
         } t++; pclock ^= 1;
      } t_count=0;
   }
}


Attachments:
rocknes_stretch3x.png
rocknes_stretch3x.png [ 18.78 KiB | Viewed 131 times ]
Top
 Profile  
 
PostPosted: Wed Jan 04, 2017 7:27 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 9213
Location: Rio de Janeiro - Brazil
Ah, now that looks much better! The interpolation is hardly noticeable, and you're retaining the blocky, sharp look one would expect from an unscaled image. The pixel size looks pretty consistent too. Does it look good in motion?


Top
 Profile  
 
PostPosted: Wed Jan 04, 2017 7:44 pm 
Offline
Formerly Fx3
User avatar

Joined: Fri Nov 12, 2004 4:59 pm
Posts: 2830
Location: Brazil
Yes, it's ok. ^_^;;


Top
 Profile  
 
PostPosted: Wed Jan 04, 2017 7:54 pm 
Offline
User avatar

Joined: Fri Nov 19, 2004 7:35 pm
Posts: 3716
I checked the image, and it's still only interpolating as either 50% or not at all, and it cut off the right side of the image.

_________________
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!


Top
 Profile  
 
PostPosted: Wed Jan 04, 2017 8:39 pm 
Offline
Formerly Fx3
User avatar

Joined: Fri Nov 12, 2004 4:59 pm
Posts: 2830
Location: Brazil
Dwedit wrote:
I checked the image, and it's still only interpolating as either 50% or not at all, and it cut off the right side of the image.

The pixel interpolation is the aritmetic mean of the R, G and B components from 2 pixels. The "50%" you noticed occurs because of black pixels interpolated with non-black pixels. So, the new pixel will be 50% of the non-black pixel. ^_^;; Any other idea for interpolation of 2 pixels?

About the cutoff, I'll check it later...


Top
 Profile  
 
PostPosted: Wed Jan 04, 2017 9:23 pm 
Offline
User avatar

Joined: Fri Nov 19, 2004 7:35 pm
Posts: 3716
My post kinda got lost in the noise, but here's my suggestion again...

In this example we want to resize 256 to 876 pixels. For each input pixel, we output 3+108/256 pixels.
We start at X = 0, and want to output the first color value 3+108/256 times.
So we output the three solid pixels.
Then we're at X = 3, and we want to output 108/256 of a pixel.
Now we read the next input pixel.
We're now at X = 3+108/256, we want to output 148/256 of a pixel to reach the next integer coordinate. Now we have 2+216/256 pixels to draw. Draw 2 solid pixels, then 216/256 of a pixel.
Now we're at X = 6+216/256, we want to output 40/256 of a pixel to reach the next integer coordinate, then we have 3+68/256 pixels to draw. Draw 3 solid pixels, then 68/256 of a pixel.

And so on, we eventually reach X=876 after outputting the 256th input pixel.

Now let's look again at X=3, we have 108/256 * pixel A, plus 148/256 * pixel B.
I tried doing the interpolation in both the sRGB and Linear RGB color spaces, and found that doing it in Linear RGB made dark/light patterns look far more even.

------------------------

Linear RGB color space quick tutorial:
If we are using color values between 0.0 and 1.0, we get output color values 0.0 to 1.0 if we do:
linear = sRGB ^ 2.2
on each component separately

Then when we want to go backwards from Linear RGB to sRGB:
sRGB = linear ^ (1.0 / 2.2)
on each component separately

If you don't like floating point math here, you can also build two lookup tables:
Y = INT(65535 * (X / 255) ^ 2.2 + .5) //to convert sRGB (8-bit, 0 to 255) to Linear (16-bit, 0 to 65535)
Y = INT(255 * (X / 65535) ^ (1.0 / 2.2) + .5) //to convert Linear (16-bit, 0 to 65535) to sRGB (8-bit, 0 to 255)

(note: when building the first lookup table, {0 1 2 3} will map to {0, 0, 2, 4}, might want to force the second output value to be 1 just so it can be invertable, then force 1 to map back to 1 in the second table)

_________________
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!


Top
 Profile  
 
PostPosted: Wed Jan 04, 2017 9:43 pm 
Offline
Formerly Fx3
User avatar

Joined: Fri Nov 12, 2004 4:59 pm
Posts: 2830
Location: Brazil
It's rendering 896 pixels, 20 extra pixels.
I was interpolating/inserting a new pixel at every 6 pixels. It's wrong. -_-;;


Top
 Profile  
 
PostPosted: Thu Jan 05, 2017 9:26 am 
Offline
Formerly Fx3
User avatar

Joined: Fri Nov 12, 2004 4:59 pm
Posts: 2830
Location: Brazil
Fixed, but there's a problem. Due to the fact of 1 pixel = 3 pixels, and 1 pixel repeats at every 7 pixels, I couldn't implement pixel interpolation because the next one isn't always a new pixel. Code belows for suggestions, a screenshot of the final result (no interpolation).
Code:
/* EXPAND 3x SQUARED ASPECT 876x720
surface_00 is a pointer to a bitmap at scanline N.
surface_08 is a pointer to a bitmap at scanline N+1.
surface_16 is a pointer to a bitmap at scanline N+2.
 */
static void gfx_expand_3xsq(void)
{
   unsigned int j=0;
   unsigned int tplot=1;
   unsigned int *t=tbuffer;
   unsigned int *tl=&tbuffer[256]; /* scanline buffer, 256 pixels */
   while(t < tl)
   {
      *surface_00 = *surface_08 = *surface_16 = *t;
      surface_00++; surface_08++; surface_16++;
      tplot++; j++;
      //check for repeating the pixel
      if(7 == j) {
         *surface_00 = *surface_08 = *surface_16 = *t;  /* TODO: how could I interpolate the pixel? */
         surface_00++; surface_08++; surface_16++;
         j=0;
      }
      //move the buffer pointer to the next pixel.
      if(3 == tplot) {
         tplot=0;
         t++;
      }
   }
}


Attachments:
rocknes_3x_final.png
rocknes_3x_final.png [ 34.99 KiB | Viewed 58 times ]
Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 37 posts ]  Go to page Previous  1, 2, 3  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: glutock and 5 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group