Otsu now works for both types of images
parent
cc771141a2
commit
37c80f45cf
|
@ -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__":
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue