Fix alpha upscaling artifacts and add CUDA fallback (addresses #3)#4
Fix alpha upscaling artifacts and add CUDA fallback (addresses #3)#4mgagvani wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3943208598
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| newalpha = cv2.resize(alpha, (alpha.shape[0]*scalefactor, alpha.shape[1]*scalefactor), interpolation=cv2.INTER_CUBIC) | ||
| # Preserve hard edges for textures with binary alpha (common in item icons). | ||
| # Fall back to cubic for textures that already contain semi-transparency. | ||
| alpha_interpolation = cv2.INTER_NEAREST if len(set(alpha.flatten())) <= 2 else cv2.INTER_CUBIC |
There was a problem hiding this comment.
Restrict nearest-alpha path to true binary masks
The new len(set(alpha.flatten())) <= 2 check treats any two-level alpha image as “binary,” so textures with semi-transparency encoded as two values (for example {0, 128} or {128, 255}) will incorrectly use INTER_NEAREST instead of cubic and lose soft edges. This contradicts the stated behavior of preserving semi-transparent textures and can visibly degrade icons/GUI assets that use quantized alpha ramps.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Pull request overview
Fixes texture upscaling artifacts and improves runtime portability by correcting alpha-channel resizing behavior and avoiding unconditional CUDA configuration when CUDA isn’t available.
Changes:
- Detect CUDA device availability before selecting OpenCV DNN CUDA backend/target, otherwise fall back to CPU.
- Fix alpha resize
(width, height)ordering and preserve hard edges by using nearest-neighbor interpolation for binary-alpha textures. - Add an investigation write-up documenting reproduction, findings, and validation for issue #3.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
texturepack.py |
Adds CUDA fallback logic and correct/edge-preserving alpha upscaling behavior. |
ISSUE_3_INVESTIGATION.md |
Documents root cause analysis and validation steps for issue #3. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if use_cuda:# Set CUDA backend and target to enable GPU inference | ||
| if cv2.cuda.getCudaEnabledDeviceCount() > 0: | ||
| sr.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA) | ||
| sr.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA) | ||
| else: | ||
| print("CUDA backend unavailable. Falling back to CPU.") |
There was a problem hiding this comment.
cv2.cuda.getCudaEnabledDeviceCount() can raise cv2.error (and/or cv2.cuda may be absent) when OpenCV is built without CUDA support. In that case this fallback logic will still crash before reaching the CPU path. Consider guarding with hasattr(cv2, "cuda") and wrapping the call in try/except cv2.error, defaulting to CPU when CUDA APIs are unavailable.
| if use_cuda:# Set CUDA backend and target to enable GPU inference | |
| if cv2.cuda.getCudaEnabledDeviceCount() > 0: | |
| sr.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA) | |
| sr.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA) | |
| else: | |
| print("CUDA backend unavailable. Falling back to CPU.") | |
| if use_cuda: # Set CUDA backend and target to enable GPU inference | |
| if hasattr(cv2, "cuda"): | |
| try: | |
| if cv2.cuda.getCudaEnabledDeviceCount() > 0: | |
| sr.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA) | |
| sr.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA) | |
| else: | |
| print("CUDA backend unavailable. Falling back to CPU.") | |
| except cv2.error: | |
| print("OpenCV CUDA support not available in this build. Falling back to CPU.") | |
| else: | |
| print("OpenCV CUDA module not found. Falling back to CPU.") |
| newalpha = cv2.resize(alpha, (alpha.shape[0]*scalefactor, alpha.shape[1]*scalefactor), interpolation=cv2.INTER_CUBIC) | ||
| # Preserve hard edges for textures with binary alpha (common in item icons). | ||
| # Fall back to cubic for textures that already contain semi-transparency. | ||
| alpha_interpolation = cv2.INTER_NEAREST if len(set(alpha.flatten())) <= 2 else cv2.INTER_CUBIC |
There was a problem hiding this comment.
Binary-alpha detection via len(set(alpha.flatten())) <= 2 is both expensive (creates a Python set over every pixel) and not equivalent to “binary alpha”: an alpha channel with exactly two non-{0,255} levels (e.g., {0, 64}) will be treated as binary and forced to INTER_NEAREST. Prefer a vectorized NumPy check like np.any((alpha != 0) & (alpha != 255)) (or np.isin) to decide between nearest/cubic, which avoids Python-level per-pixel work and matches the stated intent.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
This PR is being reviewed by Cursor Bugbot
Details
You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.
To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.
| sr.readModel(path) | ||
|
|
||
| if use_cuda:# Set CUDA backend and target to enable GPU inference | ||
| if cv2.cuda.getCudaEnabledDeviceCount() > 0: |
There was a problem hiding this comment.
CUDA check can crash without exception handling
Low Severity
The call to cv2.cuda.getCudaEnabledDeviceCount() at line 40 is not wrapped in a try/except. On some OpenCV installations (older versions, custom builds, or minimal packages), the cv2.cuda submodule may not exist, raising an unhandled AttributeError that crashes the entire upscale() function before processing any images. Since the whole purpose of this change is graceful CPU fallback, the CUDA availability check itself needs to be guarded.
| - Old path (swapped width/height in alpha resize): merge failed. | ||
| - New path (correct `(width, height)`): merge succeeded with upscaled alpha shape `(64, 52)`. | ||
|
|
||
| This confirms the old code path reproduced the defect conditions and the new path removes them for these representative textures. |
There was a problem hiding this comment.
Debugging investigation document committed to repository root
Low Severity
ISSUE_3_INVESTIGATION.md is a Codex task debugging artifact containing ephemeral details like specific pixel counts, test script outputs, and reproduction steps. This content belongs in the GitHub issue or PR comments, not as a permanent file in the repository root. It will become stale as code evolves and adds confusion for contributors who may mistake it for essential project documentation.


Motivation
Description
cv2.cuda.getCudaEnabledDeviceCount()and only set the CUDA backend/target when a device exists, otherwise continue on CPU. (texturepack.py).(width, height)so non-square RGBA textures are upscaled without merge-size mismatches. (texturepack.py).cv2.INTER_NEARESTwhen the alpha channel is binary, and usecv2.INTER_CUBICfor textures containing semi-transparency. (texturepack.py).ISSUE_3_INVESTIGATION.mddocumenting reproduction steps, findings, and the proposed/implemented solution for issue Transparent When Holding #3.Testing
EDSR_x2.pb) and compare alpha channels; tests show binary-alpha images remain binary after the patch and non-square RGBA images upscale without merge errors. (validation scripts executed successfully).texturepack.extract()+texturepack.upscale()to confirm shapes and alpha counts were correct, and ranpython -m py_compile texturepack.pywhich succeeded.Codex Task
Note
Low Risk
Scoped changes to image-processing behavior and a documentation add; main risk is subtle differences in output alpha interpolation for some textures.
Overview
Fixes RGBA upscaling issues that caused skipped non-square textures and semi-transparent/fringed edges in binary-alpha textures.
texturepack.upscale()now checkscv2.cuda.getCudaEnabledDeviceCount()before enabling the CUDA backend (otherwise continues on CPU), corrects alpha resize argument order to(width, height), and choosesINTER_NEARESTfor binary alpha masks while keepingINTER_CUBICfor already-soft alpha.Adds
ISSUE_3_INVESTIGATION.mddocumenting reproduction steps, root causes, and before/after verification for issue #3.Written by Cursor Bugbot for commit 7a64b64. This will update automatically on new commits. Configure here.