Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
abetusk committed Oct 30, 2019
2 parents 9217119 + 953a38c commit ebd2ec4
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 72 deletions.
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Have a look at [this post](http://satyarth.me/articles/pixel-sorting/) or [/r/pi

### Dependencies

Tested with python3. Should work with python2 as well.
Python 3.6 or greater.

Requires Pillow. `pip install Pillow` should work. If not, see [here](https://pillow.readthedocs.org/en/3.0.0/installation.html#linux-installation) for details.

Expand Down Expand Up @@ -42,6 +42,8 @@ Char. length | `-c` | Characteristic length for the random width generator. Use
Angle | `-a` | Angle at which you're pixel sorting in degrees. `0` (horizontal) by default.
External int file | `-f` | Image used to define intervals. Must be black and white.
Sorting function | `-s` | Sorting function to use for sorting the pixels.
Mask | `-m` | Image used for masking parts of the image.
Logging Level | `-l` | Level of logging statements made visible. Choices include `DEBUG`, `INFO`, `WARNING`, `ERROR`, and `CRITICAL`.

#### Interval Functions

Expand Down Expand Up @@ -86,6 +88,14 @@ Sorting function | Description

![file](/examples/file.png)

* `mask`: Mask taken from image specified with `-m`. Must be black and white.

`python3 pixelsort.py examples/image.jpg -i random -c 20 -m examples/mask.png`

![file](/examples/mask.png)

![file](/examples/masked.png)

### todo

* Allow defining different intervals for different channels.
Expand Down
38 changes: 27 additions & 11 deletions argparams.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import util
import interval
import sorting
import logging


def read_interval_function(int_function):
Expand All @@ -16,8 +17,8 @@ def read_interval_function(int_function):
"none": interval.none
}[int_function]
except KeyError:
print(
"[WARNING] Invalid interval function specified, defaulting to 'threshold'.")
logging.warning(
"Invalid interval function specified, defaulting to 'threshold'.")
return interval.threshold


Expand All @@ -31,7 +32,8 @@ def read_sorting_function(sorting_function):
"saturation": sorting.saturation
}[sorting_function]
except KeyError:
print("[WARNING] Invalid sorting function specified, defaulting to 'lightness'.")
logging.warning(
"Invalid sorting function specified, defaulting to 'lightness'.")
return sorting.lightness


