Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added new augmentations for Pattern Distortion. #242 #272

Merged
merged 31 commits into from
Apr 16, 2023
Merged

Added new augmentations for Pattern Distortion. #242 #272

merged 31 commits into from
Apr 16, 2023

Conversation

ss756
Copy link
Contributor

@ss756 ss756 commented Apr 13, 2023

resolves #242

This PR contains code for pattern-based distortion using 3 different techniques - Voronoi, Delaunay, and Quasicrystals. Perlin Noise is added to the Voronoi and Delaunay Tessellations patterns to create smoother and organic-looking images mentioned in #242.
Made changes to the docs and benchmark results in README.md

@ss756 ss756 requested review from jgsato and jboarman April 13, 2023 14:00
@ss756 ss756 added the enhancement New feature or request label Apr 13, 2023
@jboarman jboarman requested review from kwcckw and removed request for jgsato April 13, 2023 21:58
@ss756 ss756 self-assigned this Apr 14, 2023
@ss756 ss756 changed the title Added new augmentations and archetype pipeline. #242 Added new augmentations for Pattern Distortion. #242 Apr 15, 2023
@kwcckw kwcckw merged commit b40acf5 into sparkfish:dev Apr 16, 2023

def __init__(
self,
width=500,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ss756 Are those width, height and ws adjustable? If yes, it will be better to make them into a tuple so that the final value will be selected randomly in the code later. Same with self.perlin too. It can be initialized as random, so that if self.perlin is random, the code will randomly set it as True or False.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I will integrate this today

super().__init__(p=p)
self.width = width
self.height = height
self.n_points = random.randint(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we need a different approach here. The actual randomized parameter should be initialized during the __call__ so that the parameter value will be different from each call.

result = image.copy()
h, w, _ = result.shape
delaunay_mesh = self.apply_augmentation()
# if self.perlin:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we still need this section (line 221 to line 224)? Else we can just remove it. If you still need it, please include some related information, maybe something like # Future development or something else equivalent.

def __call__(self, image, layer=None, force=False):
if force or self.should_run():
result = image.copy()
h, w, _ = result.shape
Copy link
Collaborator

@kwcckw kwcckw Apr 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line could be just h, w = result.shape[:2] because if the input is in grayscale, it will be facing error.

super().__init__(p=p)
self.imgx = imgx # width of the image
self.imgy = imgy # hieght of the image
self.n_rotation = random.randint(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar with the issue i mentioned above, so this should be initialized in the __call__.


def apply_augmentation(self):
# Applies the Augmentation to input data.
pattern_image = Image.new("RGB", (self.imgx, self.imgy))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any particular reason to use PIL instead of Numpy here? I think this overall section (line 78 - 106) can be just in Numpy?

c = int(round(255 * z / self.n_rotation)) # color
pixels[kx, ky] = (c, c, c) # # RGB value
# pattern_image = ImageOps.autocontrast(pattern_image) # increasing the contrast of the image
pattern_image.save(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually why we need to save the image and load the image again here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I have written a comment in Voronoi.py
We save it as a 300 dpi image and load it

(perlin_x, perlin_y),
)
image = Image.fromarray(img_array)
image.save("images/Voronoi_example.png", "PNG", dpi=(300, 300))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be same with quasicrystal, why we need to save and load it again?

Copy link
Contributor Author

@ss756 ss756 Apr 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @kwcckw I went through the link you sent. As per my understanding, they are also doing the same thing by saving the image as 300 dpi and reading it from memory. Let me know if I have misunderstood it so that I can make the changes in the new PR
image

:param window_size: height and width of patch, default value is 200
:type window_size: int
"""
h, w, _ = image.shape
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line should be replaced by h, w =image.shape[:2].

cv2.BORDER_CONSTANT,
value=[255, 255, 255],
)
h, w, _ = image.shape
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line should be replaced by h, w =image.shape[:2].

image[
initial_coords[1] : initial_coords[1] + hy,
initial_coords[0] : initial_coords[0] + wx,
:,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can just remove the : here, else it will facing error if input is grayscale. same with line 131 below.

def __call__(self, image, layer=None, force=False):
if force or self.should_run():
result = image.copy()
h, w, _ = result.shape
Copy link
Collaborator

@kwcckw kwcckw Apr 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line should be replaced by h, w = result.shape[:2], and line 179 below can be just :

result = result[self.ws : h + self.ws, self.ws : w + self.ws]

We might facing error with the additional : if the input is in grayscale. So you will need to test the augmentation with grayscale image too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add Pattern-based Distortion Generator
2 participants