问题
Input is a uint16 grayscale .tif-image, 512 x 512 pixels. As the title to this question implies, I would like to calculate the average pixel intensity of blobs identified by the blob_log method (see: http://scikit-image.org/docs/dev/api/skimage.feature.html#skimage.feature.blob_log) but am unsure how to access the pixel values of each individual blob. Average intensity values must be returned in uint16 range (0 to 65535).
Below is what I have so far. Apologies in advance if I haven't been clear enough. I've been learning python (3.6.x) for about three months and this is my first project. Any help would be greatly appreciated!
from skimage import io
from math import sqrt
from skimage.feature import blob_log
import numpy as np
from pandas import DataFrame
def start():
while True:
us_input = input(
"Please enter the name of the file you'd like to analyze.\n> "
)
try:
im = io.imread(us_input)
break
except FileNotFoundError:
print(
"That file doesn't seem to exist or has been entered incorrectly."
)
neur_detect(im)
def neur_detect(im):
neurons = blob_log(im, min_sigma=1, max_sigma=30, threshold=.02, overlap=.1)
neur_props(neurons)
def neur_props(blobs):
num_neurons = len(blobs)
print("\nNumber of potential neurons detected: {}\n".format(num_neurons))
results = []
for blob in blobs:
y_row, x_col, r = blob
properties = []
properties.append(x_col / .769230769230769) # convert pixels to um
properties.append(y_row / .769230769230769) # convert pixels to um
properties.append(r * sqrt(2)) # compute radii in 3rd column of DataFrame
mean_intensity = ????
properties.append(mean_intensity)
results.append(properties)
results = DataFrame(results, columns = ['x_coor', 'y_coor', 'radius', 'mean_intensity'])
results.index = results.index + 1
print(results)
start()
回答1:
The log blob detector returns an array in which each row represents a blob. It gives center coordinates (row and column) as well as the Gaussian blog width, sigma. The radius of a blob in 2D is approximately sqrt(2) * sigma
.
import numpy as np
from skimage import draw, feature
import matplotlib.pyplot as plt
# Create a test image
image = np.zeros((200, 200))
# Parameters for test image blobs
positions_r, positions_c = (50, 100, 150), (50, 100, 150)
radii = (20, 15, 30)
values = (.5, .75, 1)
# We'll make the blobs vary a bit with noise, to make it
# more realistic. Here we'll store their known average values.
blob_avg = []
for (r, c, radius, val) in zip(positions_r, positions_c,
radii, values):
# Get the coordinates for a circle at the specified coordinates
r_ix, c_ix = draw.circle(r, c, radius)
# Generate values for all pixels inside the circle, varying
# between val/2 and val.
noisy_vals = val * 0.5 + np.random.random(size=len(r_ix)) / 2
# Put those values into our test image
image[r_ix, c_ix] = noisy_vals
# Save the average value of this blob
blob_avg.append(noisy_vals.mean())
# Compute the blobs in the image, setting the desired sigma range,
# and lowering the threshold so that we also grab our faintest blob
blobs_log = feature.blob_log(image, min_sigma=5, max_sigma=50,
threshold=0.3, num_sigma=50)
# `blob_log` returns the blobs in reverse order (in this case),
# so to compare with our test data we reverse the list of blob
# averages
blob_avg = blob_avg[::-1]
# Compute each blob's radius, by multiplying its sigma by sqrt(2)
blobs_log[:, 2] = blobs_log[:, 2] * np.sqrt(2)
# Create a plot, and display our test data
f, ax = plt.subplots(figsize=(15, 10))
ax.imshow(image, cmap='gray');
# Generate all row and column coordinates for our test image
# For an `(N, M)` test image, `ixs` will have shape `(N, M, 2)`,
# since it stores row and column coordinates.
ixs = np.indices(image.shape)
# Now, we plot each detected blob and estimate its average intensity
for i, blob in enumerate(blobs_log):
y, x, r = blob
c = plt.Circle((x, y), r, color='red', linewidth=2, fill=False)
ax.add_patch(c)
# Define an array of shape `[2, 1, 1]`, containing
# the center of the blob
blob_center = np.array([y, x])[:, np.newaxis, np.newaxis]
# Using the formula for a circle, `x**2 + y**2 < r**2`,
# generate a mask for this blob.
mask = ((ixs - blob_center)**2).sum(axis=0) < r**2
# Calculate the average intensity of pixels under the mask
blob_avg_est = image[mask].mean()
print(f'Blob {i} average value: true={blob_avg[i]:.2f}, estimated={blob_avg_est:.2f}')
Output:
Blob 0 average value: true=0.75, estimated=0.75
Blob 1 average value: true=0.63, estimated=0.63
Blob 2 average value: true=0.50, estimated=0.49
来源:https://stackoverflow.com/questions/51382850/finding-the-average-pixel-values-of-a-list-of-blobs-identified-by-scikit-images