SFTtech / SFTtech/openage

Use bicubic filtering to reverse dimetric projection

Open
#1,297 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

area: assets improvement to-discuss
Dominant language
Python
Stars
14.4k
Forks
1.3k
PR merge metrics
No merged PRs in 30d

Description

Related: #720, #985.

This is the current implementation:

https://github.com/SFTtech/openage/blob/439d224aac94c4d6114e8d0405abf7fd17db924d/openage/convert/processor/export/texture_merge.py#L165-L173

As written in the chat, I see several issues with this implementation:

  • homemade, inefficient matrix multiplication algorithm (while the images are quite small, I'd still leave that to optimized algorithms
  • No antialiasing. The code takes values from nearest neighbours instead of interpolating them depending on their proximity (bicubic, bilinear, etc)
  • A permutation index is reconstructed from scratch each time the function is called.

There are several libraries that can implement this in a more efficient way, I chose pillow based on the fact that it's used elsewhere. It doesn't have the greatest choice of antialiasing algorithms nor the most efficient implementation, but that's probably enough. Example code based on the same stackoverflow question and this tutorial, though I have ignored a few things, like the matrix inversion, and improved a few things with these two wikipedia pages

I suggest something similar to the following code:

import numpy as np
from PIL import Image
import matplotlib.pyplot as plt

file = "45c0011e-e279-11e6-9ed5-30f00391cc87.png"

img = Image.open(file)

def rot_mat(angle_rad):
    return np.array([[np.cos(angle_rad),-np.sin(angle_rad), 0],
                     [np.sin(angle_rad),np.cos(angle_rad),  0],
                     [                0,               0,   1]])

def aoe2_transf(scale=1.118):
    return np.array([[  1,  -1,     0],
                     [0.5, 0.5, scale],
                     [  0,   0,     0]])

# unsure, intuitively deduced from the above
def aoe2_inv_transf(scale=1.118):
    return np.array([[ 0.5, 1,       0],
                     [-0.5, 1, 1/scale],
                     [   0, 0,       0]])


def trans_mat(x,y):
    return np.array([[1,0,x],
                     [0,1,y],
                     [0,0,1]])

# Inverse transform should be something along those lines, with a 512x512 img size:
# trans =    trans_mat(-512,256) @ aoe2_transf() @ trans_mat(256,-256)

# We combine those transformations, starting by centering the image
trans =  trans_mat(256,256) @ aoe2_inv_transf() @trans_mat(-512,0)

# Note that this could be an PERSPECTIVE transform if we were to lose the "[:6]".
transformed = img.transform(
    (1000,512),
    Image.PERSPECTIVE,
    (trans).flatten(),
    resample=Image.BICUBIC)

transformed.save("transformed_bicubic.png")
plt.imshow(transformed)

Here is an example with the image from #720

transformed_nearest
transformed_bilinear
transformed_bicubic

Nearest neighbour, bilinear and bicubic transforms, respectively. I hope that helps make the case for bicubic filtering.

As seen in these pictures, though, I still haven't found a satisfactory projection matrix as the edges (most notably the corner on the right) are cut.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with openage/convert/processor/export/texture_merge.py at lines 165-173, then review related issues #720 and #985 and the linked projection references. Compare the current output with the attached nearest-neighbour, bilinear, and bicubic examples; done means the transform uses bicubic filtering without cutting off the image edges.

Written by the indexing model from the issue text.

Assessment

Tech stack
numpy, python
Domain
computer-graphics, game-dev
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.