Skip to content

Commit

Permalink
working refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
levi.borodenko committed Dec 22, 2021
1 parent 5015b29 commit b5261b8
Show file tree
Hide file tree
Showing 7 changed files with 44 additions and 39 deletions.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"python.formatting.provider": "black"
}
17 changes: 9 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ _Transform any image into a prime number that looks like the image if glanced up

We proceed in 5 steps:

1. We resize the image to contain at most a `--max_digits` amount of pixels.
1. We resize the image to contain at most a `--max-digits` amount of pixels.

2. Run various image processing steps like edge enhancement and smoothing before converting the image into grey-scale.

Expand All @@ -29,25 +29,26 @@ You can also import the `PrimeImage` class from `primify.base` or use `cli.py` a
### Command-line tool

```
usage: primify [-h] [--image IMAGE_PATH] [--max_digits MAX_DIGITS] [--output_file OUTPUT_FILE] [-v]
usage: primify [-h] [--image IMAGE_PATH] [--max-digits MAX_DIGITS]
[--output-file OUTPUT_FILE]
Command-line tool for converting images to primes
optional arguments:
-h, --help show this help message and exit
--image IMAGE_PATH Source image to be converted
--max_digits MAX_DIGITS
--image IMAGE_PATH, -i IMAGE_PATH
Source image to be converted
--max-digits MAX_DIGITS, -d MAX_DIGITS
Maximal number of digits the prime can have
--output_file OUTPUT_FILE
--output-file OUTPUT_FILE, -o OUTPUT_FILE
File name of the file containing the prime.
-v Verbose output
Made by Levi B.
```

Thus, if you have the source image at `./source.png` and you want to convert it into a prime contained in `./prime/prime.txt` which has at most 5000 digits. Then you should run:
Thus, if you have the source image at `./source.png` and you want to convert it into a prime contained in `./prime.txt` which has at most 5000 digits. Then you should run:

`primify -v --image ./source.png --max_digits 5000 --output_file prime/prime.txt`
`primify -v --image ./source.png --max-digits 5000 --output-file prime.txt`

### Importing the PrimeImage class

Expand Down
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ install_requires =
Pillow==8.4.0
sympy==1.9
gmpy2==2.1.1
rich==10.16.1

[options.packages.find]
where = src
Expand Down
35 changes: 15 additions & 20 deletions src/primify/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,6 @@ class PrimeImage:
max_digits (int): Maximal number of digits in the resulting prime.
converion_method (int): number between 0 and 2. Play around to see
which one produces the clearest image.
verbose (bool): Verbose status reporting in terminal if True
output_file (Path): Output file (default: "./prime.txt")
Note:
Expand All @@ -64,7 +59,7 @@ class PrimeImage:
if you have the source image at `./source.png` and you want to convert it into a prime contained in `./prime/prime.txt` which has at most 5000 digits and using conversion method 0 (other options are 1 or 2). Then you should run:
`primify -v --image ./source.png --max_digits 5000 --method 0 --output_dir ./prime/ --output_file prime.txt`
`primify --image ./source.png --max_digits 5000 --output_file prime/prime.txt`
Expand All @@ -76,7 +71,6 @@ def __init__(
max_digits: int = 5000,
conversion_method: Literal[0, 1, 2, 3] = 1,
output_file_path: Union[Path, str] = Path("./prime.txt"),
verbose: bool = False,
):

