From 95c1e6d9c6b87d213c83234cbd168fef7e7362af Mon Sep 17 00:00:00 2001 From: Mutah Date: Fri, 14 May 2021 06:40:38 +0200 Subject: [PATCH] operator binding --- README.md | 20 ++++++++++ floatimg/__init__.py | 14 +++++-- floatimg/image.py | 94 ++++++++++++++++++++++++++++++++++++++------ floatimg/operators.c | 0 tests/basics.py | 64 ++++++++++++++++++++++++++++++ 5 files changed, 178 insertions(+), 14 deletions(-) delete mode 100644 floatimg/operators.c diff --git a/README.md b/README.md index 9de9146..69b0ffd 100644 --- a/README.md +++ b/README.md @@ -102,6 +102,26 @@ TODO create a FileInfo named tuple. witdh, height, img_type = floatimg.fileinfos("/tmp/image_dump") ``` +## Operators + +```python +# addition +res_img = img + img2 + +# substraction +res_img = img - img2 + +# multiplication +res_img = img * img2 + +# min value per color channel +res_img = img.min(img2) + +# max value per color channel +res_img = img.max(img2) + +``` + ## Development diff --git a/floatimg/__init__.py b/floatimg/__init__.py index 248f2fb..5cd4dad 100644 --- a/floatimg/__init__.py +++ b/floatimg/__init__.py @@ -1,6 +1,14 @@ """Python Binding to FloatImg """ -# FloatImg class and static functions -from floatimg.image import FloatImg, create, create_rgb, create_from_dump, GRAY, RGB, fileinfos +# FloatImg class, constants & static functions +from floatimg.image import ( + GRAY, + RGB, + FloatImg, + create, + create_rgb, + create_from_dump, + fileinfos, +) -__version__ = "0.0.1" \ No newline at end of file +__version__ = "0.0.1" diff --git a/floatimg/image.py b/floatimg/image.py index 17ab2fe..932fe5a 100644 --- a/floatimg/image.py +++ b/floatimg/image.py @@ -122,6 +122,48 @@ c_fimg_add_rgb.argtypes = ( ) c_fimg_add_rgb.restype = ct.c_int +# operators +c_fimg_add_3 = LIB.fimg_add_3 +c_fimg_add_3.argtypes = ( + ct.POINTER(C_FloatImg), + ct.POINTER(C_FloatImg), + ct.POINTER(C_FloatImg), +) +c_fimg_add_3.restype = ct.c_int + +c_fimg_sub_3 = LIB.fimg_sub_3 +c_fimg_sub_3.argtypes = ( + ct.POINTER(C_FloatImg), + ct.POINTER(C_FloatImg), + ct.POINTER(C_FloatImg), +) +c_fimg_sub_3.restype = ct.c_int + +c_fimg_mul_3 = LIB.fimg_mul_3 +c_fimg_mul_3.argtypes = ( + ct.POINTER(C_FloatImg), + ct.POINTER(C_FloatImg), + ct.POINTER(C_FloatImg), +) +c_fimg_mul_3.restype = ct.c_int + +c_fimg_minimum = LIB.fimg_minimum +c_fimg_minimum.argtypes = ( + ct.POINTER(C_FloatImg), + ct.POINTER(C_FloatImg), + ct.POINTER(C_FloatImg), +) +c_fimg_minimum.restype = ct.c_int + +c_fimg_maximum = LIB.fimg_maximum +c_fimg_maximum.argtypes = ( + ct.POINTER(C_FloatImg), + ct.POINTER(C_FloatImg), + ct.POINTER(C_FloatImg), +) +c_fimg_maximum.restype = ct.c_int + + ############################################################################################################ class FloatImg: """ @@ -168,9 +210,9 @@ class FloatImg: ####################################################################################################### def clone(self, copy_data=False): """return a clone of the current instance""" - new_pic = C_FloatImg() - assert c_fimg_clone(self.c_img_p, ct.pointer(new_pic), int(copy_data)) == 0 - return FloatImg(new_pic) + c_img_p = C_FloatImg() + assert c_fimg_clone(self.c_img_p, ct.pointer(c_img_p), int(copy_data)) == 0 + return FloatImg(c_img_p) ####################################################################################################### def copy_data(self, to_img): @@ -196,11 +238,7 @@ class FloatImg: ####################################################################################################### def put(self, x, y, color): """put color to a pixel""" - # TODO may be a better way to create the array rather than iterating that may cost too much in - # intensive usaage - c_rgb = (ct.c_float * 3)() - for i, c in enumerate(color): - c_rgb[i] = c + c_rgb = (ct.c_float * 3)(*color) assert c_fimg_put_rgb(self.c_img_p, x, y, ct.pointer(c_rgb)) == 0 ####################################################################################################### @@ -229,10 +267,44 @@ class FloatImg: == 0 ) - # TODO - # fimg_plot_rgb - # fimg_add_rgb + ####################################################################################################### + def __add__(self, img): + """ + operator overload""" + res = self.clone(False) + assert c_fimg_add_3(self.c_img_p, img.c_img_p, res.c_img_p) == 0 + return res + ####################################################################################################### + def __sub__(self, img): + """ - operator overload""" + res = self.clone(False) + assert c_fimg_sub_3(self.c_img_p, img.c_img_p, res.c_img_p) == 0 + return res + + ####################################################################################################### + def __mul__(self, img): + """ * operator overload""" + res = self.clone(False) + assert c_fimg_mul_3(self.c_img_p, img.c_img_p, res.c_img_p) == 0 + return res + + ####################################################################################################### + def min(self, img): + """return a new image with minimum pixel values per channel between current and parameter""" + res = self.clone(False) + # C code invert comparison + assert c_fimg_maximum(self.c_img_p, img.c_img_p, res.c_img_p) == 0 + return res + + ####################################################################################################### + def max(self, img): + """return a new image with maximum pixel values per channel between current and parameter""" + res = self.clone(False) + # C code invert comparison + assert c_fimg_minimum(self.c_img_p, img.c_img_p, res.c_img_p) == 0 + return res + + # TODO # export(fname, flags) : depending file extension, save to the correct format diff --git a/floatimg/operators.c b/floatimg/operators.c deleted file mode 100644 index e69de29..0000000 diff --git a/tests/basics.py b/tests/basics.py index c98869b..67c8afb 100644 --- a/tests/basics.py +++ b/tests/basics.py @@ -112,3 +112,67 @@ def test_add(): img.put(0, 0, color) img.add(0, 0, color) assert img.get(0, 0) == [64.0, 64.0, 64.0] + + +def test_op_add(): + width, height = 5, 5 + img = floatimg.create_rgb(width, height) + color = (32.0, 32.0, 32.0) + img.fill(color) + img2 = floatimg.create_rgb(width, height) + img2.fill(color) + img3 = img + img2 + for y in range(height): + for x in range(width): + assert img3.get(x, y) == [64.0, 64.0, 64.0] + + +def test_op_sub(): + width, height = 5, 5 + img = floatimg.create_rgb(width, height) + color = (32.0, 32.0, 32.0) + img.fill(color) + img2 = floatimg.create_rgb(width, height) + img2.fill(color) + img3 = img - img2 + for y in range(height): + for x in range(width): + assert img3.get(x, y) == [0.0, 0.0, 0.0] + + +def test_op_mul(): + width, height = 5, 5 + img = floatimg.create_rgb(width, height) + color = (32.0, 32.0, 32.0) + img.fill(color) + img2 = floatimg.create_rgb(width, height) + img2.fill((2.0, 2.0, 2.0)) + img3 = img * img2 + for y in range(height): + for x in range(width): + assert img3.get(x, y) == [64.0, 64.0, 64.0] + +def test_op_min(): + width, height = 5, 5 + img = floatimg.create_rgb(width, height) + img.fill((32.0, 0.0, 32.0)) + + img2 = floatimg.create_rgb(width, height) + img2.fill((0.0, 32.0, 0.0)) + img3 = img.min(img2) + for y in range(height): + for x in range(width): + assert img3.get(x, y) == [0.0, 0.0, 0.0] + + +def test_op_max(): + width, height = 5, 5 + img = floatimg.create_rgb(width, height) + img.fill((32.0, 0.0, 32.0)) + + img2 = floatimg.create_rgb(width, height) + img2.fill((0.0, 32.0, 0.0)) + img3 = img.max(img2) + for y in range(height): + for x in range(width): + assert img3.get(x, y) == [32.0, 32.0, 32.0]