I am trying to plot an image with its respective histogram side by side with equal proportion using plt.fig() in Python but I am not getting the desired output. Instead I get the histogram overlapping onto the image.
Any idea as to why this keeps happening?
import pylab as plt
import matplotlib.image as mpimg
import numpy as np
img = np.uint8(mpimg.imread('motherT.png'))
im2 = np.uint8(mpimg.imread('waldo.png'))
# convert to grayscale
# do for individual channels R, G, B, A for nongrayscale images
img = np.uint8((0.2126* img[:,:,0]) + \
np.uint8(0.7152 * img[:,:,1]) +\
np.uint8(0.0722 * img[:,:,2]))
im2 = np.uint8((0.2126* img[:,:,0]) + \
np.uint8(0.7152 * img[:,:,1]) +\
np.uint8(0.0722 * img[:,:,2]))
# show old and new image
# show original image
fig = plt.figure()
plt.imshow(img)
plt.title(' image 1')
plt.set_cmap('gray')
# show original image
fig.add_subplot(221)
plt.title('histogram ')
plt.hist(img,10)
plt.show()
fig = plt.figure()
plt.imshow(im2)
plt.title(' image 2')
plt.set_cmap('gray')
fig.add_subplot(221)
plt.title('histogram')
plt.hist(im2,10)
plt.show()
You appear to be doing this for two images? Subplots would be your best bet. The following shows you how to use them for a 2 x 2 effect:
import pylab as plt
import matplotlib.image as mpimg
import numpy as np
img = np.uint8(mpimg.imread('motherT.png'))
im2 = np.uint8(mpimg.imread('waldo.png'))
# convert to grayscale
# do for individual channels R, G, B, A for nongrayscale images
img = np.uint8((0.2126 * img[:,:,0]) + np.uint8(0.7152 * img[:,:,1]) + np.uint8(0.0722 * img[:,:,2]))
im2 = np.uint8((0.2126 * im2[:,:,0]) + np.uint8(0.7152 * im2[:,:,1]) + np.uint8(0.0722 * im2[:,:,2]))
# show old and new image
# show original image
fig = plt.figure()
# show original image
fig.add_subplot(221)
plt.title(' image 1')
plt.set_cmap('gray')
plt.imshow(img)
fig.add_subplot(222)
plt.title('histogram ')
plt.hist(img,10)
fig.add_subplot(223)
plt.title(' image 2')
plt.set_cmap('gray')
plt.imshow(im2)
fig.add_subplot(224)
plt.title('histogram')
plt.hist(im2,10)
plt.show()
This would give you something like:
Also note, in your original code, your grey scale calculation for im2 was using the image data for img not im2.
You might want to turn the axis off for each of your images, to do this you could add plt.axis('off') before each plt.imshow() giving you:
Related
I'm trying to find the total area of glue regions in this digital microscopy image.
I have the problem that I can't seem to fill the regions inside, I can however succesfully get the contours of the glue regions.
Here is my code so far:
from skimage.io import imread
from scipy.ndimage import distance_transform_edt
from skimage.color import rgb2hed
from skimage.filters import threshold_otsu
from skimage.morphology import opening, closing, disk
import numpy as np
from scipy import fftpack
from matplotlib.colors import LogNorm
from scipy import ndimage
from skimage import img_as_ubyte
import cv2
# Read the image
im = imread("10C_11_lugol_smaller.jpg")
# Show the image
plt.figure()
plt.imshow(im)
# Convert image from RGB to HED
hed = rgb2hed(im)
# Remove Stripes
im_fft = fftpack.fft2(hed[:, :, 0])
plt.figure()
plt.imshow((np.abs(im_fft)).astype(np.uint8), norm=LogNorm())
plt.colorbar()
plt.title('Fourier transform')
keep_fraction = 0.1
im_fft2 = im_fft.copy()
# Set r and c to be the number of rows and columns of the array
r, c = im_fft2.shape
im_fft2[int(r * keep_fraction):int(r * (1 - keep_fraction))] = 0
im_fft2[:, int(c * keep_fraction):int(c * (1 - keep_fraction))] = 0
plt.figure()
plt.imshow((np.abs(im_fft2)).astype(np.uint8), norm=LogNorm())
plt.colorbar()
plt.title('Filtered Spectrum')
# Reconstructing
im_new = fftpack.ifft2(im_fft2).real
plt.figure()
plt.imshow(im_new)
plt.title('Reconstructed Image')
# Creating the Otsu Threshold on the first layer
t = threshold_otsu(im_new)
mask = im_new > t
mask = closing(opening(mask, disk(1)), disk(1))
# Show the result of the thresholding
fig = plt.figure()
plt.subplot(1, 2, 1)
plt.imshow(im)
plt.subplot(1, 2, 2)
plt.imshow(mask)
# Filling the contour
cv_image = img_as_ubyte(mask)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
res = cv2.morphologyEx(cv_image, cv2.MORPH_OPEN, kernel)
plt.figure()
plt.imshow(res, plt.cm.gray)
plt.title('Filled Contours')
# Apply the distance transform on the results
distance = distance_transform_edt(mask)
plt.figure()
plt.imshow(distance)
plt.colorbar()
plt.show()
Can someone please help :(
Thanks in advance for reading!
Results So Far
I have a medical Image, and I'm trying to segment a specific zone inside.
After several steps of conventional image processing, I was able to locate the region, and managed to get the seeds for the segmentation, but when I try to apply RandomWalker algorithm, I don't get a good segmentation.
can you please tell me what is the problem here, and how to correct it?
Code :
# import math
import numpy as np
import matplotlib.pyplot as plt
import cv2 as cv
from skimage.feature import canny
from skimage.transform import hough_circle, hough_circle_peaks
from skimage.draw import circle_perimeter
from skimage.segmentation import watershed, random_walker, active_contour
import skimage.filters as filters
# Read image
img = cv.imread("CT.png")
# Get image center coordinates
img_center = (img.shape[0]//2, img.shape[1]//2)
# Edge detector
edges = canny(img, sigma=2.0, low_threshold=19, high_threshold=57)
# Hough_circle
hough_radii = np.arange(29, 32, 1)
hough_res = hough_circle(edges, hough_radii)
accums, cx, cy, radii = hough_circle_peaks(hough_res, hough_radii,total_num_peaks=4, min_xdistance=70,min_ydistance=200, threshold=0.25)
# Remove false-posite circle
sortX = np.argsort(cx)
cx = cx[sortX[:-1]]
cy = cy[sortX[:-1]]
radii = radii[sortX[:-1]]
#--------------------------------------
# get the closest circle to the centre
#--------------------------------------
dist = []
for idx in range(len(cx)):
dist.append(abs(img_center[1]-cx[idx])+abs(img_center[0]-cy[idx]))
sortD = np.argsort(dist)
Cx = cx[sortD[0]]
Cy = cy[sortD[0]]
radius = radii[sortD[0]]
markers = np.ones(img.shape, dtype=np.uint)
markers[img==0] = 0
markers[Cy-radius//2:Cy+radius//2, Cx-radius//2:Cx+radius//2] = 2
# markers[(Cy-radius//2)+1:(Cy+radius//2)-1, (Cx-radius//2)+1:(Cx+radius//2)-1] = 0
#---------------------------------
labels = random_walker(img, markers)
# print(labels.shape)
# Plot results
fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(8, 3.2),
sharex=True, sharey=True)
ax1.imshow(img, cmap='gray')
ax1.axis('off')
ax1.set_title('Noisy data')
ax2.imshow(markers, cmap='magma')
ax2.axis('off')
ax2.set_title('Markers')
ax3.imshow(labels, cmap='gray')
ax3.axis('off')
ax3.set_title('Segmentation')
fig.tight_layout()
plt.show()
#======================================
Random walker only expands labels from markers into the regions having label 0. You end up with an image containing only ones everywhere except for 2 in the original square. That's because the label 2 has nowhere to expand into: it is surrounded by 1s.
I was able to modify the segmentation a little by using:
border = 71
surround = (
(dilation(markers, np.ones((border, border))) == 2)
^ (markers==2)
)
markers[surround] = 0
labels = random_walker(img, markers) * (img != 0)
It's definitely still not perfect. Beyond this, you will need to play with the border size as well as the beta= and tol= parameters of random_walker.
import matplotlib.pyplot as plt
from PIL import Image
import numpy as np
from skimage.feature import canny
from skimage.transform import hough_circle, hough_circle_peaks
from skimage.segmentation import watershed, random_walker, active_contour
from skimage.morphology import erosion, dilation
from skimage.restoration import denoise_bilateral
from skimage.color import rgb2gray
from skimage.filters import threshold_local
image=plt.imread('medical_image.png')
plt.imshow(image)
plt.show()
canny_edges=canny(image, sigma=1.5 )
hough_radii = np.arange(29, 32, 1)
hough_res = hough_circle(canny_edges, hough_radii)
#Identifies most prominent circles separated by certain distances in a
#Hough space.
accums, cx, cy, radii = hough_circle_peaks(hough_res, hough_radii,total_num_peaks=4, min_xdistance=70,min_ydistance=200, threshold=0.25)
img_center = (image.shape[0]//2, image.shape[1]//2)
dist = []
for idx in range(len(cx)):
dist.append(abs(img_center[1]-cx[idx])+abs(img_center[0]-cy[idx]))
sortD = np.argsort(dist)
Cx = cx[sortD[0]]
Cy = cy[sortD[0]]
radius = radii[sortD[0]]
markers = np.ones(image.shape, dtype=np.uint)
markers[image==0] = 0
markers[Cy-radius//2:Cy+radius//2, Cx-radius//2:Cx+radius//2] = 2
border = 71
surround = (
(dilation(markers, np.ones((border, border))) == 2)
^ (markers==2)
)
markers[surround] = 0
labels = random_walker(image, markers)
block_size=35
grayscale_image=rgb2gray(image)
denoised_image=denoise_bilateral(grayscale_image,multichannel=False)
local_thresh= threshold_local(grayscale_image, block_size,offset=.01)
#apply the thresholding to the image
binary_global = grayscale_image<local_thresh
plt.clf()
fig, (ax1, ax2, ax3,ax4,ax5) = plt.subplots(1, 5, figsize=(8, 3.2),
sharex=True, sharey=True)
ax1.imshow(canny_edges, cmap='gray')
ax1.axis('off')
ax2.imshow(markers,cmap='gray')
ax2.axis('off')
ax3.imshow(labels,cmap='gray')
ax3.axis('off')
ax4.imshow(binary_global,cmap='gray')
ax4.axis('off')
ax5.imshow(denoised_image,cmap='gray')
ax5.axis('off')
plt.show()
Help, I need to put a border on the image displayed from the code below. How do I do this? The code below pulls up the image, and now i need a border. Help.. All of this code is Python
# -*- coding: utf-8 -*-
'''
LoganCaroline_1_4_7: Merge images
'''
import matplotlib.pyplot as plt
import os.path
import numpy as np # “as” lets us use standard abbreviations
'''Read the image data'''
# Get the directory of this python script
directory = os.path.dirname(os.path.abspath(__file__))
# Build an absolute filename from directory + filename
filename = os.path.join(directory, 'family1.jpg')
# Read the image data into an array
img = plt.imread(filename)
'''Show the image data'''
# Create figure with 1 subplot
fig, ax = plt.subplots(1, 1)
# Show the image data in a subplot
ax.imshow(img, interpolation='none')
# Show the figure on the screen
fig.show()
Just create a slightly larger array that is black and fill the central pixels with your image.
import numpy as np
import matplotlib.pyplot as plt
def frame_image(img, frame_width):
b = frame_width # border size in pixel
ny, nx = img.shape[0], img.shape[1] # resolution / number of pixels in x and y
if img.ndim == 3: # rgb or rgba array
framed_img = np.zeros((b+ny+b, b+nx+b, img.shape[2]))
elif img.ndim == 2: # grayscale image
framed_img = np.zeros((b+ny+b, b+nx+b))
framed_img[b:-b, b:-b] = img
return framed_img
img = np.random.rand(456, 333, 3)
fig, (ax1, ax2) = plt.subplots(1,2)
ax1.imshow(img, interpolation='none')
ax2.imshow(frame_image(img, 20), interpolation='none')
plt.show()
Based on the previous answer, if you want customizable RGB colors (3 dimensions images) for the border color:
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
def frame_image(img, frame_width):
b = frame_width # border size in pixel
ny, nx = img.shape[0], img.shape[1] # resolution / number of pixels in x and y
framed_img = Image.new('RGB', (b+ny+b, b+nx+b), (255, 0, 0)) # RGB color tuple
framed_img = np.array(framed_img.getdata()).reshape(framed_img.size[0], framed_img.size[1], 3)
framed_img[b:-b, b:-b] = img
return framed_img
img = np.random.rand(456, 333, 3)
fig, (ax1, ax2) = plt.subplots(1,2)
ax1.imshow(img, interpolation='none')
ax2.imshow(frame_image(img*255, 20), interpolation='none')
plt.show()
Output example
So in python I have the following code, taken from this answer:
import matplotlib.pyplot as plt
import sympy
x = sympy.symbols('x')
y = 1 + sympy.sin(sympy.sqrt(x**2 + 20))
lat = sympy.latex(y)
#add text
plt.text(0, 0.6, r"$%s$" % lat, fontsize = 50)
#hide axes
fig = plt.gca()
fig.axes.get_xaxis().set_visible(False)
fig.axes.get_yaxis().set_visible(False)
plt.savefig('out.png', bbox_inches='tight', pad_inches=0)
plt.show()
This opens the text and exports it to a png file just fine:
But this includes whitespace beyond the whitespace outside of the frame. How would you go about cropping the image to export only the text, like a bounding box, like so?
The following is not a perfect solution, but it will hopefully give you some ideas on how to progress:
import matplotlib.pyplot as plt
import sympy
x = sympy.symbols('x')
y = 1 + sympy.sin(sympy.sqrt(x**2 + 2))
lat = sympy.latex(y)
fig = plt.figure()
renderer = fig.canvas.get_renderer()
t = plt.text(0.001, 0.001, f"${lat}$", fontsize=50)
wext = t.get_window_extent(renderer=renderer)
fig.set_size_inches(wext.width / 65, wext.height / 40, forward=True)
fig.patch.set_facecolor('white')
plt.axis('off')
plt.tight_layout()
plt.savefig('out.png', bbox_inches='tight', pad_inches=0)
plt.show()
The idea being that you can determine the size of your text by getting the window extent using the current renderer. It is then also possible to manually specify a figure size. I am though not sure on the correct approach to convert between the two. Note, I added a border to the image so you can see that amount of remaining padding:
As a workaround to this problem, the following approach simply makes use of Python's PIL library to automatically crop the image before saving it:
import io
from PIL import Image, ImageOps
import matplotlib.pyplot as plt
import sympy
x = sympy.symbols('x')
y = 5 /sympy.sqrt(1 + sympy.sin(sympy.sqrt(x**2 + 2)))
lat = sympy.latex(y)
fig = plt.figure()
t = plt.text(0.001, 0.001, f"${lat}$", fontsize=50)
fig.patch.set_facecolor('white')
plt.axis('off')
plt.tight_layout()
with io.BytesIO() as png_buf:
plt.savefig(png_buf, bbox_inches='tight', pad_inches=0)
png_buf.seek(0)
image = Image.open(png_buf)
image.load()
inverted_image = ImageOps.invert(image.convert("RGB"))
cropped = image.crop(inverted_image.getbbox())
cropped.save('out.png')
The cropped version looks like:
I am trying my hand at image processing and my goal is to output the measurements of a human hand given an image of a human hand as the input. My current thought process is to include a quarter in the image to provide a reference value. Therefore, my input looks like this:
I am currently using scikit-image for image processing, and my code looks like this:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from skimage import data
from skimage.filter import threshold_otsu
from skimage.segmentation import clear_border
from skimage.morphology import label, closing, square
from skimage.measure import regionprops
from skimage.color import label2rgb
from skimage import io, color
#image = data.coins()[50:-50, 50:-50]
filename = io.imread("hand2.JPG")
image = color.rgb2gray(filename)
# apply threshold
thresh = threshold_otsu(image)
bw = closing(image > thresh, square(3))
# remove artifacts connected to image border
cleared = bw.copy()
#clear_border(cleared)
# label image regions
label_image = label(cleared)
borders = np.logical_xor(bw, cleared)
label_image[borders] = -1
image_label_overlay = label2rgb(label_image, image=image)
fig, ax = plt.subplots(ncols=1, nrows=1, figsize=(12, 12))
ax.imshow(image_label_overlay)
for region in regionprops(label_image):
# skip small images
if region.area < 1000:
continue
print "Perimeter: "
print region.perimeter
print "Area: "
print region.area
print ""
# draw rectangle around segments
minr, minc, maxr, maxc = region.bbox
rect = mpatches.Rectangle((minc, minr), maxc - minc, maxr - minr,
fill=False, edgecolor='red', linewidth=2)
ax.add_patch(rect)
plt.show()
I am able to segment my image into regions, but I don't know how to convert my hand segment into measurements for the individual fingers and width of the hand. I think I'm close, I just don't quite know how to proceed!
EDIT: Maybe I should be using opencv for this?
It wasn't clear exactly what you wanted as output, but here is my best guess. I used the SLIC segmentation algorithm to identify regions in the image. Based on their region properties (area), I choose the largest two (hand and coin) and display them, along with their principal axes.
import numpy as np
import matplotlib.pyplot as plt
import math
from skimage import io, segmentation, measure, color
image = io.imread("hand2.JPG")
label_image = segmentation.slic(image, n_segments=2)
label_image = measure.label(label_image)
regions = measure.regionprops(label_image)
areas = [r.area for r in regions]
ix = np.argsort(areas)
hand = regions[ix[-1]]
coin = regions[ix[-2]]
selected_labels = np.zeros_like(image[..., 0], dtype=np.uint8)
fig, ax = plt.subplots(ncols=1, nrows=1, figsize=(12, 12))
for n, region in enumerate([hand, coin]):
selected_labels[region.coords[:, 0], region.coords[:, 1]] = n + 2
y0, x0 = region.centroid
orientation = region.orientation
x1 = x0 + math.cos(orientation) * 0.5 * region.major_axis_length
y1 = y0 - math.sin(orientation) * 0.5 * region.major_axis_length
x2 = x0 - math.sin(orientation) * 0.5 * region.minor_axis_length
y2 = y0 - math.cos(orientation) * 0.5 * region.minor_axis_length
ax.plot((x0, x1), (y0, y1), '-r', linewidth=2.5)
ax.plot((x0, x2), (y0, y2), '-r', linewidth=2.5)
ax.plot(x0, y0, '.g', markersize=15)
image_label_overlay = color.label2rgb(selected_labels, image=image, bg_label=0)
ax.imshow(image_label_overlay, cmap='gray')
ax.axis('image')
plt.show()