self.image_path = Path(image_path)
Expand All @@ -85,13 +79,6 @@ def __init__(
# saving conversion method.
self.conversion_method = conversion_method

if verbose:
logger.setLevel(logging.DEBUG)

# check if verbose is boolean
if not isinstance(verbose, bool):
raise ValueError("Verbosity must be True or False")

# check if max_digits is and integer and greater than 10
if not (isinstance(self.max_digits, int) or (self.max_digits < 10)):
raise ValueError("max_digits should be an integer and > 10")
Expand All @@ -105,7 +92,7 @@ def __init__(
@staticmethod
def resize_for_pixel_limit(image: Image.Image, max_pixels: int) -> Image.Image:
"""
We resize the image to contain at most max_size pixels
We resize the image to contain at most max_pixels pixels
description:
The reason is that we don't want to find too large primes
Expand All @@ -122,8 +109,8 @@ def resize_for_pixel_limit(image: Image.Image, max_pixels: int) -> Image.Image:
x_scaled, y_scaled = int(x / scale_factor), int(y / scale_factor)

image = image.resize((x_scaled, y_scaled))

console.log(f"Resized image to be {image.size[0]} x {image.size[1]} pixels.")

return image

@staticmethod
Expand All @@ -134,7 +121,7 @@ def quantize_image(image: Image.Image) -> Image.Image:
# smooth the image to have better regions of constancy after quanitsation
image = image.filter(ImageFilter.MinFilter)

# now convert to quantized greyscale
# now convert to greyscale
grey_scale_image = image.convert("L")

# make sure we use the entire digit pallet
Expand Down Expand Up @@ -173,9 +160,16 @@ def get_prime(self) -> ImageNumber:

with console.status("Searching for a similar looking prime."):

# initiate helping prime finder. Must faster than just using nextprime()
# initiate helping prime finder. Much faster than just using nextprime()
n_processes = max(
1, mp.cpu_count() - 1
) # at least one core should remain free

console.log(
f"Initializing multi-process prime finder with {n_processes} workers."
)
prime_finder = NextPrimeFinder(
value=image_number.value, n_workers=max(1, mp.cpu_count() - 1)
value=image_number.value, n_workers=n_processes
)
next_prime = prime_finder.find_next_prime()

Expand All @@ -191,7 +185,8 @@ def get_prime(self) -> ImageNumber:
if __name__ == "__main__":

instance = PrimeImage(
image_path="examples/images/tao.png", max_digits=5000, verbose=True
image_path="examples/images/tao.png",
max_digits=5000,
)

instance.get_prime()
13 changes: 5 additions & 8 deletions src/primify/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ def parse_args(args):

parser.add_argument(
"--image",
"-i",
action="store",
type=Path,
default="./prime.png",
Expand All @@ -36,7 +37,8 @@ def parse_args(args):
)

parser.add_argument(
"--max_digits",
"--max-digits",
"-d",
action="store",
type=int,
default=5000,
Expand All @@ -45,18 +47,15 @@ def parse_args(args):
)

parser.add_argument(
"--output_file",
"--output-file",
"-o",
action="store",
type=Path,
default="prime.txt",
help="File name of the file containing the prime.",
dest="output_file",
)

parser.add_argument(
"-v", action="store_true", dest="verbose", help="Verbose output"
)

return parser.parse_args(args)


Expand All @@ -71,8 +70,6 @@ def main(args):
a = PrimeImage(
image_path=args.image_path,
max_digits=args.max_digits,
conversion_method=args.method,
verbose=args.verbose,
output_file_path=args.output_file,
)

Expand Down
6 changes: 3 additions & 3 deletions src/primify/prime_finder.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from itertools import islice
import math
import time
from typing import Iterator, List, Optional
from typing import Iterator, List, Optional, Set
import multiprocessing as mp
from sympy import isprime
import logging
Expand Down Expand Up @@ -45,7 +45,7 @@ def find_next_prime(self) -> int:
(candidate, found_prime) for candidate in self.prime_candidates()
)

results: List[Optional[int]] = []
results: Set[Optional[int]] = set()
search_start = time.time()
while not found_prime.is_set():
console.log(
Expand All @@ -56,7 +56,7 @@ def find_next_prime(self) -> int:
islice(candidate_iter, self.expected_n_primality_tests),
)

results.extend(result)
results |= set(result)

console.log(
f"Got one! Next prime was found within {int(time.time()- search_start) + 1}s"
Expand Down
8 changes: 8 additions & 0 deletions tests/test_image_ops.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
from PIL import Image
from sympy import isprime

from primify.base import PrimeImage
from primify.prime_finder import NextPrimeFinder


def test_prime_finder():
almost_prime = 2 ** 67 - 2
instance = NextPrimeFinder(almost_prime, n_workers=1)
assert isprime(instance.find_next_prime())


def test_resize_with_pixel_limit(test_image: Image.Image, test_max_digits: int):
Expand Down

0 comments on commit b5261b8

Please sign in to comment.