Erosion and Dilated getting swapped - python

I tried using morphological operations: Erosion and Dilation using skimage module. However, the results seem interchanged for me. Dilation should add pixels to the boundaries and erosion should remove them. But in my case, it is happening just the opposite.
Code:
from skimage import data, morphology
from matplotlib import pyplot as plt
def plot_comparison(original, first, second, title1, title2):
fig, (ax1, ax2, ax3) = plt.subplots(nrows=1, ncols=3, sharex=True, sharey=True, figsize=(10,8))
ax1.imshow(original, cmap='gray')
ax1.set_title('Original')
ax1.axis('off')
ax2.imshow(first, cmap='gray')
ax2.set_title(title1)
ax2.axis('off')
ax3.imshow(second, cmap='gray')
ax3.set_title(title2)
ax3.axis('off')
plt.show()
selem = morphology.rectangle(12, 6)
horse = data.horse()
eroded = morphology.binary_erosion(horse, selem=selem)
dilated = morphology.binary_dilation(horse, selem=selem)
plot_comparison(horse, eroded, dilated, 'Eroded', 'Dilated')
Output:

Related

Displaying lowest values as white

I have the following 3x3 matrix which I would like to plot:
import matplotlib.cm
import matplotlib.pyplot as plt
import numpy as np
import copy
cmap = copy.copy(cm.get_cmap("Blues"))
cmap.set_bad('white')
fig = plt.figure(figsize=(15, 10))
img = np.array([[-0.9, -0.5599234, 0.21042876],[-0.42735877, 0.61514954, -0.74305015],[0.61958201, -0.04358633, 0.78672511]])
im = plt.imshow(img, origin='upper', cmap=cmap)
The result looks as follows:
As visible the top left entry is smallest and should be displayed as white. How can I change it in such a way so that the smallest entry is displayed in white?
Second, is there a way to adapt the colormap such that it starts with darker values?
One way to have a colormap start with white, is to create a ListedColormap, e.g. going from white to darkblue. To start with the darkest color, just reverse the list of colors for the ListedColormap.
A standard colormap can be reversed, just by appending _r at the end of its name.
One way to create a colormap going from a mid-range to a dark blue, is creating a ListedColormap where the rgb-values are given as hexadecimal.
Here are some examples:
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
import numpy as np
img = np.array([[-0.9, -0.5599234, 0.21042876], [-0.42735877, 0.61514954, -0.74305015], [0.61958201, -0.04358633, 0.78672511]])
fig, axs = plt.subplots(ncols=3, figsize=(12, 5))
cmap0 = LinearSegmentedColormap.from_list('', ['white', 'darkblue'])
cmap1 = 'Blues_r'
cmap2 = LinearSegmentedColormap.from_list('', ['#aaddee', '#000077'])
for ax, cmap in zip(axs, [cmap0, cmap1, cmap2]):
im = ax.imshow(img, origin='upper', cmap=cmap)
plt.colorbar(im, ax=ax, orientation='horizontal', pad=0.05)
ax.set_xticks([0, 1, 2])
ax.set_yticks([0, 1, 2])
ax.tick_params(labelbottom=False, labelleft=False, length=0) # hide ticks, but use position for a grid
ax.grid(True, color='white')
axs[0].set_title("Colormap from white to darkblue")
axs[1].set_title("Reversed blues colormap")
axs[2].set_title("Custom darker blues colormap")
plt.show()
Also of interest might be Seaborn's palette functions, which provide additional ways to create colormaps (the parameter as_cmap=True is needed for these functions to return a colormap).

Open saved png's by savefig to plot them in subplots

