-
-
Notifications
You must be signed in to change notification settings - Fork 46.8k
Added Burkes dithering algorithm. #1916
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
Merged
Merged
Changes from 15 commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
201ca25
Added Burkes dithering algorithm
l3str4nge fa79687
Added unit tests for burkes algorithm
l3str4nge a157b47
Fix burkes algorithm
l3str4nge b92ccd3
Added some additional information
l3str4nge 0f2bbde
Fixed CI tests
l3str4nge 611e113
Update digital_image_processing/dithering/burkes.py
l3str4nge c872fc6
Update digital_image_processing/dithering/burkes.py
l3str4nge 8757600
Update digital_image_processing/dithering/burkes.py
l3str4nge 6b8e069
Propogate the += and add a doctest
cclauss f33f4ca
Fix doctest
l3str4nge 4cd6aa7
@staticmethod --> @ classmethod to ease testing
cclauss bea2a4d
def test_burkes(file_path):
cclauss 114ee8d
Fix for mypy checks
l3str4nge 66190e4
Fix variable order in get_greyscale
l3str4nge 823a98f
Fix get_greyscale method
l3str4nge b827c55
Fix get_greyscale method
l3str4nge 6ce1e16
3.753
cclauss File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
""" | ||
Implementation Burke's algorithm (dithering) | ||
""" | ||
from cv2 import destroyAllWindows, imread, imshow, waitKey | ||
import numpy as np | ||
|
||
|
||
class Burkes: | ||
""" | ||
Burke's algorithm is using for converting grayscale image to black and white version | ||
Source: Source: https://en.wikipedia.org/wiki/Dither | ||
|
||
Note: | ||
* Best results are given with threshold= ~1/2 * max greyscale value. | ||
* This implementation get RGB image and converts it to greyscale in runtime. | ||
""" | ||
|
||
def __init__(self, input_img, threshold: int): | ||
self.min_threshold = 0 | ||
# max greyscale value for #FFFFFF | ||
self.max_threshold = int(self.get_greyscale(255, 255, 255)) | ||
|
||
if not self.min_threshold < threshold < self.max_threshold: | ||
raise ValueError(f"Factor value should be from 0 to {self.max_threshold}") | ||
|
||
self.input_img = input_img | ||
self.threshold = threshold | ||
self.width, self.height = self.input_img.shape[1], self.input_img.shape[0] | ||
|
||
# error table size (+4 columns and +1 row) greater than input image because of | ||
# lack of if statements | ||
self.error_table = [ | ||
[0 for _ in range(self.height + 4)] for __ in range(self.width + 1) | ||
] | ||
self.output_img = np.ones((self.width, self.height, 3), np.uint8) * 255 | ||
|
||
@classmethod | ||
def get_greyscale(cls, blue: int, green: int, red: int) -> float: | ||
""" | ||
>>> Burkes.get_greyscale(5, 4, 3) | ||
3.5557999999999996 | ||
""" | ||
return 0.114 * blue + 0.587 * green + 0.2126 * red | ||
|
||
def process(self) -> None: | ||
for y in range(self.height): | ||
for x in range(self.width): | ||
greyscale = int(self.get_greyscale(*self.input_img[y][x])) | ||
if self.threshold > greyscale + self.error_table[y][x]: | ||
self.output_img[y][x] = (0, 0, 0) | ||
current_error = greyscale + self.error_table[x][y] | ||
else: | ||
self.output_img[y][x] = (255, 255, 255) | ||
current_error = greyscale + self.error_table[x][y] - 255 | ||
""" | ||
Burkes error propagation (`*` is current pixel): | ||
|
||
* 8/32 4/32 | ||
2/32 4/32 8/32 4/32 2/32 | ||
""" | ||
self.error_table[y][x + 1] += int(8 / 32 * current_error) | ||
self.error_table[y][x + 2] += int(4 / 32 * current_error) | ||
self.error_table[y + 1][x] += int(8 / 32 * current_error) | ||
self.error_table[y + 1][x + 1] += int(4 / 32 * current_error) | ||
self.error_table[y + 1][x + 2] += int(2 / 32 * current_error) | ||
self.error_table[y + 1][x - 1] += int(4 / 32 * current_error) | ||
self.error_table[y + 1][x - 2] += int(2 / 32 * current_error) | ||
|
||
|
||
if __name__ == "__main__": | ||
# create Burke's instances with original images in greyscale | ||
burkes_instances = [ | ||
Burkes(imread("image_data/lena.jpg", 1), threshold) | ||
for threshold in (1, 126, 130, 140) | ||
] | ||
|
||
for burkes in burkes_instances: | ||
burkes.process() | ||
|
||
for burkes in burkes_instances: | ||
imshow( | ||
f"Original image with dithering threshold: {burkes.threshold}", | ||
burkes.output_img, | ||
) | ||
|
||
waitKey(0) | ||
destroyAllWindows() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.