Expand All @@ -56,8 +58,16 @@ def parse_args():
help="What percentage of intervals are NOT sorted", default=0)
p.add_argument("-s", "--sorting_function",
help="lightness, intensity, hue, saturation, minimum", default="lightness")
p.add_argument("-m", "--mask",
help="Image used for masking parts of the image")
p.add_argument("-l", "--log_level", default="WARNING", help="Print more or less info",
choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"])

__args = p.parse_args()

logging.basicConfig(
format="%(name)s: %(levelname)s - %(message)s", level=logging.getLevelName(__args.log_level))

return {
"image_input_path": __args.image,
"output_image_path": __args.output,
Expand All @@ -68,21 +78,27 @@ def parse_args():
"clength": __args.clength,
"angle": __args.angle,
"randomness": __args.randomness,
"sorting_function": __args.sorting_function
"sorting_function": __args.sorting_function,
"mask": __args.mask
}


def verify_args(args):

print("Interval function: ", args["interval_function"])
# Informational logs
logging.info(f"Interval function: {args['interval_function']}")
if args["interval_function"] in ["threshold", "edges", "file-edges"]:
print("Lower threshold: ", args["bottom_threshold"])
logging.info(f"Lower threshold: {args['bottom_threshold']}")
if args["interval_function"] == "threshold":
print("Upper threshold: ", args["upper_threshold"])
logging.info(f"Upper threshold: {args['upper_threshold']}")
if args["interval_function"] in ["random", "waves"]:
print("Characteristic length: ", args["clength"])
print("Randomness: ", args["randomness"], "%")

logging.info(f"Characteristic length: {args['clength']}")
logging.info(f"Randomness: {args['randomness']}%")
# Actual validation
if not args["output_image_path"]:
output = f"{util.id_generator()}.png"
logging.warning(
f"No output path provided, defaulting to {output}")
args["output_image_path"] = output
args["interval_function"] = read_interval_function(
args["interval_function"])
args["sorting_function"] = read_sorting_function(args["sorting_function"])
Binary file added examples/mask.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/masked.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
79 changes: 42 additions & 37 deletions interval.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import random as rand
import constants
import util

import logging

def edge(pixels, args):
img = Image.open(args["image_input_path"])
Expand All @@ -19,62 +19,62 @@ def edge(pixels, args):
edge_pixels = []
intervals = []

print("Defining edges...")
logging.debug("Defining edges...")
for y in range(img.size[1]):
filter_pixels.append([])
for x in range(img.size[0]):
filter_pixels[y].append(edge_data[x, y])

print("Thresholding...")
logging.debug("Thresholding...")
for y in range(len(pixels)):
edge_pixels.append([])
for x in range(len(pixels[0])):
for x in range(len(pixels[y])):
if util.lightness(filter_pixels[y][x]) < args["bottom_threshold"]:
edge_pixels[y].append(constants.white_pixel)
else:
edge_pixels[y].append(constants.black_pixel)

print("Cleaning up edges...")
logging.debug("Cleaning up edges...")
for y in range(len(pixels) - 1, 1, -1):
for x in range(len(pixels[0]) - 1, 1, -1):
for x in range(len(pixels[y]) - 1, 1, -1):
if edge_pixels[y][x] == constants.black_pixel and edge_pixels[y][x - 1] == constants.black_pixel:
edge_pixels[y][x] = constants.white_pixel

print("Defining intervals...")
logging.debug("Defining intervals...")
for y in range(len(pixels)):
intervals.append([])
for x in range(len(pixels[0])):
for x in range(len(pixels[y])):
if edge_pixels[y][x] == constants.black_pixel:
intervals[y].append(x)
intervals[y].append(len(pixels[0]))
intervals[y].append(len(pixels[y]))
return intervals


def threshold(pixels, args):
intervals = []

print("Defining intervals...")
logging.debug("Defining intervals...")
for y in range(len(pixels)):
intervals.append([])
for x in range(len(pixels[0])):
for x in range(len(pixels[y])):
if util.lightness(pixels[y][x]) < args["bottom_threshold"] or util.lightness(pixels[y][x]) > args["upper_threshold"]:
intervals[y].append(x)
intervals[y].append(len(pixels[0]))
intervals[y].append(len(pixels[y]))
return intervals


def random(pixels, args):
intervals = []

print("Defining intervals...")
logging.debug("Defining intervals...")
for y in range(len(pixels)):
intervals.append([])
x = 0
while True:
width = util.random_width(args["clength"])
x += width
if x > len(pixels[0]):
intervals[y].append(len(pixels[0]))
if x > len(pixels[y]):
intervals[y].append(len(pixels[y]))
break
else:
intervals[y].append(x)
Expand All @@ -84,15 +84,15 @@ def random(pixels, args):
def waves(pixels, args):
intervals = []

print("Defining intervals...")
logging.debug("Defining intervals...")
for y in range(len(pixels)):
intervals.append([])
x = 0
while True:
width = args["clength"] + rand.randint(0, 10)
x += width
if x > len(pixels[0]):
intervals[y].append(len(pixels[0]))
if x > len(pixels[y]):
intervals[y].append(len(pixels[y]))
break
else:
intervals[y].append(x)
Expand All @@ -103,36 +103,32 @@ def file_mask(pixels, args):
intervals = []
file_pixels = []

img = Image.open(args["interval_file_path"])
img = img.convert('RGBA')
img = img.rotate(args["angle"], expand=True)
img = load_interval_file(args)
data = img.load()
for y in range(img.size[1]):
file_pixels.append([])
for x in range(img.size[0]):
file_pixels[y].append(data[x, y])

print("Cleaning up edges...")
logging.debug("Cleaning up edges...")
for y in range(len(pixels) - 1, 1, -1):
for x in range(len(pixels[0]) - 1, 1, -1):
for x in range(len(pixels[y]) - 1, 1, -1):
if file_pixels[y][x] == constants.black_pixel and file_pixels[y][x - 1] == constants.black_pixel:
file_pixels[y][x] = constants.white_pixel

print("Defining intervals...")
logging.debug("Defining intervals...")
for y in range(len(pixels)):
intervals.append([])
for x in range(len(pixels[0])):
for x in range(len(pixels[y])):
if file_pixels[y][x] == constants.black_pixel:
intervals[y].append(x)
intervals[y].append(len(pixels[0]))
intervals[y].append(len(pixels[y]))

return intervals


def file_edges(pixels, args):
img = Image.open(args["interval_file_path"])
img = img.rotate(args["angle"], expand=True)
img = img.resize((len(pixels[0]), len(pixels)), Image.ANTIALIAS)
img = load_interval_file(args)
edges = img.filter(ImageFilter.FIND_EDGES)
edges = edges.convert('RGBA')
edge_data = edges.load()
Expand All @@ -141,34 +137,34 @@ def file_edges(pixels, args):
edge_pixels = []
intervals = []

print("Defining edges...")
logging.debug("Defining edges...")
for y in range(img.size[1]):
filter_pixels.append([])
for x in range(img.size[0]):
filter_pixels[y].append(edge_data[x, y])

print("Thresholding...")
logging.debug("Thresholding...")
for y in range(len(pixels)):
edge_pixels.append([])
for x in range(len(pixels[0])):
for x in range(len(pixels[y])):
if util.lightness(filter_pixels[y][x]) < args["bottom_threshold"]:
edge_pixels[y].append(constants.white_pixel)
else:
edge_pixels[y].append(constants.black_pixel)

print("Cleaning up edges...")
logging.debug("Cleaning up edges...")
for y in range(len(pixels) - 1, 1, -1):
for x in range(len(pixels[0]) - 1, 1, -1):
for x in range(len(pixels[y]) - 1, 1, -1):
if edge_pixels[y][x] == constants.black_pixel and edge_pixels[y][x - 1] == constants.black_pixel:
edge_pixels[y][x] = constants.white_pixel

print("Defining intervals...")
logging.debug("Defining intervals...")
for y in range(len(pixels)):
intervals.append([])
for x in range(len(pixels[0])):
for x in range(len(pixels[y])):
if edge_pixels[y][x] == constants.black_pixel:
intervals[y].append(x)
intervals[y].append(len(pixels[0]))
intervals[y].append(len(pixels[y]))
return intervals


Expand All @@ -177,3 +173,12 @@ def none(pixels, args):
for y in range(len(pixels)):
intervals.append([len(pixels[y])])
return intervals

# Helper functions

def load_interval_file(args):
img = Image.open(args["interval_file_path"])
img = img.convert('RGBA')
img = img.rotate(args["angle"], expand=True)
img = img.resize(Image.open(args["image_input_path"]).size, Image.ANTIALIAS)
return img
Loading

0 comments on commit ebd2ec4

Please sign in to comment.