I saved plots with savefig like plt.savefig('1.png') and now I want to adjust them to determined subplots like:
import matplotlib.pyplot as plt
from PIL import Image
img1 = Image.open("1.png")
img1 = Image.open("2.png")
img1 = Image.open("3.png")
fig, (ax_1, ax_2, ax_3) = plt.subplots(nrows=3, ncols=1,
sharex=True, figsize=(8.27,11.7))
ax_1.set_title('Plot1')
ax_1 = img1
ax_2.set_title('Plot2')
ax_2 = img2
ax_3.set_title('Plot3')
ax_3 = img3
fig.suptitle('Name')
plt.show()
But I get 3 empty plots without an error
Use ax.imshow():
import matplotlib.pyplot as plt
from PIL import Image
img1 = Image.open("1.png")
img1 = Image.open("2.png")
img1 = Image.open("3.png")
fig, (ax_1, ax_2, ax_3) = plt.subplots(nrows=3, ncols=1,
sharex=True, figsize=(8.27,11.7))
ax_1.set_title('Plot1')
ax_1.imshow(img1)
ax_2.set_title('Plot2')
ax_2.imshow(img2)
ax_3.set_title('Plot3')
ax_3.imshow(img3)
fig.suptitle('Name')
plt.show()
If you want to remove the ticks and tick labels, you can add ax.axis('off') for every axis you to remove them.

How to get a lighter "jet" colormap in matplotlib

I am trying to make a background color for clusters, but have no idea how to make jet colormap brighter or darker.
Could someone help me?
It will surely depend on how you define "lighter" or "darker". A useful definition would be to multiply the lightness channel of the colors in HSL space. This could look like
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import colors as mcolors
import colorsys
def man_cmap(cmap, value=1.):
colors = cmap(np.arange(cmap.N))
hls = np.array([colorsys.rgb_to_hls(*c) for c in colors[:,:3]])
hls[:,1] *= value
rgb = np.clip(np.array([colorsys.hls_to_rgb(*c) for c in hls]), 0,1)
return mcolors.LinearSegmentedColormap.from_list("", rgb)
cmap = plt.cm.get_cmap("jet")
fig, (ax1, ax2, ax3) = plt.subplots(3)
x=np.linspace(0,1,64)
sc = ax1.scatter(x,np.ones_like(x), c=x, cmap=cmap)
fig.colorbar(sc, ax=ax1, orientation="horizontal")
sc = ax2.scatter(x,np.ones_like(x), c=x, cmap=man_cmap(cmap, 0.75))
fig.colorbar(sc, ax=ax2, orientation="horizontal")
sc = ax3.scatter(x,np.ones_like(x), c=x, cmap=man_cmap(cmap, 1.25))
fig.colorbar(sc, ax=ax3, orientation="horizontal")
plt.show()
maybe this will help you:
https://scipy-cookbook.readthedocs.io/items/Matplotlib_ColormapTransformations.html
There you find:
light_jet = cmap_map(lambda x: x/2 + 0.5, matplotlib.cm.jet)
x, y = np.mgrid[1:2, 1:10:0.01]
plt.figure(figsize=[15, 1])
plt.imshow(y, cmap=light_jet, aspect='auto')
plt.axis('off')
plt.show()

skimage How to get correct color when converting RGB to HSV. Understanding Hue

