Added texture rotation, mirroring, blurring to img2tex.py

This commit is contained in:
Revar Desmera 2024-03-25 22:43:06 -07:00
parent 53d7c7e56b
commit adf22a53c4

View file

@ -6,38 +6,60 @@ import sys
import os.path
import argparse
from PIL import Image
from PIL import Image, ImageFilter, ImageOps
def img2tex(filename, varname, invert, resize, outf):
def img2tex(filename, opts, outf):
indent = " " * 4
im = Image.open(filename).convert('L')
if resize:
print("Resizing to {}x{}".format(resize[0],resize[1]))
im = im.resize(resize)
if opts.resize:
print("Resizing to {}x{}".format(opts.resize[0], opts.resize[1]))
im = im.resize(opts.resize)
if opts.invert:
print("Inverting luminance.")
im = ImageOps.invert(im)
if opts.blur:
print("Blurring, radius={}.".format(opts.blur))
im = im.filter(ImageFilter.BoxBlur(opts.blur))
if opts.rotate:
if opts.rotate in (-90, 270):
print("Rotating 90 degrees clockwise.".format(opts.rotate))
elif opts.rotate in (90, -270):
print("Rotating 90 degrees counter-clockwise.".format(opts.rotate))
elif opts.rotate in (180, -180):
print("Rotating 180 degrees.".format(opts.rotate))
im = im.rotate(opts.rotate, expand=True)
if opts.mirror_x:
print("Mirroring left-to-right.")
im = im.transpose(Image.FLIP_LEFT_RIGHT)
if opts.mirror_y:
print("Mirroring top-to-bottom.")
im = im.transpose(Image.FLIP_TOP_BOTTOM)
pix = im.load()
width, height = im.size
print("// Image {} ({}x{})".format(filename, width, height), file=outf)
pixmin = 255;
pixmax = 0;
for y in range(height):
for x in range(width):
pixmin = min(pixmin, pix[x,y])
pixmax = max(pixmax, pix[x,y])
print("// min = {} max = {}".format(pixmin, pixmax), file=outf)
if opts.range == "dynamic":
pixmin = 255;
pixmax = 0;
for y in range(height):
for x in range(width):
pixmin = min(pixmin, pix[x,y])
pixmax = max(pixmax, pix[x,y])
else:
pixmin = 0;
pixmax = 255;
print("// Original luminances: min={}, max={}".format(pixmin, pixmax), file=outf)
print("// Texture heights: min={}, max={}".format(opts.minout, opts.maxout), file=outf)
print("{} = [".format(varname), file=outf)
print("{} = [".format(opts.varname), file=outf)
line = indent
for y in range(height):
line += "[ "
for x in range(width):
if not invert:
line += "{:.2f}, ".format((pix[x,y]-pixmin)/(pixmax-pixmin))
else:
line += "{:.2f}, ".format((pixmax-pix[x,y])/(pixmax-pixmin))
u = (pix[x,y] - pixmin) / (pixmax - pixmin)
val = u * (opts.maxout - opts.minout) + opts.minout
line += "{:.3f}".format(val).rstrip('0').rstrip('.') + ", "
if len(line) > 60:
print(line, file=outf)
line = indent * 2
@ -49,6 +71,13 @@ def img2tex(filename, varname, invert, resize, outf):
print("", file=outf)
def check_nonneg_float(value):
val = float(value)
if val < 0:
raise argparse.ArgumentTypeError("{} is an invalid non-negative float value".format(val))
return val
def main():
parser = argparse.ArgumentParser(prog='img2tex')
parser.add_argument('-o', '--outfile',
@ -56,9 +85,24 @@ def main():
parser.add_argument('-v', '--varname',
help='Variable to use in .scad file.')
parser.add_argument('-i', '--invert', action='store_true',
help='Invert greyscale values.')
help='Invert luminance values.')
parser.add_argument('-r', '--resize',
help='Resample image to WIDTHxHEIGHT.')
parser.add_argument('-R', '--rotate', choices=(-270, -180, -90, 0, 90, 180, 270), default=0, type=int,
help='Rotate output by the given number of degrees.')
parser.add_argument('--mirror-x', action="store_true",
help='Mirror output in the X direction.')
parser.add_argument('--mirror-y', action="store_true",
help='Mirror output in the Y direction.')
parser.add_argument('--blur', type=check_nonneg_float, default=0,
help='Perform a box blur on the output with the given radius.')
parser.add_argument('--minout', type=float, default=0.0,
help='The value to output for the minimum luminance.')
parser.add_argument('--maxout', type=float, default=1.0,
help='The value to output for the maximum luminance.')
parser.add_argument('--range', choices=["dynamic", "full"], default="dynamic",
help='If "dynamic", the lowest to brightest luminances are scaled to the minout/maxout range.\n'
'If "full", 0 to 255 luminances will be scaled to the minout/maxout range.')
parser.add_argument('infile', help='Input image file.')
opts = parser.parse_args()
@ -71,10 +115,7 @@ def main():
opts.varname = "image_data"
size_pat = re.compile(r'^([0-9][0-9]*)x([0-9][0-9]*)$')
if not opts.invert:
opts.invert = False
else:
opts.invert = True
opts.invert = bool(opts.invert)
if opts.resize:
m = size_pat.match(opts.resize)
@ -89,9 +130,9 @@ def main():
if opts.outfile:
with open(opts.outfile, "w") as outf:
img2tex(opts.infile, opts.varname, opts.invert, opts.resize, outf)
img2tex(opts.infile, opts, outf)
else:
img2tex(opts.infile, opts.varname, opts.invert, opts.resize, sys.stdout)
img2tex(opts.infile, opts, sys.stdout)
sys.exit(0)