Otsu now works for both types of images

main
Gasper Spagnolo 2022-10-22 14:29:12 +02:00
parent cc771141a2
commit 37c80f45cf
2 changed files with 66 additions and 24 deletions

View File

@ -66,14 +66,12 @@ def one_c(image: npt.NDArray[np.float64]) -> None:
axs[0].imshow(cutout_0, cmap='gray')
axs[0].set(title='Channel 0')
axs[1].imshow(cutout_1, cmap='gray')
axs[1].set(title='Channel 1')
axs[2].imshow(cutout_2, cmap='gray')
axs[2].set(title='Channel 2')
plt.show
plt.show()
def one_d(startx: int, endx: int, starty: int, endy: int, image:npt.NDArray[np.float64]) -> None:
"""
@ -94,8 +92,8 @@ def one_d(startx: int, endx: int, starty: int, endy: int, image:npt.NDArray[np.f
Question: How is inverting a grayscale value defined for uint8 ?
Answer:
"""
inverted_image = uz_image.invert_coloured_image_part(image, startx, endx, starty, endy)
fig, axs = plt.subplots(1, 2)
fig.suptitle("Lomberlini")
@ -144,11 +142,11 @@ def excercise_two() -> None:
size where the value of pixels is determined by whether the value of the corresponding
pixels in the source image is greater or lower than the given threshold.
"""
#two_a()
two_a()
#two_b('./images/bird.jpg', 100, 20)
#two_c('./images/bird.jpg', 20, 100)
#two_d()
two_e(uz.imread_gray('./images/bird.jpg', uz.ImageType.uint8).astype(np.uint8))
#two_e(uz.imread_gray('./images/bird.jpg', uz.ImageType.uint8).astype(np.uint8))
def two_a() -> tuple[npt.NDArray[np.float64], npt.NDArray[np.uint8]]:
@ -159,9 +157,8 @@ def two_a() -> tuple[npt.NDArray[np.float64], npt.NDArray[np.uint8]]:
bird.jpg. Display both the image and the mask.
"""
random_number = random.random()
TRESHOLD = 75/255 # Found using otsu method
image = uz.imread_gray("./images/bird.jpg", uz.ImageType.float64)
image = uz_image.imread_gray("./images/bird.jpg", uz_image.ImageType.float64)
TRESHOLD = uz_image.calculate_best_treshold_using_otsu_method(image) / 255
binary_mask = image.copy()
if random_number < 0.5:
@ -170,17 +167,15 @@ def two_a() -> tuple[npt.NDArray[np.float64], npt.NDArray[np.uint8]]:
else:
binary_mask = np.where(binary_mask < TRESHOLD, 0, 1)
binary_mask = uz.convert_float64_array_to_uint8_array(binary_mask)
binary_mask = binary_mask.astype(np.uint8)
fig, (ax0, ax1) = plt.subplots(1, 2)
fig, axs = plt.subplots(1, 2)
fig.suptitle("Birdie and its mask")
ax0.imshow(image, cmap="gray")
ax1.imshow(binary_mask, cmap="gray")
ax0.set(title="Original image")
ax1.set(title="Mask of birdie")
axs[0].imshow(image, cmap="gray")
axs[0].set(title="Original image")
axs[1].imshow(binary_mask, cmap="gray")
axs[1].set(title="Mask of birdie")
plt.show()
return (image, binary_mask)
@ -594,8 +589,8 @@ def three_e():
def main() -> None:
excercise_one()
#excercise_two()
#excercise_one()
excercise_two()
#excercise_three()
if __name__ == "__main__":

View File

@ -24,7 +24,7 @@ def imread(path: str, type: ImageType) -> npt.NDArray[np.float64] or npt.NDArray
elif type == ImageType.uint8:
return I
raise Exception("Wrong image format picked!")
raise Exception("Unrecognized image format!")
def imread_gray(path: str, type: ImageType) -> npt.NDArray[np.float64] or npt.NDArray[np.uint8]:
@ -42,7 +42,7 @@ def imread_gray(path: str, type: ImageType) -> npt.NDArray[np.float64] or npt.ND
elif type == ImageType.uint8:
return I
raise Exception("Wrong image format picked!")
raise Exception("Unrecognized image format!")
def signal_show(*signals):
"""
@ -86,6 +86,9 @@ def transform_coloured_image_to_grayscale(image: npt.NDArray[np.float64]) -> npt
return grayscale_image
def invert_coloured_image_part(image: npt.NDArray[np.float64] or npt.NDArray[np.uint8], startx: int, endx: int, starty: int, endy: int) -> npt.NDArray[np.float64] or npt.NDArray[np.uint8]:
"""
Accepts image, starting position end end position for axes x & y. Returns whole image with inverted part.
"""
inverted_image = image.copy()
if image.dtype.type == np.float64:
@ -94,7 +97,6 @@ def invert_coloured_image_part(image: npt.NDArray[np.float64] or npt.NDArray[np.
inverted_image[i, j, 0] = 1 - image[i, j, 0]
inverted_image[i, j, 1] = 1 - image[i, j, 1]
inverted_image[i, j, 2] = 1 - image[i, j, 2]
print('wtf')
return inverted_image
elif image.dtype.type == np.uint8:
for i in range(startx, endx):
@ -107,8 +109,53 @@ def invert_coloured_image_part(image: npt.NDArray[np.float64] or npt.NDArray[np.
raise Exception("Unrecognized image format!")
def invert_coloured_image(image: npt.NDArray[np.float64] or npt.NDArray[np.uint8]) -> npt.NDArray[np.float64] or npt.NDArray[np.uint8]:
"""
Accepts image and inverts it
"""
return invert_coloured_image_part(image, 0, image.shape[0], 0, image.shape[1])
def calculate_best_treshold_using_otsu_method(image: npt.NDArray[np.float64] or npt.NDArray[np.uint8]) -> int:
"""
Accepts image and returns best treshold using otsu method
"""
def convert_float64_array_to_uint8_array(a: npt.NDArray[np.float64]) -> npt.NDArray[np.uint8]:
return a.astype(np.uint8)
if image.dtype.type == np.float64:
im = image.copy()
im = im * (255.0/im.max())
elif image.dtype.type == np.uint8:
im = image.copy()
else:
raise Exception("Unrecognized image format!")
treshold_range = np.arange(np.max(im) + 1)
criterias = []
for treshold in treshold_range:
# create the thresholded image
thresholded_im = np.zeros(im.shape)
thresholded_im[im >= treshold] = 1
# compute weights
nb_pixels = im.size
nb_pixels1 = np.count_nonzero(thresholded_im)
weight1 = nb_pixels1 / nb_pixels
weight0 = 1 - weight1
# if one the classes is empty, eg all pixels are below or above the threshold, that threshold will not be considered
# in the search for the best threshold
if weight1 == 0 or weight0 == 0:
continue
# find all pixels belonging to each class
val_pixels1 = im[thresholded_im == 1]
val_pixels0 = im[thresholded_im == 0]
# compute variance of these classes
var0 = np.var(val_pixels0) if len(val_pixels0) > 0 else 0
var1 = np.var(val_pixels1) if len(val_pixels1) > 0 else 0
criterias.append( weight0 * var0 + weight1 * var1)
best_threshold = treshold_range[np.argmin(criterias)]
return best_threshold