I tried to convert an RGB to HSV using skimage and getting behavior that I do not expect. Here is some sample code that I would expect to produce only blue. This is important as (later on) as I would like to take real images and determine how much of each color is present across the whole image by referring to the hue.
import numpy as np
import skimage as ski
import matplotlib.pyplot as plt
#define my own color in RGB, should be B
tested = np.ones(shape=(100,100,3))*200
tested[:,:,0] =0
tested[:,:,1] =0
hsv_test_img_arr=ski.color.rgb2hsv(tested)
hue_img = hsv_test_img_arr[:, :, 0]
sat_img = hsv_test_img_arr[:, :, 1]
value_img = hsv_test_img_arr[:, :, 2]
fig, (ax1, ax2, ax3) = plt.subplots(ncols=3, figsize=(8, 2))
ax1.imshow(hue_img, cmap='hsv')
ax1.set_title('hue channel')
ax1.axis('off')
ax2.imshow(value_img)
ax2.set_title('value channel')
ax2.axis('off')
ax3.imshow(sat_img)
ax3.set_title('sat channel')
ax3.axis('off')
You forgot to normalize the data correctly. Values in all channels range between 0 and 1. So you need to give this information to imshow,
imshow(..., vmin=0, vmax=1)
Complete code:
import numpy as np
import skimage as ski
import matplotlib.pyplot as plt
#define my own color in RGB, should be B
tested = np.ones(shape=(100,100,3))*200
tested[:,:,0] =0
tested[:,:,1] =0
hsv_test_img_arr=ski.color.rgb2hsv(tested)
hue_img = hsv_test_img_arr[:, :, 0]
sat_img = hsv_test_img_arr[:, :, 1]
value_img = hsv_test_img_arr[:, :, 2]
fig, (ax1, ax2, ax3) = plt.subplots(ncols=3, figsize=(8, 2))
im1 = ax1.imshow(hue_img, cmap='hsv', vmin=0, vmax=1)
ax1.set_title('hue channel')
ax1.axis('off')
fig.colorbar(im1, ax=ax1)
im2 = ax2.imshow(value_img, cmap="gray", vmin=0, vmax=1)
ax2.set_title('value channel')
ax2.axis('off')
fig.colorbar(im2, ax=ax2)
im3 = ax3.imshow(sat_img, cmap="gray", vmin=0, vmax=1)
ax3.set_title('sat channel')
ax3.axis('off')
fig.colorbar(im3, ax=ax3)
plt.show()
Taking a real image makes this more useful though.
import skimage as ski
import matplotlib.pyplot as plt
img = "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/World%2C_administrative_divisions_-_de_-_colored_%28all_countries%29.svg/640px-World%2C_administrative_divisions_-_de_-_colored_%28all_countries%29.svg.png"
tested = plt.imread(img)[:,:,:3]
hsv_test_img_arr=ski.color.rgb2hsv(tested)
hue_img = hsv_test_img_arr[:, :, 0]
sat_img = hsv_test_img_arr[:, :, 1]
value_img = hsv_test_img_arr[:, :, 2]
fig, ((ax0, ax1), (ax2, ax3)) = plt.subplots(ncols=2, nrows=2, figsize=(8, 6))
im0 = ax0.imshow(tested)
ax0.set_title('original')
ax0.axis('off')
im1 = ax1.imshow(hue_img, cmap='hsv', vmin=0, vmax=1)
ax1.set_title('hue channel')
ax1.axis('off')
fig.colorbar(im1, ax=ax1)
im2 = ax2.imshow(value_img, cmap="gray", vmin=0, vmax=1)
ax2.set_title('value channel')
ax2.axis('off')
fig.colorbar(im2, ax=ax2)
im3 = ax3.imshow(sat_img, cmap="gray", vmin=0, vmax=1)
ax3.set_title('sat channel')
ax3.axis('off')
fig.colorbar(im3, ax=ax3)
plt.show()

How to obtain the skeleton of a binary image with scikit-image

I want to draw the skeleton of the following image:
I've tried with the following Python code:
import cv2
from skimage import morphology, color
import matplotlib.pyplot as plt
image = cv2.imread(r'C:\Users\Administrator\Desktop\sample.jpg')
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
image=color.rgb2gray(image)
skeleton =morphology.medial_axis(image)
fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=(8, 4))
ax1.imshow(image, cmap=plt.cm.gray)
ax1.axis('off')
ax1.set_title('original', fontsize=20)
ax2.imshow(skeleton, cmap=plt.cm.gray)
ax2.axis('off')
ax2.set_title('skeleton', fontsize=20)
fig.tight_layout()
plt.show()
And I got the following skeleton:
This doesn't look like the right skeleton image. I don't know what's going wrong.
Can anyone help me on this? Any help would be appreciated!!!
Applying the medial axis as in your example:
from skimage import img_as_bool, io, color, morphology
import matplotlib.pyplot as plt
image = img_as_bool(color.rgb2gray(io.imread('CIBUv.png')))
out = morphology.medial_axis(image)
f, (ax0, ax1) = plt.subplots(1, 2)
ax0.imshow(image, cmap='gray', interpolation='nearest')
ax1.imshow(out, cmap='gray', interpolation='nearest')
plt.show()
yields
Note that, as #Aaron mentions below, converting to a boolean image first helps here, because your original image was stored in JPEG which could introduce small fluctuations in pixel values.
You can also replace medial_axis with skeletonize for a different algorithm.
If you want the outline as described in #Tonechas's answer, then look at edge detection methods.

Categories