Skip to content

Commit

Permalink
adding tests 16 bits to 12 bits
Browse files Browse the repository at this point in the history
  • Loading branch information
bigcat88 committed Jul 3, 2022
1 parent 6bfd3bf commit 3ab234f
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 68 deletions.
54 changes: 0 additions & 54 deletions tests/compare_hashes.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,58 +80,6 @@ def dhash(image, hash_size=8):
return diff


def colorhash(image, binbits=3):
"""
Color Hash computation.
Computes fractions of image in intensity, hue and saturation bins:
* the first binbits encode the black fraction of the image
* the next binbits encode the gray fraction of the remaining image (low saturation)
* the next 6*binbits encode the fraction in 6 bins of saturation, for highly saturated parts of the remaining image
* the next 6*binbits encode the fraction in 6 bins of saturation, for mildly saturated parts of the remaining image
@binbits number of bits to use to encode each pixel fractions
"""

# bin in hsv space:
intensity = numpy.asarray(image.convert("L")).flatten()
h, s, v = [numpy.asarray(v).flatten() for v in image.convert("HSV").split()]
# black bin
mask_black = intensity < 256 // 8
frac_black = mask_black.mean()
# gray bin (low saturation, but not black)
mask_gray = s < 256 // 3
frac_gray = numpy.logical_and(~mask_black, mask_gray).mean()
# two color bins (medium and high saturation, not in the two above)
mask_colors = numpy.logical_and(~mask_black, ~mask_gray)
mask_faint_colors = numpy.logical_and(mask_colors, s < 256 * 2 // 3)
mask_bright_colors = numpy.logical_and(mask_colors, s > 256 * 2 // 3)

c = max(1, mask_colors.sum())
# in the color bins, make sub-bins by hue
hue_bins = numpy.linspace(0, 255, 6 + 1)
if mask_faint_colors.any():
h_faint_counts, _ = numpy.histogram(h[mask_faint_colors], bins=hue_bins)
else:
h_faint_counts = numpy.zeros(len(hue_bins) - 1)
if mask_bright_colors.any():
h_bright_counts, _ = numpy.histogram(h[mask_bright_colors], bins=hue_bins)
else:
h_bright_counts = numpy.zeros(len(hue_bins) - 1)

# now we have fractions in each category (6*2 + 2 = 14 bins)
# convert to hash and discretize:
maxvalue = 2**binbits
values = [min(maxvalue - 1, int(frac_black * maxvalue)), min(maxvalue - 1, int(frac_gray * maxvalue))]
for counts in list(h_faint_counts) + list(h_bright_counts):
values.append(min(maxvalue - 1, int(counts * maxvalue * 1.0 / c)))
# print(values)
bitarray = []
for v in values:
bitarray += [v // (2 ** (binbits - i - 1)) % 2 ** (binbits - i) > 0 for i in range(binbits)]
return numpy.asarray(bitarray).reshape((-1, binbits))


def compare_hashes(pillow_images: list, hash_type="average", hash_size=16, max_difference=0):
image_hashes = []
for pillow_image in pillow_images:
Expand All @@ -140,8 +88,6 @@ def compare_hashes(pillow_images: list, hash_type="average", hash_size=16, max_d
pillow_image = ImageOps.exif_transpose(pillow_image)
if hash_type == "dhash":
image_hash = dhash(pillow_image, hash_size)
elif hash_type == "colorhash":
image_hash = colorhash(pillow_image)
else:
image_hash = average_hash(pillow_image, hash_size)
image_hash = image_hash.flatten()
Expand Down
56 changes: 48 additions & 8 deletions tests/convert_mode_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@


@pytest.mark.parametrize("mode", ("RGB;16", "BGR;16"))
def test_rgb8_to_16bit_color_mode(mode):
def test_rgb8_to_16_10_bit_color_mode(mode):
png_pillow = Image.open(Path("images/jpeg_gif_png/RGB_8.png"))
heif_file = from_pillow(png_pillow)
assert heif_file.bit_depth == 8
Expand All @@ -29,11 +29,31 @@ def test_rgb8_to_16bit_color_mode(mode):
heif_file = open_heif(out_heic, convert_hdr_to_8bit=False)
assert heif_file.bit_depth == 10
assert not heif_file.has_alpha
imagehash.compare_hashes([png_pillow, out_heic], hash_size=16, max_difference=0)
imagehash.compare_hashes([png_pillow, out_heic], hash_size=16)


@pytest.mark.parametrize("mode", ("RGB;16", "BGR;16"))
def test_rgb8_to_16_12_bit_color_mode(mode):
try:
options().save_to_12bit = True
png_pillow = Image.open(Path("images/jpeg_gif_png/RGB_8.png"))
heif_file = from_pillow(png_pillow)
assert heif_file.bit_depth == 8
heif_file[0].convert_to(mode)
out_heic = BytesIO()
heif_file.save(out_heic, quality=-1)
assert heif_file.bit_depth == 16
assert not heif_file.has_alpha
heif_file = open_heif(out_heic, convert_hdr_to_8bit=False)
assert heif_file.bit_depth == 12
assert not heif_file.has_alpha
imagehash.compare_hashes([png_pillow, out_heic], hash_size=8)
finally:
options().reset()


@pytest.mark.parametrize("mode", ("RGBA;16", "BGRA;16"))
def test_rgba8_to_16bit_color_mode(mode):
def test_rgba8_to_16_10_bit_color_mode(mode):
png_pillow = Image.open(Path("images/jpeg_gif_png/RGBA_8.png"))
heif_file = from_pillow(png_pillow)
assert heif_file.bit_depth == 8
Expand All @@ -45,7 +65,27 @@ def test_rgba8_to_16bit_color_mode(mode):
heif_file = open_heif(out_heic, convert_hdr_to_8bit=False)
assert heif_file.bit_depth == 10
assert heif_file.has_alpha
imagehash.compare_hashes([png_pillow, out_heic], hash_size=8, max_difference=0)
imagehash.compare_hashes([png_pillow, out_heic], hash_size=8)


@pytest.mark.parametrize("mode", ("RGBA;16", "BGRA;16"))
def test_rgba8_to_16_12_bit_color_mode(mode):
try:
options().save_to_12bit = True
png_pillow = Image.open(Path("images/jpeg_gif_png/RGBA_8.png"))
heif_file = from_pillow(png_pillow)
assert heif_file.bit_depth == 8
heif_file[0].convert_to(mode)
out_heic = BytesIO()
heif_file.save(out_heic, quality=-1)
assert heif_file.bit_depth == 16
assert heif_file.has_alpha
heif_file = open_heif(out_heic, convert_hdr_to_8bit=False)
assert heif_file.bit_depth == 12
assert heif_file.has_alpha
imagehash.compare_hashes([png_pillow, out_heic], hash_size=8)
finally:
options().reset()


@pytest.mark.parametrize("mode", ("RGB;16", "BGR;16"))
Expand All @@ -61,7 +101,7 @@ def test_rgb10_to_16bit_color_mode(mode):
heif_file = open_heif(out_heic, convert_hdr_to_8bit=False)
assert heif_file.bit_depth == 10
assert not heif_file.has_alpha
imagehash.compare_hashes([img_path, out_heic], hash_size=8, max_difference=0)
imagehash.compare_hashes([img_path, out_heic], hash_size=8)


@pytest.mark.parametrize("mode", ("RGBA;16", "BGRA;16"))
Expand All @@ -77,7 +117,7 @@ def test_rgba10_to_16bit_color_mode(mode):
heif_file = open_heif(out_heic, convert_hdr_to_8bit=False)
assert heif_file.bit_depth == 10
assert heif_file.has_alpha
imagehash.compare_hashes([img_path, out_heic], hash_size=8, max_difference=0)
imagehash.compare_hashes([img_path, out_heic], hash_size=8)


@pytest.mark.parametrize("mode", ("RGB;16", "BGR;16"))
Expand All @@ -93,7 +133,7 @@ def test_rgb12_to_16bit_color_mode(mode):
heif_file = open_heif(out_heic, convert_hdr_to_8bit=False)
assert heif_file.bit_depth == 10
assert not heif_file.has_alpha
imagehash.compare_hashes([img_path, out_heic], hash_size=8, max_difference=0)
imagehash.compare_hashes([img_path, out_heic], hash_size=8)


@pytest.mark.parametrize("mode", ("RGBA;16", "BGRA;16"))
Expand All @@ -109,4 +149,4 @@ def test_rgba12_to_16bit_color_mode(mode):
heif_file = open_heif(out_heic, convert_hdr_to_8bit=False)
assert heif_file.bit_depth == 10
assert heif_file.has_alpha
imagehash.compare_hashes([img_path, out_heic], hash_size=8, max_difference=0)
imagehash.compare_hashes([img_path, out_heic], hash_size=8)
46 changes: 42 additions & 4 deletions tests/opencv_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,32 +20,70 @@
register_heif_opener()


def test_save_bgr_16bit_color_mode():
def test_save_bgr_16bit_to_10_bit_color_mode():
image_path = "images/jpeg_gif_png/RGB_16.png"
cv_img = cv2.imread(image_path, cv2.IMREAD_UNCHANGED)
assert cv_img.shape[2] == 3 # 3 channels(BGR)
heif_file = from_bytes(mode="BGR;16", size=(cv_img.shape[1], cv_img.shape[0]), data=bytes(cv_img))
out_heic = BytesIO()
heif_file.save(out_heic, quality=-1)
assert open_heif(out_heic, convert_hdr_to_8bit=False).bit_depth == 10
heif_file = open_heif(out_heic, convert_hdr_to_8bit=False)
assert heif_file.bit_depth == 10
png_pillow = Image.open(Path(image_path))
heif_pillow = Image.open(out_heic)
imagehash.compare_hashes([png_pillow, heif_pillow], hash_type="dhash", hash_size=8, max_difference=0)


def test_save_bgra_16bit_color_mode():
def test_save_bgr_16bit_to_12_bit_color_mode():
try:
options().save_to_12bit = True
image_path = "images/jpeg_gif_png/RGB_16.png"
cv_img = cv2.imread(image_path, cv2.IMREAD_UNCHANGED)
assert cv_img.shape[2] == 3 # 3 channels(BGR)
heif_file = from_bytes(mode="BGR;16", size=(cv_img.shape[1], cv_img.shape[0]), data=bytes(cv_img))
out_heic = BytesIO()
heif_file.save(out_heic, quality=-1)
heif_file = open_heif(out_heic, convert_hdr_to_8bit=False)
assert heif_file.bit_depth == 12
png_pillow = Image.open(Path(image_path))
heif_pillow = Image.open(out_heic)
imagehash.compare_hashes([png_pillow, heif_pillow], hash_type="dhash", hash_size=8, max_difference=0)
finally:
options().reset()


def test_save_bgra_16bit_to_10_bit_color_mode():
image_path = "images/jpeg_gif_png/RGBA_16.png"
cv_img = cv2.imread(image_path, cv2.IMREAD_UNCHANGED)
assert cv_img.shape[2] == 4 # 4 channels(BGRA)
heif_file = from_bytes(mode="BGRA;16", size=(cv_img.shape[1], cv_img.shape[0]), data=bytes(cv_img))
out_heic = BytesIO()
heif_file.save(out_heic, quality=-1)
assert open_heif(out_heic, convert_hdr_to_8bit=False).bit_depth == 10
heif_file = open_heif(out_heic, convert_hdr_to_8bit=False)
assert heif_file.bit_depth == 10
png_pillow = Image.open(Path(image_path))
heif_pillow = Image.open(out_heic)
imagehash.compare_hashes([png_pillow, heif_pillow], hash_type="dhash", hash_size=8, max_difference=1)


def test_save_bgra_16bit_to_12_bit_color_mode():
try:
options().save_to_12bit = True
image_path = "images/jpeg_gif_png/RGBA_16.png"
cv_img = cv2.imread(image_path, cv2.IMREAD_UNCHANGED)
assert cv_img.shape[2] == 4 # 4 channels(BGRA)
heif_file = from_bytes(mode="BGRA;16", size=(cv_img.shape[1], cv_img.shape[0]), data=bytes(cv_img))
out_heic = BytesIO()
heif_file.save(out_heic, quality=-1)
heif_file = open_heif(out_heic, convert_hdr_to_8bit=False)
assert heif_file.bit_depth == 12
png_pillow = Image.open(Path(image_path))
heif_pillow = Image.open(out_heic)
imagehash.compare_hashes([png_pillow, heif_pillow], hash_type="dhash", hash_size=8, max_difference=1)
finally:
options().reset()


def test_save_bgr_8bit_color_mode():
image_path = "images/jpeg_gif_png/RGB_8.png"
cv_img = cv2.imread(image_path, cv2.IMREAD_UNCHANGED)
Expand Down
23 changes: 21 additions & 2 deletions tests/opener_encoder_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ def test_1_color_mode():
@pytest.mark.parametrize("img_path", ("images/jpeg_gif_png/I_color_mode_image.pgm",))
# "images/jpeg_gif_png/I_color_mode_image.png"
# when Pillow will be able to properly convert PNG from "I" mode to "L"(for imagehash) - add to test.
def test_I_color_modes(img_path):
def test_I_color_modes_to_10bit(img_path):
src_pillow = Image.open(Path(img_path))
assert src_pillow.mode == "I"
for mode in ("I", "I;16", "I;16L"):
Expand All @@ -164,7 +164,26 @@ def test_I_color_modes(img_path):
i_mode_img.save(out_heic, format="HEIF", quality=-1)
assert open_heif(out_heic, convert_hdr_to_8bit=False).bit_depth == 10
heic_pillow = Image.open(out_heic)
imagehash.compare_hashes([src_pillow, heic_pillow], hash_type="dhash", hash_size=8, max_difference=0)
imagehash.compare_hashes([src_pillow, heic_pillow], hash_type="dhash", hash_size=8)


@pytest.mark.parametrize("img_path", ("images/jpeg_gif_png/I_color_mode_image.pgm",))
# "images/jpeg_gif_png/I_color_mode_image.png"
# when Pillow will be able to properly convert PNG from "I" mode to "L"(for imagehash) - add to test.
def test_I_color_modes_to_12bit(img_path):
try:
options().save_to_12bit = True
src_pillow = Image.open(Path(img_path))
assert src_pillow.mode == "I"
for mode in ("I", "I;16", "I;16L"):
i_mode_img = src_pillow.convert(mode=mode)
out_heic = BytesIO()
i_mode_img.save(out_heic, format="HEIF", quality=-1)
assert open_heif(out_heic, convert_hdr_to_8bit=False).bit_depth == 12
heic_pillow = Image.open(out_heic)
imagehash.compare_hashes([src_pillow, heic_pillow], hash_type="dhash", hash_size=8)
finally:
options().reset()


def test_append_images():
Expand Down

0 comments on commit 3ab234f

Please sign in to comment.