Esta es la respuesta más válida que te podemos aportar, pero primero estúdiala pausadamente y valora si se puede adaptar a tu proyecto.
Solución:
En primer lugar, excluiría la escala del “algoritmo de búsqueda de partículas”, así:
imgWithScale = Import["https://i.stack.imgur.com/ryzmV.jpg"];
img = ImageTake[imgWithScale, 280]
(seguido de los mismos pasos que usó anteriormente).
Luego extraería la escala nm / pixel:
scaleArea = ImageTake[imgWithScale, -20, -15]
whitePixels = PixelValuePositions[Binarize[scaleArea], 1];
left, right = MinMax[whitePixels[[All, 1]]];
nmPerPx = 500./(right - left)
(Tenga en cuenta que estoy usando Part
array acceso ([[All, ...
) instead For
loops to extract specific elements from a nested list. This is almost always shorter, faster and more readable. Never use For
in Mathematica)
Next, I’m not sure the Area
is the best measure of particle size. Your particles are mostly ciruclar, so we can try a few others:
measurements = "EquivalentDiskRadius", "MeanCentroidDistance",
"Length", "CaliperLength", "BoundingDiskRadius", "MeanIntensity";
(* MeanIntensity is dimensionless, the other ones are lengths,
i.e scaled by nmPerPx^1 *)
scale = nmPerPx^1, 1, 1, 1, 1, 0;
(* only count particles that aren't clipped by an image border, with
condition #AdjacentBorderCount == 0 & *)
comp = ComponentMeasurements[img, morph, measurements, #AdjacentBorderCount == 0 &]; Multicolumna[
MapThread[
Histogram[#1, PlotLabel -> #2, ImageSize -> 300] &, escala * Transponer[comp[[All, 2]]], mediciones]]
(He usado EquivalentDiskRadius
, el radio de un disco con la misma área, por lo que es más fácil compararlo con las otras longitudes).
Parece que Length
y CaliperLength
son estimaciones mucho mejores para el tamaño de partícula, porque dependen menos de la oclusión.
También podemos ver fácilmente que existe una correlación entre la intensidad (es decir, la profundidad) y el tamaño:
compare = 4, 6;
ListPlot[comp[[All, 2, compare]],
AxesLabel -> measurements[[compare]]]
Si desea explorar más la correlación, puede utilizar LocatorPane
y Dynamic
para ver qué componente está dónde de forma interactiva:
nfIdx = Nearest[comp[[All, 2, compare]] -> comp[[All, 1]]];
nf = Nearest[comp[[All, 2, compare]]];
pt = comp[[1, 2, compare]];
Row[
LocatorPane[Dynamic[pt],
Dynamic[ListPlot[comp[[All, 2, compare]],
AxesLabel -> measurements[[compare]], GridLines -> nf[pt],
ImageSize -> 500]]],
Dynamic[
HighlightImage[img,
ColorNegate[Binarize[Image[(morph - nfIdx[pt][[1]])^2], 0]],
ImageSize -> 400], TrackedSymbols :> pt]]
Puede extraer el factor de conversión de forma semiautomática.
imgcrop = ImageTake[img, -20, -15, -150, -1]
bars = MorphologicalComponents[imgcrop, .1];
[email protected]
Las coordenadas x de los centroides de las barras son entonces
xcoords = ComponentMeasurements[bars, "Centroid"][[All, 2, 1]]
(* 0.5, 16., 31.8, 47.0556, 63., 79., 95., 110., 126., 142. *)
Y la diferencia media entre las coordenadas x de barras sucesivas es
Mean[Differences[xcoords]]
(* 15.7222 *)
El factor de conversión en nanómetros / píxel es (suponiendo que estoy leyendo la escala correcta y que cada espacio entre las marcas es de 500 nm)
nmPerPixel = 500/Mean[Differences[xcoords]]
(* 31.8021 *)
Luego, a partir de su análisis de imagen, las áreas en píxeles son
areaPixels =
Flatten[ComponentMeasurements[morph, "Area"][[All, 2]]];
Y las áreas convertidas a nanómetros cuadrados
areaSqNanometers = nmPerPixel^2 areaPixels;
Histogram[areaSqNanometers]
Recuerda que puedes optar por la opción de parafrasear si te ayudó.