218 lines
8.3 KiB
Python
218 lines
8.3 KiB
Python
# vim: set fileencoding=utf-8 :
|
|
import operator
|
|
import pytest
|
|
from functools import reduce
|
|
|
|
import pyvips
|
|
from helpers import noncomplex_formats, run_fn2, run_fn, \
|
|
assert_almost_equal_objects, assert_less_threshold
|
|
|
|
|
|
# point convolution
|
|
def conv(image, mask, x_position, y_position):
|
|
s = 0.0
|
|
for x in range(0, mask.width):
|
|
for y in range(0, mask.height):
|
|
m = mask(x, y)
|
|
i = image(x + x_position, y + y_position)
|
|
p = run_fn2(operator.mul, m, i)
|
|
s = run_fn2(operator.add, s, p)
|
|
|
|
return run_fn2(operator.truediv, s, mask.scale)
|
|
|
|
|
|
def compass(image, mask, x_position, y_position, n_rot, fn):
|
|
acc = []
|
|
for i in range(0, n_rot):
|
|
result = conv(image, mask, x_position, y_position)
|
|
result = run_fn(abs, result)
|
|
acc.append(result)
|
|
mask = mask.rot45()
|
|
|
|
return reduce(lambda a, b: run_fn2(fn, a, b), acc)
|
|
|
|
|
|
class TestConvolution:
|
|
@classmethod
|
|
def setup_class(cls):
|
|
im = pyvips.Image.mask_ideal(100, 100, 0.5, reject=True, optical=True)
|
|
cls.colour = im * [1, 2, 3] + [2, 3, 4]
|
|
cls.colour = cls.colour.copy(interpretation=pyvips.Interpretation.SRGB)
|
|
cls.mono = cls.colour.extract_band(1)
|
|
cls.mono = cls.mono.copy(interpretation=pyvips.Interpretation.B_W)
|
|
cls.all_images = [cls.mono, cls.colour]
|
|
cls.sharp = pyvips.Image.new_from_array([[-1, -1, -1],
|
|
[-1, 16, -1],
|
|
[-1, -1, -1]], scale=8)
|
|
cls.blur = pyvips.Image.new_from_array([[1, 1, 1],
|
|
[1, 1, 1],
|
|
[1, 1, 1]], scale=9)
|
|
cls.line = pyvips.Image.new_from_array([[1, 1, 1],
|
|
[-2, -2, -2],
|
|
[1, 1, 1]])
|
|
cls.sobel = pyvips.Image.new_from_array([[1, 2, 1],
|
|
[0, 0, 0],
|
|
[-1, -2, -1]])
|
|
cls.all_masks = [cls.sharp, cls.blur, cls.line, cls.sobel]
|
|
|
|
@classmethod
|
|
def teardown_class(cls):
|
|
cls.colour = None
|
|
cls.mono = None
|
|
cls.all_images = None
|
|
cls.sharp = None
|
|
cls.blur = None
|
|
cls.line = None
|
|
cls.sobel = None
|
|
cls.all_masks = None
|
|
|
|
def test_conv(self):
|
|
for im in self.all_images:
|
|
for msk in self.all_masks:
|
|
for prec in [pyvips.Precision.INTEGER, pyvips.Precision.FLOAT]:
|
|
convolved = im.conv(msk, precision=prec)
|
|
|
|
result = convolved(25, 50)
|
|
true = conv(im, msk, 24, 49)
|
|
assert_almost_equal_objects(result, true)
|
|
|
|
result = convolved(50, 50)
|
|
true = conv(im, msk, 49, 49)
|
|
assert_almost_equal_objects(result, true)
|
|
|
|
# don't test conva, it's still not done
|
|
def dont_est_conva(self):
|
|
for im in self.all_images:
|
|
for msk in self.all_masks:
|
|
print("msk:")
|
|
msk.matrixprint()
|
|
print("im.bands = %s" % im.bands)
|
|
|
|
convolved = im.conv(msk,
|
|
precision=pyvips.Precision.APPROXIMATE)
|
|
|
|
result = convolved(25, 50)
|
|
true = conv(im, msk, 24, 49)
|
|
print("result = %s, true = %s" % (result, true))
|
|
assert_less_threshold(result, true, 5)
|
|
|
|
result = convolved(50, 50)
|
|
true = conv(im, msk, 49, 49)
|
|
print("result = %s, true = %s" % (result, true))
|
|
assert_less_threshold(result, true, 5)
|
|
|
|
def test_compass(self):
|
|
for im in self.all_images:
|
|
for msk in self.all_masks:
|
|
for prec in [pyvips.Precision.INTEGER, pyvips.Precision.FLOAT]:
|
|
for times in range(1, 4):
|
|
convolved = im.compass(msk,
|
|
times=times,
|
|
angle=pyvips.Angle45.D45,
|
|
combine=pyvips.Combine.MAX,
|
|
precision=prec)
|
|
|
|
result = convolved(25, 50)
|
|
true = compass(im, msk, 24, 49, times, max)
|
|
assert_almost_equal_objects(result, true)
|
|
|
|
for im in self.all_images:
|
|
for msk in self.all_masks:
|
|
for prec in [pyvips.Precision.INTEGER, pyvips.Precision.FLOAT]:
|
|
for times in range(1, 4):
|
|
convolved = im.compass(msk,
|
|
times=times,
|
|
angle=pyvips.Angle45.D45,
|
|
combine=pyvips.Combine.SUM,
|
|
precision=prec)
|
|
|
|
result = convolved(25, 50)
|
|
true = compass(im, msk, 24, 49, times, operator.add)
|
|
assert_almost_equal_objects(result, true)
|
|
|
|
def test_convsep(self):
|
|
for im in self.all_images:
|
|
for prec in [pyvips.Precision.INTEGER, pyvips.Precision.FLOAT]:
|
|
gmask = pyvips.Image.gaussmat(2, 0.1,
|
|
precision=prec)
|
|
gmask_sep = pyvips.Image.gaussmat(2, 0.1,
|
|
separable=True,
|
|
precision=prec)
|
|
|
|
assert gmask.width == gmask.height
|
|
assert gmask_sep.width == gmask.width
|
|
assert gmask_sep.height == 1
|
|
|
|
a = im.conv(gmask, precision=prec)
|
|
b = im.convsep(gmask_sep, precision=prec)
|
|
|
|
a_point = a(25, 50)
|
|
b_point = b(25, 50)
|
|
|
|
assert_almost_equal_objects(a_point, b_point, threshold=0.1)
|
|
|
|
def test_fastcor(self):
|
|
for im in self.all_images:
|
|
for fmt in noncomplex_formats:
|
|
small = im.crop(20, 45, 10, 10).cast(fmt)
|
|
cor = im.fastcor(small)
|
|
v, x, y = cor.minpos()
|
|
|
|
assert v == 0
|
|
assert x == 25
|
|
assert y == 50
|
|
|
|
def test_spcor(self):
|
|
for im in self.all_images:
|
|
for fmt in noncomplex_formats:
|
|
small = im.crop(20, 45, 10, 10).cast(fmt)
|
|
cor = im.spcor(small)
|
|
v, x, y = cor.maxpos()
|
|
|
|
assert v == 1.0
|
|
assert x == 25
|
|
assert y == 50
|
|
|
|
def test_gaussblur(self):
|
|
for im in self.all_images:
|
|
for prec in [pyvips.Precision.INTEGER, pyvips.Precision.FLOAT]:
|
|
for i in range(5, 10):
|
|
sigma = i / 5.0
|
|
gmask = pyvips.Image.gaussmat(sigma, 0.2,
|
|
precision=prec)
|
|
|
|
a = im.conv(gmask, precision=prec)
|
|
b = im.gaussblur(sigma, min_ampl=0.2, precision=prec)
|
|
|
|
a_point = a(25, 50)
|
|
b_point = b(25, 50)
|
|
|
|
assert_almost_equal_objects(a_point, b_point,
|
|
threshold=0.1)
|
|
|
|
def test_sharpen(self):
|
|
for im in self.all_images:
|
|
for fmt in noncomplex_formats:
|
|
# old vipses used "radius", check that that still works
|
|
sharp = im.sharpen(radius=5)
|
|
|
|
for sigma in [0.5, 1, 1.5, 2]:
|
|
im = im.cast(fmt)
|
|
sharp = im.sharpen(sigma=sigma)
|
|
|
|
# hard to test much more than this
|
|
assert im.width == sharp.width
|
|
assert im.height == sharp.height
|
|
|
|
# if m1 and m2 are zero, sharpen should do nothing
|
|
sharp = im.sharpen(sigma=sigma, m1=0, m2=0)
|
|
sharp = sharp.colourspace(im.interpretation)
|
|
# print("testing sig = %g" % sigma)
|
|
# print("testing fmt = %s" % fmt)
|
|
# print("max diff = %g" % (im - sharp).abs().max())
|
|
assert (im - sharp).abs().max() == 0
|
|
|
|
|
|
if __name__ == '__main__':
|
|
pytest.main()
|