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()
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()
I am making an algorithm to detect license plates, specifically at character segmentation part. For this I use a histogram projection.
My idea is to use this histogram projection to
Clean edges
Segment the characters
The problem is when I want to apply histogram projection twice, when applying a filter, it does not show well (see last image)
Example with clean edges, with this binary image:
I have this algorithm that cleans the edges of a binary image:
from matplotlib import pyplot as plt
import pylab
import numpy as np
img = binary_image # input image
(rows,cols)=img.shape
h_projection = np.array([ x/rows for x in img.sum(axis=0)])
threshold = 255 - 60
print("we will use threshold {} for horizontal".format(threshold))
# select the black areas
black_areas = np.where(h_projection > threshold)
fig = plt.figure(figsize=(16,8))
fig.add_subplot(121)
for j in black_areas:
img[:, j] = 0
plt.plot((j, j), (0, 1), 'g-')
plt.plot(range(cols), h_projection.T)
v_projection = np.array([ x/cols for x in img.sum(axis=1)])
threshold = 255 - 60
print("we will use threshold {} for vertical".format(threshold))
black_areas = np.where(v_projection > threshold)
fig.add_subplot(122)
for j in black_areas:
img[j, :] = 0
plt.plot((0,1), (j,j), 'g-')
plt.plot(v_projection, range(rows))
plt.show()
# obscurate areas on the image
plt.figure(figsize=(16,12))
plt.subplot(211)
plt.title("Image with the projection mask")
plt.imshow(img)
And the output:
It do it very well (It could be more specific with the threshold, but I can't because different images were loaded for a neural network).
Now if I want to apply another histogram projection for character segmentation:
from matplotlib import pyplot as plt
import pylab
import numpy as np
#input image will be the same img variable.
(rows,cols)=img.shape
h_projection = np.array([ x/rows for x in img.sum(axis=0)])
print(np.min(h_projection))
print(np.max(h_projection))
threshold = (np.max(h_projection) - np.min(h_projection)) / 4
print("we will use threshold {} for horizontal".format(threshold))
# select the black areas
black_areas = np.where(h_projection < threshold)
fig = plt.figure(figsize=(16,8))
fig.add_subplot(121)
for j in black_areas:
img[:, j] = 1
plt.plot((j, j), (0, 1), 'g-')
plt.plot(range(cols), h_projection.T)
v_projection = np.array([ x/cols for x in img.sum(axis=1)])
threshold = (np.max(v_projection) - np.min(v_projection)) / 4
print("we will use threshold {} for vertical".format(threshold))
black_areas = np.where(v_projection < threshold)
fig.add_subplot(122)
for j in black_areas:
img[j, :] = 0
plt.plot((0,1), (j,j), 'g-')
plt.plot(v_projection, range(rows))
plt.show()
# obscurate areas on the image
plt.figure(figsize=(16,12))
plt.subplot(211)
plt.title("Image with the projection mask")
plt.imshow(img)
# erode the features
import scipy
plt.subplot(212)
plt.title("Image after erosion (suggestion)")
eroded_img = scipy.ndimage.morphology.binary_erosion(img, structure=np.ones((1,1))).astype(img.dtype)
plt.imshow(eroded_img)
plt.show()
It will show something like this:
As you can see the last image, when erosion it's applied, it seems that don't take the black of the previous the mask. Am I marking some areas wrong?
I work on python 2.7.
I want to label picture, so I use skimage, skimage.label and skimage.regionprops packages.
I've found a great code on scikit-image.org :
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from skimage import data
from skimage.filters import threshold_otsu
from skimage.segmentation import clear_border
from skimage.measure import label, regionprops
from skimage.morphology import closing, square
from skimage.color import label2rgb
image = data.coins()[50:-50, 50:-50]
# apply threshold
thresh = threshold_otsu(image)
bw = closing(image > thresh, square(3))
# remove artifacts connected to image border
cleared = clear_border(bw)
# label image regions
label_image = label(cleared)
image_label_overlay = label2rgb(label_image, image=image)
fig, ax = plt.subplots(figsize=(10, 6))
ax.imshow(image_label_overlay)
for region in regionprops(label_image):
# take regions with large enough areas
if region.area >= 100:
# draw rectangle around segmented coins
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)
ax.set_axis_off()
plt.tight_layout()
plt.show()
The problem is, when I put my png rgb picture, it doesn't work and more preciesly I got this error message :
sz = footprint.shape[ii] IndexError: tuple index out of range
I've also noticed that data.coins().shape = (303L, 384L) which is not a rgb picture. How come?
I have an image and I want to calculate the angle between two lines in this image. Let consider a very simple image like this:
Now I want to calculate the angle between the two lines in this image. Do you know how I can do that in python?
You could try with the Hough Transform. This transform allows you to detect line and then get the angle of each line.
Then you can use those two angles to compute the angle between the two line by subtracting both?
import numpy as np
from skimage.transform import (hough_line, hough_line_peaks,
probabilistic_hough_line)
from skimage.feature import canny
from skimage import data
from pylab import imread, imshow, gray, mean
import matplotlib.pyplot as plt
from matplotlib import cm
image = imread('bn2TV.jpg')
image = np.mean(image,axis=2)
image = (image < 128)*255
h, theta, d = hough_line(image)
fig, axes = plt.subplots(1, 3, figsize=(15, 6),
subplot_kw={'adjustable': 'box-forced'})
ax = axes.ravel()
ax[0].imshow(image, cmap=cm.gray)
ax[0].set_title('Input image')
ax[0].set_axis_off()
ax[1].imshow(np.log(1 + h),
extent=[np.rad2deg(theta[-1]), np.rad2deg(theta[0]), d[-1], d[0]],
cmap=cm.gray, aspect=1/1.5)
ax[1].set_title('Hough transform')
ax[1].set_xlabel('Angles (degrees)')
ax[1].set_ylabel('Distance (pixels)')
ax[1].axis('image')
ax[2].imshow(image, cmap=cm.gray)
for _, angle, dist in zip(*hough_line_peaks(h, theta, d)):
y0 = (dist - 0 * np.cos(angle)) / np.sin(angle)
y1 = (dist - image.shape[1] * np.cos(angle)) / np.sin(angle)
ax[2].plot((0, image.shape[1]), (y0, y1), '-r')
ax[2].set_xlim((0, image.shape[1]))
ax[2].set_ylim((image.shape[0], 0))
ax[2].set_axis_off()
ax[2].set_title('Detected lines')
plt.tight_layout()
plt.show()
angle=[]
dist=[]
for _, a , d in zip(*hough_line_peaks(h, theta, d)):
angle.append(a)
dist.append(d)
angle = [a*180/np.pi for a in angle]
angle_reel = np.max(angle) - np.min(angle)
Most of the code comes from here : http://scikit-image.org/docs/dev/auto_examples/edges/plot_line_hough_transform.html
we then get
Which give a 28 degree angle. Seems reasonable !