Lossy compression for NES screens

A place for your artistic side. Discuss techniques and tools for pixel art on the NES, GBC, or similar platforms.

Moderator: Moderators

JRoatch
Formerly 43110
Posts: 422
Joined: Wed Feb 05, 2014 7:01 am
Contact:

Lossy compression for NES screens

Post by JRoatch »

Edit: check The next page for a improvement to this script.

So I took a couple days to tackle a problem I had to deal with a couple of times: Fitting complex images into the 256 tile limit.
What I basically tried out was an automated version of the process I end up do manually. Randomly search for 2 similar tiles that are unique in the nametable and merge them in some way.

In this program similar tiles are pairs of tiles that have the least number of pixels changed, and merging is randomly selecting the pixels from both tiles

Edit 2: Linked example images, and python scripts removed.

Results vary due to random pixel selections between tiles. Not the best of quality, but looks on par with the worst JPEG compression. In any case I figured this hack of a tool might be useful to someone. It's input is the output of tepple's pilbmp2nes.py

Edit: Attachment moved off site ... but are now gone.
Last edited by JRoatch on Sun Feb 12, 2023 1:05 pm, edited 3 times in total.
User avatar
rainwarrior
Posts: 8731
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Lossy compression for NES screens

Post by rainwarrior »

Two ideas that might improve results:

1. Instead of just "number of changed pixels", multiply this number by the number of times that either tile is being used in the image. That will give you the total number of pixels changed in the whole image, rather than just the number changed in the individual tiles. (Also might guide the merging process; i.e. where pixels differ, take more from the one that is used more.)

2. Use a 3x3 neighbourhood to weight the importance of pixel changes. e.g. if you're about to place a black pixel into a 3x3 region of white pixels, consider this a greater change than placing a black pixel next to a group of black pixels just extending an edge, etc. This might let you favour changes that don't stand out as much? (Also gives you a way to choose which pixels to keep from the two merging tiles.)
JRoatch
Formerly 43110
Posts: 422
Joined: Wed Feb 05, 2014 7:01 am
Contact:

Re: Lossy compression for NES screens

Post by JRoatch »

Suggestion 1 about counting the pixel changes of the whole image helped a lot. What is measured now better matches what's changed. Combined with the suggestion to bias the merge changes, this now does subtle changes to more tiles rather then big changes to less.

[external image deleted]

I not sure how to work in suggestion 2. I did try something with a 3x3 region, but I must of severely messed up the weights because the result was garbage.

The way I see the problem is that tiles with opposite edges and corners are matched together, but every time I try to fix the random edge dots, the overall picture gets worse. I'm starting to think the random dots are actually a feature and the best compromise for reducing the tileset.

A thing that I might try another day is to factor in a manually made mask that prevents select pixels from changing. So that some crucial details, like faces, are preserved.

Edit: Attachment moved off site ... but
Edit 2: Removed dead links.
Last edited by JRoatch on Sun Feb 12, 2023 1:03 pm, edited 2 times in total.
User avatar
Alp
Posts: 223
Joined: Mon Oct 06, 2014 12:37 am

Re: Lossy compression for NES screens

Post by Alp »

JRoatch wrote:So I took a couple days to tackle a problem I had to deal with a couple of times: Fitting complex images into the 256 tile limit.

Example image NES screen sized image with way too many distinct tiles (471)
471? That's honestly not too bad. With fullscreen scenes like this, I say screw the limitations!

I tend to limit my RPG's *ahem* "cutscenes" to 448 tiles, with a timed $00/$10 background split, to use more on-screen tiles. The rest is used for sprite overlays, to enhance the scene. It's all done by hand, on my end, though.
User avatar
Macbee
Posts: 120
Joined: Sat Nov 26, 2011 8:31 am
Location: Brazil
Contact:

Re: Lossy compression for NES screens

Post by Macbee »

Thanks JRoatch for creating (and publishing) this!
It's fantastic and is already helping me a lot with a NES project.

User NESRocks is also using this - and even created a .BAT to make it easier to use (just drop the BMP file to convert.bat).
I'm attaching it here.

Are you planning to release a version that also removes the duplicated tiles?
It can be done on NES Screen Tool, just asking for curiosity.

Thanks! =)
Attachments
bmp2nescompress.zip
(9.17 KiB) Downloaded 755 times
User avatar
Bregalad
Posts: 8055
Joined: Fri Nov 12, 2004 2:49 pm
Location: Divonne-les-bains, France

Re: Lossy compression for NES screens

Post by Bregalad »

Looks like this really rocks ! Drawing such a scene limited to 256 tiles should be hard, a bit of automation can always help.

Also, for those pointing to the possibility of doing raster effects trickery to bypass the limitation, I'd add that there's a million of reason why you'd want to stick to vanialla 256 tiles and not want to deal with PPU register writes midframe at all.
User avatar
FrankenGraphics
Formerly WheelInventor
Posts: 2064
Joined: Thu Apr 14, 2016 2:55 am
Location: Gothenburg, Sweden
Contact:

Re: Lossy compression for NES screens

Post by FrankenGraphics »

A masking feature sounds like a very sensible option to be able to use.

Currently, i'm doing this completely manually.
tepples
Posts: 22705
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Lossy compression for NES screens

Post by tepples »

Would you be willing to make compress-nes-image-2.py available under a free software license so that I can incorporate it into my NES background tools?
JRoatch
Formerly 43110
Posts: 422
Joined: Wed Feb 05, 2014 7:01 am
Contact:

Re: Lossy compression for NES screens

Post by JRoatch »

Sure, it's now under the "Expat License".
tepples
Posts: 22705
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Lossy compression for NES screens

Post by tepples »

Many thanks.
User avatar
bazza
Posts: 94
Joined: Fri Nov 24, 2017 1:36 pm
Location: Argentina
Contact:

Re: Lossy compression for NES screens

Post by bazza »

Macbee wrote:Thanks JRoatch for creating (and publishing) this!
It's fantastic and is already helping me a lot with a NES project.

User NESRocks is also using this - and even created a .BAT to make it easier to use (just drop the BMP file to convert.bat).
I'm attaching it here.

Are you planning to release a version that also removes the duplicated tiles?
It can be done on NES Screen Tool, just asking for curiosity.

Thanks! =)
Some example of as use the output_result.chr and input_tiles.chr In a project?
zzo38
Posts: 1096
Joined: Mon Feb 07, 2011 12:46 pm

Re: Lossy compression for NES screens

Post by zzo38 »

Macbee wrote:Are you planning to release a version that also removes the duplicated tiles?
It can be done on NES Screen Tool, just asking for curiosity.
My ff-uniq program will remove duplicated tiles from a tileset. However, it does not use the Famicom format directly (but ffbit and bitff can be used to convert in either direction).
(Free Hero Mesh - FOSS puzzle game engine)
tepples
Posts: 22705
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Lossy compression for NES screens

Post by tepples »

I've started refactoring what I'm calling "JRoatch's Tile Vector Quantizer" to make it more usable from within other Python programs.
  • biased_random_byte() now called biased_getrandbits() and allows changing word width like random.getrandbits()
  • Can be imported as a library
  • Variable output tile count
  • Takes a filelike for logging the tile count
  • Input and output filenames passed through command line instead of hardcoded
I'll probably add a way to remove duplicated tiles when I integrate it into savtool.
Attachments
jrtilevq.zip
(2.24 KiB) Downloaded 673 times
User avatar
slembcke
Posts: 172
Joined: Fri Nov 24, 2017 2:40 pm
Location: Minnesota

Re: Lossy compression for NES screens

Post by slembcke »

Hay! This is pretty neat. I wrote something kinda similar a few years ago for the Gameduino. It used 8x8 4bpp tiles with individual 16bpp palettes. It made using photo input pretty easy, though it looked kinda terrible.

Image Image

I've been musing about doing something similar for the NES. Will have to give it a try. :D
User avatar
bazza
Posts: 94
Joined: Fri Nov 24, 2017 1:36 pm
Location: Argentina
Contact:

Re: Lossy compression for NES screens

Post by bazza »

Image
Image

Code: Select all

#!/bin/bash

mkdir nam
mkdir nam1
rm nam/a-*m
rm nam1/a-*m
convert -crop 8x8 $1 -depth 2 -colors 4 -compress none nam/a-%010d.xpm
convert -crop 8x8 $1 -depth 2 -colors 4 -compress none nam1/a-%010d.xpm

cd nam

# quita las cabeceras
mogrify -sample $2 *
sed -i $sed '/^s/d' *

LISTA=$(fdupes . | grep "^$" -B 1 | grep "^./" )

# quita los duplicados
fdupes -r1 . | sed -e 's/\(\w\) /\1|/g' -e 's/|$//' > files
while read line; do
        IFS='|' read -a arr <<< "$line"
        orig=${arr[0]}
        for ((i = 1; i < ${#arr[@]}; i++)); do
                file="${arr[$i]}"
                #sleep 1
                ln -sf "$orig" "$file"
        done
done < files
rm files


ls -F ../nam | grep -v @ | while read A; do
	cp ../nam1/$A ../nam/$A
done

# join
rm ../nam.png
N=0
$(echo "convert ( "
ls a-*m | while read A; do
    echo $A
    N=$((N+1))
    [ "$N" == "32" ] && echo " +append ) (" && N=0
done
echo ") -background none -append ../nam.png")
Post Reply